迎着风跑  

Spring AOP

二、AOP

1、AOP术语

​ AOP面向切面编程,是对oop的补充。aop的底层就是动态代理,他的功能就是将动态代理进行友好的封装。

AOP相关术语:

​ Joinpoint( 连接点):类中的方法称为连接点

​ Pointcut( 切入点):连接点所在的类称为节入点

​ Advice( 通知/ 增强):以前动态代理类中编写的业务代码称为通知

​ Aspect( 切面):通知+切入点

​ Weaving( 织入):通知和连接点进行关联的过程

通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。

 

2、AOP配置步骤

  • 导入aop坐标


    <!--spring aop坐标-->
           <dependency>
               <groupId>org.springframework</groupId>
               <artifactId>spring-aop</artifactId>
               <version>5.0.9.RELEASE</version>
           </dependency>
  • 导入aop名称空间(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: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">
  • 在xml中配置aop

    配置前需要将通知类和切入点类进行实例化

    <!--配置aop-->
       <aop:config>
           <!--配置切面   通知+切入点-->
          <aop:aspect id="asp" ref="loggers">
              <!--配置切入点
                 expression:切入点表达式,告诉切面要对哪些类下的哪些方法进行增强
              -->
              <aop:pointcut id="pot" expression="execution(* cn.woniu.service.impl.*.*(..))"/>

              <!--配置通知的织入-->
              <aop:before method="show" pointcut-ref="pot"></aop:before>
          </aop:aspect>
       </aop:config>
  • aop说明

    spring-aop和spring-aspects包的区别

    spring-aop:是spring中提供aop功能的包,但是该包中没有提供解析切入点表达式的功能,还需要导入aspectsj坐标才能正确解析切入点表达式

    ​ spring-aspects:可以理解为是aop的框架,将aspectsj功能与aop功能进行封装

    springaop默认使用的是jdk接口代理,在注入对象时需要使用对象的接口来接收,否则报错。可以强制改为使用cglib代理。需要导入cglib坐标


    <aop:config proxy-target-class="true">

3、切入点表达式写法


语法:
execution(访问修饰符 包名.包名.包名.方法名(参数))

常用写法:

任意公共方法的执行:


execution(public * *(..))

任何一个名字以“set”开始的方法的执行


execution(* set*(..))

AccountService接口定义的任意方法的执行:


execution(* com.xyz.service.AccountService.*(..))

在service包中定义的任意方法的执行:


execution(* com.xyz.service.*.*(..))

在service包或其子包中定义的任意方法的执行:<font color=red>【常用方式】</font>


execution(* com.xyz.service..*.*(..))

 

三、aop的通知

Spring中一共有5种通知:前置通知(before)、后置通知(returning)、异常通知(throwing)、最终通知(after)、环绕通知(around)

​ 前置通知(before):在连接点方法执行前执行

​ 后置通知(after-returning):在连接点方法执行之后执行

异常通知(after-throwing):在连接点方法出现异常时执行

<font color=red>注意:异常通知和后置通知只会出现一个。</font>.

最终通知(after):不管有没有发生异常,都会执行

环绕通知(around):可以将前四个通知都在环绕通知中调用,环绕通知执行的顺序是按哪个通知先调用就先执行谁。

1、xml配置通知


<!--配置aop-->
   <aop:config proxy-target-class="false">
       <!--配置切面   通知+切入点-->
      <aop:aspect id="asp" ref="loggers">
          <!--配置切入点
             expression:切入点表达式,告诉切面要对哪些类下的哪些方法进行增强
          -->
          <aop:pointcut id="pot" expression="execution(* cn.woniu.service.impl.*.*(..))"/>

          <!--配置通知的织入-->
          <aop:before method="beforePrintLog" pointcut-ref="pot"></aop:before>
          <!--后置通知-->
          <aop:after-returning method="afterReturning" pointcut-ref="pot" ></aop:after-returning>
           <!--异常通知-->
          <aop:after-throwing method="afterThrowingLog" pointcut-ref="pot"></aop:after-throwing>
           <!--最终通知-->
          <aop:after method="afterLog" pointcut-ref="pot"></aop:after>

          <!--配置环绕通知-->
          <aop:around method="aroundPrintLog" pointcut-ref="pot"></aop:around>
      </aop:aspect>
   </aop:config>

2、注解配置通知


开启aop注解支持
<!--开启aop注解支持-->
   <aop:aspectj-autoproxy></aop:aspectj-autoproxy>


通知类
@Component  //实例化类
@Aspect  //表示该类是一个通知类
public class Loggers {

   //配置切入点表达式
   @Pointcut("execution(* cn.woniu.service.impl.*.*(..))")
   public void pott(){}

   /**
    * 前置通知
    */
   @Before("pott()")
   public void beforePrintLog(){
       System.out.println("开始记录日志。。。。。。");
  }

   /**
    * 后置通知
    */
   @AfterReturning("pott()")
   public void afterReturning(){
       System.out.println("我是后置通知。。。。。");
  }

   /**
    * 异常通知
    */
   @AfterThrowing("pott()")
   public void afterThrowingLog(){
       System.out.println("我是异常通知。。。。。");
  }

   /**
    * 最终通知
    */
   @After("pott()")
   public void afterLog(){
       System.out.println("我是最终通知。。。。。");
  }

   /**
    * 环绕通知
    * @param
    * @return
    */
   @Around("pott()")
   public Object aroundPrintLog(ProceedingJoinPoint point){
       //定义返回值
       Object result = null;
       try{
           //前置通知
           beforePrintLog();
           //后置通知
           afterReturning();
      }catch (Exception e){
           //异常通知
           afterThrowingLog();
      }catch (Throwable throwable) {
           throwable.printStackTrace();
      }finally {
           //最终通知
           afterLog();
      }
       return result;
  }
}

 

四、aop实现事务控制

  • 导入spring事务坐标

    该jar包中提供了一组管理事务的api(开启事务,提交事务,回滚事务),这个类称为事务管理器


    <!--spring事务-->
           <dependency>
               <groupId>org.springframework</groupId>
               <artifactId>spring-tx</artifactId>
               <version>5.0.9.RELEASE</version>
           </dependency>

1、xml方式配置实现事务控制

实例化事务管理器


<!--配置事务管理器-->
   <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <property name="dataSource" ref="dataSource"></property>
   </bean>

编写通知(确定哪些方法使用什么事务[只读事务|可读写事务])


<!--配置事务的通知 区分同一个类中哪些方法使用只读事务,哪些方法使用可读写事务(提交,回滚)-->
   <tx:advice id="txadv" transaction-manager="transactionManager">
       <tx:attributes>
           <!--配置哪些方法是只读事务-->
           <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
           <tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
           <tx:method name="select*" propagation="SUPPORTS" read-only="true"/>

           <!--配置增删改事务-->
           <tx:method name="add*" propagation="REQUIRED"></tx:method>
           <tx:method name="save*" propagation="REQUIRED"></tx:method>
           <tx:method name="insert*" propagation="REQUIRED"></tx:method>
           <tx:method name="update*" propagation="REQUIRED"></tx:method>
           <tx:method name="delete*" propagation="REQUIRED"></tx:method>
           <tx:method name="del*" propagation="REQUIRED"></tx:method>
       </tx:attributes>
   </tx:advice>

配置切面


<!--配置切面-->
   <aop:config proxy-target-class="true">
       <!--配置切入点表达式-->
       <aop:pointcut id="pot" expression="execution(* cn.woniu.service.impl.*.*(..))"/>
       <!--将通知织入到切入点中-->
       <aop:advisor advice-ref="txadv" pointcut-ref="pot"></aop:advisor>
   </aop:config>

2、注解实现事务配置

  • 在spring配置类中开启事务注解支持


    @EnableTransactionManagement(proxyTargetClass = true)
  • 在spring配置类中配置事务管理器


      /**
        * 配置事务管理器
        * @param dataSource
        * @return
        */
       @Bean
       public DataSourceTransactionManager transactionManager(DataSource dataSource){
           DataSourceTransactionManager manager=new DataSourceTransactionManager();
           manager.setDataSource(dataSource);
           return manager;
      }
  • 在service类上添加事务注解

posted on 2021-10-16 09:36  迎着风跑  阅读(222)  评论(0编辑  收藏  举报