Spring 基础5 —— AOP 与事务

2017-12-13  本文已影响0人  WesleyLien

Spring 的 AOP 支持

基于 Annotation 的“零配置”方式

基于 Annotation 的“零配置”方式步骤:

  1. 引入 aop Schema

    xmlns:aop="http://www.springframework.org/schema/aop"
    
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
    
  2. 在 配置文件中加入支持

    <!-- 启动 @AspectJ 支持 -->
    <aop:aspect-autoproxy/>
    

    这里实际上是利用 aop Schema 简化了配置,实际上配置了 AnnotationAwareAspectJAutoProxyCreator 这个 Bean 后处理器,为容器中 Bean 生成 AOP 代理(添加下面到 Spring 配置文件中是一样的)

    <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
    

    Spring 只是使用了和 AspectJ 一样的注解,但并没有 AspectJ 的编译器和织入器,底层仍然使用 Spring AOP,依然是在运行时动态生成 AOP 代理,并不依赖 AspectJ 的编译器或织入器

  3. 添加两个 AspectJ 库:aspectjweaver.jaraspectjrt.jar

  4. 定义切面 Bean 和增强处理

    • @Aspect 定义切面 Bean
    • @Before 增强处理只能在目标方法执行之前织入增强
    • @AfterReturning 增强处理在目标方法正常完成后被织入
    • @AfterThrowing 增强处理主要用于处理程序中未处理的异常
    • @After 增强处理不管目标方法如何结束,都会被织入
    • @Around 增强处理近似等于 @Before + @AfterReturning,既可在执行目标方法前织入,也可在目标方法织入增强动作。它可决定目标方法执行时间、执行方式,甚至完全阻止执行。可改变目标方法的参数值,也可改变目标方法的返回值。@Around 增强处理需要在线程安全下执行
    // 定义一个切面类
    @Aspect
    public class SomeAspect {
    
        // 匹配 com.lian.service.impl 包下所有类的所有方法的执行作为切入点
        @Before("execution(* com.lian.service.impl.*.*(..))")
        public void authority() {
            
        }
        
        // 指定一个返回值参数名,增强处理定义的方法可通过该形参名访问目标方法的返回值
        // 匹配 com.lian.service.impl 包下所有类的所有方法的执行作为切入点
        @AfterReturning(returing="rvt", pointcut="execution(* com.lian.service.impl.*.*(..))")
        public void log(Object rvt) {
            
        }
        
        // 指定一个返回值参数名,增强处理定义的方法可通过该形参名访问目标方法所抛出的异常对象
        // 匹配 com.lian.service.impl 包下所有类的所有方法的执行作为切入点
        @AfterThrowing(throwing="ex", pointcut="execution(* com.lian.service.impl.*.*(..))")
        public void doRecoveryActions(Throwable ex) {
            
        }
        
        // 匹配 com.lian.service.impl 包下所有类的所有方法的执行作为切入点
        @After("execution(* com.lian.service.impl.*.*(..))")
        public void release() {
            
        }
        
        // Around 增强处理方法第一个形参必须是 ProceedingJoinPoint 类型
        // 匹配 com.lian.service.impl 包下所有类的所有方法的执行作为切入点
        @Around("execution(* com.lian.service.impl.*.*(..))")
        public Object processTx(ProceedingJoinPoint jp) throws Throwable {
            // ProceedingJoinPoint 对象的其他常用方法:
            // Object[] getArgs() 返回参数
            // Signature getSignature() 返回被增强方法的相关信息
            // Object getTarget() 返回被织入增强处理的目标对象
            // Object getThis() 返回 AOP 框架为目标对象生成的代理对象
            
            // proceed() 方法用于执行目标方法
            // proceed() 方法返回值为目标方法执行后的返回值
            // proceed(Object[] objs) 方法可传进一个 Object[] 对象,该 Object[] 数组中的值将被传入目标方法作为执行方法的实参
            Object rvt = jp.proceed(new Object[]{"被改变的参数"});
            return rvt + "新增的内容";
        }
    }
    

增强处理的执行顺序:
* 进入目标方法时:Around -> Before
* 退出目标方法时:Around -> AfterReturning -> After

可自定义切面类的执行顺序

切入点的定义与切入点指示符

基于 XML 配置文件的管理方式

