JAVA学习日志3-6(spring AOP)

spring aop 是面向切面编程,底层也是使用代理模式来进行实现的
在spring aop 如果是实现接口方式 使用 jdk 提供的代理模式,如果继承的方式,就使用cglib来实现代理模式。aop来实现代码的分离,以及动态来执行某些操作(方法)。

  • 一些概念
    被代理对象:只包含核心代码的对象。
    代理对象:对被代理对象增强的对象。
    连接点(joinpoint):指核心代码中的所有方法。
    切入点(pointcut):指核心代码中需要增强的方法。
    通知(advice):指事务、日志等代码,增强代码。
    织入(weaving):是一个动作,指将增强代码加入到切入点中执行。
    切面(aspect):通知+切入点
  • 小案例
    1.添加依赖
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>

    <!--用于来解析切入点表达式-->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.7</version>
    </dependency>
  1. 编写代理对象类(核心代理业务类)、增强类
  2. xml文件中添加约束,实例化代理对象和增强对象,配置切面
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--    代理对象-->
    <bean id="ser" class="com.fyj.service.impl.UserService"></bean>
<!--    增强对象-->
    <bean id="aop" class="com.fyj.springaop.Aop"></bean>
<!--    <aop:config>-->
<!--        <aop:aspect ref="aop">-->
<!--            <aop:after method="show1" pointcut="execution(public void com.fyj.service.impl.UserService.core())"></aop:after>-->
<!--        </aop:aspect>-->
<!--    </aop:config>-->
    
<!--    可以将pointcut提取出来-->
    <aop:config>
        <aop:pointcut id="pc" expression="execution(public void com.fyj.service.impl.UserService.core())"/>
        <aop:aspect ref="aop">
            <aop:before method="show1" pointcut-ref="pc"></aop:before>
            <aop:after-returning method="show2" pointcut-ref="pc"></aop:after-returning>
            <aop:after-throwing method="show3" pointcut-ref="pc"></aop:after-throwing>
            <aop:after method="show4" pointcut-ref="pc"></aop:after>
        </aop:aspect>
    </aop:config>

execution(public void com.fyj.service.impl.UserService.core()中写的是代理对象中被增强的方法,public可以省略 void、路径名和方法名可以用*代替
4.获得实体bean执行被增强的方法

    @org.junit.Test
    public void test1(){
        ApplicationContext app = new ClassPathXmlApplicationContext("aop.xml");
        UserService userService = (UserService) app.getBean("ser");
        userService.core();

    }
  • spring中四种增强

前置增强 ==>在核心业务代码前面执行操作aop:before

后置增强 ==>在核心代码的后面执行的操作 after-returning

异常增强 ==>核心操作发生异常执行的操作 aop:after-throwing

最终增强 ==>最后执行的代码 aop:after

环绕增强实际是自定义的增强
xml中配置

    <aop:config>
        <aop:aspect ref="aop">
            <aop:around method="show" pointcut="execution(public  void com.fyj.service.TestService.core())"></aop:around>
        </aop:aspect>
    </aop:config>

增强类

    public void show(ProceedingJoinPoint point){
        try {
            System.out.println("before");
            //执行代理方法
            point.proceed(point.getArgs());
            System.out.println("after");
        } catch (Throwable throwable) {
            System.out.println("throw");
        }finally {
            System.out.println("finally");
        }
    }

使用注解来实现面向切面开发
xml,中删除切面的配置信息,添加

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:component-scan base-package="com.fyj"></context:component-scan>
    <aop:aspectj-autoproxy />
</beans>

增强对象中

@Component(value = "tu2")
public class TestUtils2 {

    @Pointcut(value = "execution(public void com.fyj.service.TestService2.core())")
    public void show(){}

    @Before("show()")
    public void before(){
        System.out.println("before");
    }
}

@Pointcut指定了切点,show()方法是没有任何意义的。@Before(“show()”)设置了前置增强。同样的注解还有@AfterReturning@AfterThrowing@After@Around 环绕增强

spring关于事务的操作
编程式事务:直接在java代码中添加事务,没有动态代理之前最原始方式
声明式事务:采用spring aop的思想来进行事务管理,事务代码与核心代码进行分离
spring中的事物控制主要通过以下三个api来实现:
1.PlatformTransactionManager 负责事务的管理,是个接口,其子类负责具体工作

类或方法描述
DataSourceTransactionManagerPlatformTransactionManager的实现类,用于使用标准数据源时的事务管理
TransactionStatus getTransaction(TranstionDefinition def)获取事务状态信息
void commit(TransactionStatus status)提交事务
void rollback(TransactionStatus status)回滚事务

2.TransactionDefinition 定义事务的相关参数
规定事务隔离级别,事务传播行为

隔离级别描述
TRANSACTION_READ_UNCOMMITTED读未提交,存在问题:脏读
TRANSACTION_READ_COMMITTED读已经提交 ,存在问题:可重复读
TRANSACTION_REPEATABLE_READ可重复读 ,存在问题:幻读
RANSACTION_SERIALIZABLE可串化,解决以上所有的问题:使用数据库(同步锁)锁来进行操作

事务传播行为是指当一个业务方法被另一个事务方法调用时,如何进行事务控制
3.TransactionStatus 代表事务运行的实时状态

方法描述
boolean isNewTransaction()是否是新事务
boolean hasSavepoint()是否有回滚点
void setRollbackOnly()设置回滚事务
boolean isRollbackOnly()是否是回滚事务
void flush()刷新事务
boolean isCompleted()事务是否完成

即事务管理器读取事务参数进行事务管理,会产生事务的运行状态

  • 基于xml文件进行事务管理
    需要使用AOP来进行事务控制,spring提供事务代码(增强类),我们需要去编写业务代码和配置切面
    transfer是需要配置事务的方法
@Component(value = "ser")
public class UserServiceImpl implements UserService {

    @Autowired
    @Qualifier(value = "dao")
    private  UserDao userDao;

//    @Transactional(propagation = REQUIRED)
    public void transfer(User user1, User user2) {
        userDao.update(user1);
        int num = 0/0;
        userDao.update(user2);
    }
}
<!--    设置事务管理对象-->
    <bean id="tvm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="ds"></property>
    </bean>
<!--    设置(环绕)通知-->
    <tx:advice transaction-manager="tvm" id="tva">
        <tx:attributes>
<!--            规定待匹配的方法,以及事务设置-->
            <tx:method name="transfer"  propagation="REQUIRED"/>
<!--            设置*则会匹配所有的方法-->
<!--            <tx:method name="*" propagation="REQUIRED"></tx:method>-->
        </tx:attributes>
    </tx:advice>
<!--    设置切面-->
    <aop:config>
        <aop:pointcut id="pc" expression="execution(* com.fyj.service.impl.UserServiceImpl.*(..))"/>
        <aop:advisor advice-ref="tva" pointcut-ref="pc"></aop:advisor>
    </aop:config>

    <!--    <tx:annotation-driven transaction-manager="tvm"></tx:annotation-driven>-->
    @org.junit.Test
    public void Test1(){
        ApplicationContext app = new ClassPathXmlApplicationContext("User.xml");
        UserService service = (UserService) app.getBean("ser");
        User user =new User(1,"a",50);
        User user1 = new User(2,"b",100);
        service.transfer(user,user1);
    }
}

验证:当执行到 service中的 int num = 0/0; 发生运行时异常,userDao.update(user1);的操作并生效。将 int num = 0/0;注释,再次运行userDao.update(user1)和userDao.update(user2)都生效。
配置时也可以使用注解的方式
service中的注解
在这里插入图片描述
xml中不需要在配置切面,开启事务的注解
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值