• Spring AOP源码分析


    1.什么是AOP
      与OOP对比,AOP是处理一些横切性问题,这些横切性问题不会影响到主逻辑实现的,但是会散落到代 码的各个部分,难以维护。
    AOP就是把这些问题和主业务逻辑分开,达到与主业务逻辑解耦的目的。

    2. AOP的应用场景

    • 日志记录
    • 权限验证
    • 效率检查
    • 事务管理

    问题: Aspectj 和spring aop的区别?

     切面织入的方式:    

    •   编译期织入
    •      类装载期织入
    •      动态代理织入   spring采用  动态代理的方式,在运行时织入

     区别:

      织入的时期不同:Spring Aop采用的动态织入,而Aspectj是静态织入。静态织入:指在编译时期就织入,即:编译出来的class文件,字节码就已经被织入了。动态织入又分静动两种,静则指织入过程只在第一次调用时执行;动则指根据代码动态运行的中间状态来决定如何操作,每次调用Target的时候都执行。

       从使用对象不同:spring的通知 是基于该对象是spring bean才可以;aspectj 可以在任何java对象上使用通知;

          

    3. Spring AOP原理及其应用 

    3.1 AOP相关概念 

      Aspect(切面): 通常是一个类(交给Spring容器管理),里面可以定义切入点和通知

      JointPoint(连接点): 程序执行过程中的一个点,如方法的执行或异常的处理

      Advice(通知): AOP在特定的切入点上执行的增强处理

      通知类型:

      •   Before advice
      •   After returning advice
      •   After throwing advice
      •   After (finally) advice
      •   Around advice

      调用顺序: Around advice>Before advice>After (finally) advice>After returning advice/After throwing advice

      Pointcut(切入点): 连接点的集合

      Target object(目标对象):被通知对象 AOP proxy:AOP框架创建的对象,代理就是目标对象的增强。

      •    JDK dynamic proxy
      •   CGLIB proxy

        思考: 初始化时织入还是获取对象时织入?   spring是在初始化的时候织入的, ioc容器初始化bean的时候,在第8次调用 spring的后置处理器的时候执行的;

      Weaving(织入):把代理逻辑加入到目标对象上的过程叫做织入.

    3.2  AOP的应用

      3.2.1 Spring AOP with AspectJ pointcuts

      Schema-based AOP Support   xml配置对AOP支持的 后置处理器

      

    AspectJAwareAdvisorAutoProxyCreator 
    AnnotationAwareAspectJAutoProxyCreator // 配置 <aop:aspectj-autoproxy/>

      spring-aop.xml

      

    <!-- 自动为spring容器中那些配置@AspectJ切面的bean创建代理,织入切面    proxy-target-class默认为false,表示使用jdk动态代理织入增强,    当配为true时,表示使用Cglib动态代理技术织入增强--> 
    <aop:aspectj-autoproxy proxy-target-class="true"/> <aop:config>     <!-- 配置切面-->     <aop:aspect id="myAspect" ref="xmlAspect">        
        <!-- 配置切入点-->        
        <aop:pointcut id="businessService"                      
          expression="execution(* bat.ke.qq.com.dao.*.*(..))"/>      
        <!-- 通知-->        
        <aop:before pointcut-ref="businessService" method="before"/>        
        <aop:after pointcut-ref="businessService" method="after"/>  
      </aop:aspect> </aop:config> <bean id="xmlAspect" class="bat.ke.qq.com.config.XmlAspect"/> <bean id="foxDao" class="bat.ke.qq.com.dao.FoxDao"/>

      

    public class XmlAspect {
        public void before(JoinPoint point) {        
        System.out.println("before");
      } public void after() {
        System.out.println("after");
      }
    }

      

      基于注解的方式@AspectJ support  

          注解配置对AOP支持的 后置处理器:   AnnotationAwareAspectJAutoProxyCreator

      @Aspect 

    @Component 
    @Aspect
    @Order(1) //如果有多个切面,可以通过该注解 指定加载顺序,值越小越先加载
    public class AspectConfig {   @Pointcut("execution(* bat.ke.qq.com.dao.*.*(..))")   常用的是execution
      //@Pointcut("within(bat.ke.qq.com.dao.*)")  
      //@Pointcut("args(String)")  
      //@Pointcut("this(bat.ke.qq.com.dao.FoxDao)")   // jdk动态代理 extend Proxy implements IFoxDao  
      //@Pointcut("target(bat.ke.qq.com.dao.FoxDao)")  
      //@Pointcut("args(String ...) || args()")  
      //@Pointcut("execution(* bat.ke.qq.com.dao.*.*(String))")  
      //@Pointcut("@annotation(bat.ke.qq.com.anno.Yuanma)")  
      //@Pointcut("@target(bat.ke.qq.com.anno.Dao)") // 目标是注解配置  
      //@Pointcut("@within(bat.ke.qq.com.anno.Dao)")  
      //@Pointcut("@args(bat.ke.qq.com.anno.Dao)") //传参类型配置@Dao的类型  

       @Pointcut("bean(foxDao)")  
       private void pointcut() {}  


      //前置通知   @Before("pointcut()")  
      public void before(JoinPoint point) {      
        point.getThis();      
        System.out.println("before");  
      }
      
      //后置通知   @After("pointcut()")  
      public void after() {      
        System.out.println("after");  
      }
      
      @AfterReturning("pointcut()")  
      public void afterReturning() {      
        System.out.println("afterReturning");  
      }
      @AfterThrowing("pointcut()")  
      public void afterThrwoing() {      
        System.out.println("afterThrwoing");  
      }
      
      //环绕通知   @Around("pointcut()")  
      public Object around(ProceedingJoinPoint point) throws Throwable {      
        System.out.println("around");      
        Object[] args = point.getArgs();      
        for(int i=0;i<args.length;i++){
             if(args[i].getClass().equals(String.class)){           
                args[i] += "xxxx";         
              } 
        }
       return point.proceed(args);
    }
            

      3.2.2  pointcut的配置分析

        execution  : 属于方法级别的配置

    execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?namepattern(param-pattern) throws-pattern?)
    modifiers-pattern:方法的可见性,如public,protected
    ret-type-pattern:方法的返回值类型,如int,void等,必须配置;
    declaring-type-pattern:方法所在类的全路径名,如bat.ke.qq.com.dao.FoxDao;
    name-pattern:方法名类型,如userService(),必须配置;
    param-pattern:方法的参数类型,如java.lang.String,必须配置;
    throws-pattern:方法抛出的异常类型,如java.lang.Exception;

      @Pointcut("execution(* bat.ke.qq.com.dao.*.*(..))")

      within  表达式的最小粒度 为 类;

    @Pointcut("within(bat.ke.qq.com.dao.*)")
    

      this  代理对象  :使用jdk动态代理时 表达式中配置的为 接口;使用cglib动态代理时,表达式中配置的是类

    // jdk动态代理 基于接口 extend Proxy implements IFoxDao 只支持接口和Proxy 
    // cglib   基于继承,支持接口和目标类
    @Pointcut("this(bat.ke.qq.com.dao.FoxDao)")

      target  目标对象

    @Pointcut("target(bat.ke.qq.com.dao.FoxDao)")
    

      args :args表达式的作用是匹配指定参数类型和指定参数数量的方法,与包名和类名无关

    @Pointcut("args(String)") 
    @Pointcut("args(String ...) || args()")
    

      @target   目标对象有配置@Dao注解

    @Pointcut("@target(bat.ke.qq.com.anno.Dao)")
    

      @args  传参类型配置@Dao的类型

    @Pointcut("@args(bat.ke.qq.com.anno.Dao)") 
    

      @within 

      @annotation   作用方法级别,配置@Yuanma  自定义注解;只用对使用该注解的方法生效; @Transactional注解就是基于该方式

    @Pointcut("@annotation(bat.ke.qq.com.anno.Yuanma)")
    

      bean  指定的bean

    @Pointcut("bean(foxDao)") 
    @Pointcut("bean(*Service)")
    

      注意: 上述所有的表达式可以混合使用,|| && !

     

  • 相关阅读:
    WebRTC的一个例子
    Gerrit增加SSL证书
    Ruby on Rails 创建https应用
    使用Ruby来实现批量更新AD中字段
    pg gem 安装(postgresql94)
    Spark源码剖析(一):如何将spark源码导入到IDEA中
    Scala入门系列(十三):类型参数
    Scala入门系列(十二):隐式转换
    Scala 安装 Exception in thread "main" java.lang.VerifyError: Uninitialized object exists on backward branch 96
    Scala入门系列(十一):模式匹配
  • 原文地址:https://www.cnblogs.com/wl20200316/p/12792057.html
Copyright © 2020-2023  润新知