基于 XML 配置文件的管理方式步骤:

  1. 配置切面
    使用 <aop:aspect.../> 元素来定义切面,其实质是将一个已有的 Bean 转化为切面 Bean

    <aop:config>
        <!-- 将容器中的 afterAdviceBean 转换成切面 Bean ,切面 Bean 的新名称为 afterAdviceAspect -->
        <!-- id 属性 -->
        <!-- ref 属性 -->
        <!-- order 属性,指定该切面 Bean 的优先级,数值越小优先级越高 -->
        <aop:aspect id="afterAdviceAspect" ref="afterAdviceBean">
            ...
        </aop:aspect>
    </aop:config>
    
  2. 配置增强处理
    使用 XML 配置增强处理分别依赖于如下几个元素:

    • <aop:before.../>
    • <aop:after.../>
    • <aop:after-returning.../>
    • <aop:after-throwing.../>
    • <aop:around.../>
      这些元素可指定的属性有:
    • pointcut —— 指定一个切入表达式
    • pointcut-ref —— 指定一个切入点名,与 pointcut 属性选其一
    • method —— 指定方法名
    • throwing —— 属性仅对 <aop:after-throwing.../> 元素有效,指定一个形参名
    • returning —— 属性仅对 <aop:after-returning.../> 元素有效,指定一个形参名

    当定义切入点表达式时,一样支持 execution、within、args、this、target 和 bean 等切入点指示符,但组合运算符为:and(替代 &&)、or(替代 ||)、not(替代 !)

    <aop:config>
        <aop:aspect id="afterAdviceAspect" ref="afterAdviceBean" order="2">
            <aop:before pointcut="execution(* com.lian.service.impl.*.*(..))" method="doBefore"/>
        </aop:aspect>
    </aop:config>
    
  3. 配置切入点
    可以定义切入点来重用切入点表达式,使用 <aop:pointcut.../> 元素来定义切入点
    <aop:pointcut.../> 元素作为 <aop:config.../> 的子元素时,表明切入点可以被多个切面共享
    <aop:pointcut.../> 元素作为 <aop:aspect.../> 的子元素时,表明切入点只能在对应切面有效
    <aop:pointcut.../> 元素可指定的属性有:

    • id
    • expression —— 切入点关联的表达式
      增强处理元素只需要在 pointcut-ref 属性指定对应 id 的切入点即可

Spring 事务

一些不同持久层访问环境及对应 PlatformTransactionManager 实现类举例(可能有不同的实现类):

声明式事务管理的事务配置

声明式事务管理无需在程序中书写任何的事务操作代码,而是通过在 XML 文件中为业务组件配置事务代理(AOP 代理的一种),AOP 为事务代理所织入的增强处理也由 Spring 提供:在目标方法执行之前,织入开始事务;在目标方法执行之后,织入结束事务

声明式事务管理的事务配置步骤:

  1. 使用 tx Schema
    xmlns:tx="http://www.springframework.org/schema/tx"
    
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
    
  2. tx 命名空间下提供 <tx:advice.../> 元素来配置事务增强处理,然后在 <aop:advisor.../> 元素中启用该自动代理
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx-attributes>
            <!-- 为一批方法指定所需的事务语义,包括:事务传播属性、事务隔离属性、事务超时属性、只读属性、对指定异常回滚、对指定异常不回滚 -->
            <!-- name 属性,必选,与事务语义关联的方法名,支持通配符 -->
            <!-- propagation 属性,指定事务传播行为,默认为 Propagation.REQUIRED -->
            <!-- isolation 属性,指定事务的隔离级别,默认为 Isolation.DEFAULT -->
            <!-- timeout 属性,指定事务的超时时间(秒),默认为 -1 不超时 -->
            <!-- read-only 属性,指定事务是否只读,默认为 false -->
            <!-- rollback-for 属性,指定触发事务回滚的异常类(全限定类名),多个以 , 隔开 -->
            <!-- no-rollback-for 属性,指定不触发事务回滚的异常类(全限定类名),多个以 , 隔开 -->
            <tx:method name="get*" read-only="true"/>
            <tx method name="*"/>
        </tx-attributes>
    </tx:advice>
    
    <aop:config>
        <!-- 匹配 com.lian.dao.impl 包里所有以 Impl 结尾的类里所有方法 -->
        <aop:pointcut id="myPointcut" expression="execution(* com.lian.dao.impl.*Impl.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"/>
    </aop:config>
    
    当采用 <aop:advisor.../> 元素将 Advice 和切入点绑定时,实际是由 Spring 提供的 Bean 后处理器完成的。BeanNameAutoProxyCreator、DefaultAdvisorAutoProxyCreator 两个 Bean 后处理器都可以后处理容器中的 Bean(为它们织入切面中包含的处理)

配置的属性相关说明:

使用 Annotation 来进行声明式事务管理的事务配置

使用 @Transactional 修饰 Bean 类,表明事务的设置对整个 Bean 类起作用,使用 @Transactional 修饰方法,表明事务的设置只对该方法有效

@Transactional 的属性有:

配置文件的设置

<!-- 根据 Annotation 来生成事务代理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
上一篇 下一篇

猜你喜欢

热点阅读