Spring 如何实现 AOP

简介: Spring 如何实现 AOP

1. 从注解入手找到对应核心类

 

最近工作中我都是基于注解实现 AOP 功能,常用的开启 AOP 的注解是 @EnableAspectJAutoProxy,我们就从它入手。

 

 

上面的动图的流程的步骤就是:@EnableAspectJAutoProxy --> AspectJAutoProxyRegistrar -->AopConfigUtils .registerAspectJAnnotationAutoProxyCreatorIfNecessary -->AnnotationAwareAspectJAutoProxyCreator.class

AnnotationAwareAspectJAutoProxyCreator 查看其中文注释(如下),确定它就是 AOP 的核心类!-- 温安适 20191020

 

  1. AspectJAwareAdvisorAutoProxyCreator的子类 ,用于处理当前应用上下文中的注解切面
  2. 任何被AspectJ注解的类将自动被识别。
  3. 若SpringAOP代理模式可以识别,优先使用Spring代理模式。
  4. 它覆盖了方法执行连接点
  5. 如果使用aop:include元素, 则只有名称与include模式匹配的@aspectj bean才被视为切面 ,并由spring自动代理。
  6. Spring Advisors的处理请查阅,
org.springframework.aop
.framework.autoproxy.AbstractAdvisorAutoProxyCreator
 
@SuppressWarnings("serial")
public class AnnotationAwareAspectJAutoProxyCreator
extends AspectJAwareAdvisorAutoProxyCreator {
    //...省略实现
    }注解切面

 

虽然找到了核心类,但是并没有找到核心方法!下面我们尝试画类图确定核心方法。

 

2. 画核心类类图,猜测核心方法

 

AnnotationAwareAspectJAutoProxyCreator 的部分类图。

 

 

AnnotationAwareAspectJAutoProxyCreator 从类图看到了 AnnotationAwareAspectJAutoProxyCreator 实现了 BeanPostProcessor,而 AOP 功能应该在创建完 Bean 之后执行,猜测 AnnotationAwareAspectJAutoProxyCreator 实现 BeanPostProcessor 的 postProcessAfterInitialization(实例化 bean 后处理)是核心方法。

 

查看 AnnotationAwareAspectJAutoProxyCreator 实现的 postProcessAfterInitialization 方法,实际该方法在其父类 AbstractAutoProxyCreator 中。

 

//AbstractAutoProxyCreator中的postProcessAfterInitialization实现
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
 throws BeansException {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (!this.earlyProxyReferences.contains(cacheKey)) {
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}

 

发现发现疑似方法 wrapIfNecessary,查看其源码如下,发现 createProxy 方法。确定找对了地方。

 

protected Object wrapIfNecessary
        (Object bean, String beanName, Object cacheKey) {
   if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }
   if (isInfrastructureClass(bean.getClass())
                   || shouldSkip(bean.getClass(), beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
   }
 
   // 创建代理
   Object\[\] specificInterceptors =
       getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   if (specificInterceptors != DO\_NOT\_PROXY) {
      this.advisedBeans.put(cacheKey, Boolean.TRUE);
      Object proxy = createProxy(
            bean.getClass(), beanName,
            specificInterceptors, new SingletonTargetSource(bean));
      this.proxyTypes.put(cacheKey, proxy.getClass());
      return proxy;
   }
 
   this.advisedBeans.put(cacheKey, Boolean.FALSE);
   return bean;
}

 

即 AnnotationAwareAspectJAutoProxyCreator 实现 BeanPostProcessor 的 postProcessAfterInitialization 方法,在该方法中由 wrapIfNecessary 实现了 AOP 的功能。wrapIfNecessary 中有 2 个和核心方法

 

  • getAdvicesAndAdvisorsForBean 获取当前 bean 匹配的增强器
  • createProxy 为当前 bean 创建代理 要想明白核心流程还需要分析这 2 个方法。

 

3. 读重点方法,理核心流程

 

3.1 getAdvicesAndAdvisorsForBean 获取当前 bean 匹配的增强器

查看源码如下,默认实现在 AbstractAdvisorAutoProxyCreator 中。

 

@Override
@Nullable
protected Object\[\] getAdvicesAndAdvisorsForBean(
      Class<?> beanClass, String beanName,
      @Nullable TargetSource targetSource) {
   List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
   if (advisors.isEmpty()) {
      return DO\_NOT\_PROXY;
   }
   return advisors.toArray();
}

 

查阅 findEligibleAdvisors 方法,就干了 3 件事

 

  • 找所有增强器,也就是所有 @Aspect 注解的 Bean
  • 找匹配的增强器,也就是根据 @Before,@After 等注解上的表达式,与当前 bean 进行匹配,暴露匹配上的。
  • 对匹配的增强器进行扩展和排序,就是按照 @Order 或者 PriorityOrdered 的 getOrder 的数据值进行排序,越小的越靠前。
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
   //找所有增强器
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
   //找所有匹配的增强器
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
   extendAdvisors(eligibleAdvisors);
   if (!eligibleAdvisors.isEmpty()) {
       //排序
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
}

 

AnnotationAwareAspectJAutoProxyCreator 重写了 findCandidateAdvisors,下面我们看看具体实现了什么

 

3.1.1findCandidateAdvisors 找所有增强器,也就是所有 @Aspect 注解的 Bean

 

@Override
protected List<Advisor> findCandidateAdvisors() {
   // Add all the Spring advisors found according to superclass rules.
   List<Advisor> advisors = super.findCandidateAdvisors();
   // Build Advisors for all AspectJ aspects in the bean factory.
   if (this.aspectJAdvisorsBuilder != null) {
      //@Aspect注解的类在这里除了
      advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
   }
   return advisors;
}

 

从该方法我们可以看到处理 @Aspect 注解的 bean 的方法是:this.aspectJAdvisorsBuilder.buildAspectJAdvisors()。这个方法如下:

 

public List<Advisor> buildAspectJAdvisors() {
   List<String> aspectNames = this.aspectBeanNames;
 
   if (aspectNames == null) {
      synchronized (this) {
         aspectNames = this.aspectBeanNames;
         if (aspectNames == null) {
            List<Advisor> advisors = new ArrayList<>();
            aspectNames = new ArrayList<>();
            //找到所有BeanName
            String\[\] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                  this.beanFactory, Object.class, true, false);
            for (String beanName : beanNames) {
               if (!isEligibleBean(beanName)) {
                  continue;
               }
               // 必须注意,bean会提前暴露,并被Spring容器缓存,但是这时还不能织入。
               Class<?> beanType = this.beanFactory.getType(beanName);
               if (beanType == null) {
                  continue;
               }
               if (this.advisorFactory.isAspect(beanType)) {
                  //找到所有被@Aspect注解的类
                  aspectNames.add(beanName);
                  AspectMetadata amd = new AspectMetadata(beanType, beanName);
                  if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                     MetadataAwareAspectInstanceFactory factory =
                           new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                     //解析封装为Advisor返回
                     List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                     if (this.beanFactory.isSingleton(beanName)) {
                        this.advisorsCache.put(beanName, classAdvisors);
                     }
                     else {
                        this.aspectFactoryCache.put(beanName, factory);
                     }
                     advisors.addAll(classAdvisors);
                  }
                  else {
                     // Per target or per this.
                     if (this.beanFactory.isSingleton(beanName)) {
                        throw new IllegalArgumentException("Bean with name '" + beanName +
                              "' is a singleton, but aspect instantiation model is not singleton");
                     }
                     MetadataAwareAspectInstanceFactory factory =
                           new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                     this.aspectFactoryCache.put(beanName, factory);
                     advisors.addAll(this.advisorFactory.getAdvisors(factory));
                  }
               }
            }
            this.aspectBeanNames = aspectNames;
            return advisors;
         }
      }
   }
 
   if (aspectNames.isEmpty()) {
      return Collections.emptyList();
   }
   List<Advisor> advisors = new ArrayList<>();
   for (String aspectName : aspectNames) {
      List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
      if (cachedAdvisors != null) {
         advisors.addAll(cachedAdvisors);
      }
      else {
         MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
         advisors.addAll(this.advisorFactory.getAdvisors(factory));
      }
   }
   return advisors;
}

 

这个方法可以概括为:

 

  • 找到所有 BeanName
  • 根据 BeanName 筛选出被 @Aspect 注解的类
  • 针对类中被 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 注解的方法,先按上边的注解顺序排序后按方法名称排序,每一个方法对应一个 Advisor。

 

3.2 createProxy 为当前 bean 创建代理。

 

3.2.1 创建代理的 2 种方式

 

众所周知,创建代理的常用的 2 种方式是:JDK 创建和 CGLIB,下面我们就看看这 2 中创建代理的例子。

 

3.2.1 .1 jdk 创建代理的例子

 

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
 
public class JDKProxyMain {
 
    public static void main(String\[\] args) {
        JDKProxyTestInterface target = new JDKProxyTestInterfaceImpl();
        // 根据目标对象创建代理对象
        JDKProxyTestInterface proxy =
         (JDKProxyTestInterface) Proxy
         .newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new JDKProxyTestInvocationHandler(target));
        // 调用代理对象方法
        proxy.testProxy();
    }
 
    interface JDKProxyTestInterface {
        void testProxy();
    }
    static class JDKProxyTestInterfaceImpl
                    implements JDKProxyTestInterface {
        @Override
        public void testProxy() {
            System.out.println("testProxy");
        }
    }
   static class JDKProxyTestInvocationHandler
                           implements InvocationHandler {
        private  Object target;
        public JDKProxyTestInvocationHandler(Object target){
            this.target=target;
        }
        @Override
        public Object invoke(Object proxy, Method method,
                             Object\[\] args) throws Throwable {
            System.out.println("执行前");
            Object result=  method.invoke(this.target,args);
            System.out.println("执行后");
            return result;
        }
    }

 

3.2.1 .2 cglib 创建代理的例子

 

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxyTest {

  static class CglibProxyService {
       public  CglibProxyService(){
       }
       void sayHello(){
           System.out.println(" hello !");
       }
   }

   static class CglibProxyInterceptor implements MethodInterceptor{
       @Override
       public Object intercept(Object sub, Method method,
            Object\[\] objects, MethodProxy methodProxy)
                                         throws Throwable {
           System.out.println("before hello");
           Object object = methodProxy.invokeSuper(sub, objects);
           System.out.println("after hello");
           return object;
       }
   }

   public static void main(String\[\] args) {
       // 通过CGLIB动态代理获取代理对象的过程
       Enhancer enhancer = new Enhancer();
       // 设置enhancer对象的父类
       enhancer.setSuperclass(CglibProxyService.class);
       // 设置enhancer的回调对象
       enhancer.setCallback(new CglibProxyInterceptor());
       // 创建代理对象
       CglibProxyService proxy= (CglibProxyService)enhancer.create();
       System.out.println(CglibProxyService.class);
       System.out.println(proxy.getClass());
       // 通过代理对象调用目标方法
       proxy.sayHello();
   }
}

 

3.2.1 .3 jdk 创建代理与 cglib 创建代理的区别

 

 

3.2.2 Spring 如何选择的使用哪种方式

 

Spring 的选择选择如何代理时在 DefaultAopProxyFactory 中。

 

public class DefaultAopProxyFactory implements AopProxyFactory,
                                                        Serializable {
   @Override
   public AopProxy createAopProxy(AdvisedSupport config)
                                   throws AopConfigException {
      if (config.isOptimize()
          || config.isProxyTargetClass()
          || hasNoUserSuppliedProxyInterfaces(config)) {
         Class<?> targetClass = config.getTargetClass();
         if (targetClass == null) {
            throw new AopConfigException(
            "TargetSource cannot determine target class: "
            +"Either an interface or a target "+
           " is required for proxy creation.");
         }
         if (targetClass.isInterface()
                 || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
         }
         return new ObjenesisCglibAopProxy(config);
      }
      else {
         return new JdkDynamicAopProxy(config);
      }
   }
   //...
   }

 

  • config.isOptimize() 查看源码注释时发现,这个是配置使用 cglib 代理时,是否使用积极策略。这个值一般不建议使用!
  • config.isProxyTargetClass() 就是 @EnableAspectJAutoProxy 中的 proxyTargetClass 属性。

 

//exposeProxy=true AopContext 可以访问,proxyTargetClass=true CGLIB 生成代理 @EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true)

 

  • hasNoUserSuppliedProxyInterfaces 是否存在可代理的接口

 

总结下 Spring 如何选择创建代理的方式:

 

  1. 如果设置了 proxyTargetClass=true,一定是 CGLIB 代理
  2. 如果 proxyTargetClass=false,目标对象实现了接口,走 JDK 代理
  3. 如果没有实现接口,走 CGLIB 代理

 

4. 总结

 

 

Spring 如何实现 AOP?,您可以这样说:

 

  1. AnnotationAwareAspectJAutoProxyCreator 是 AOP 核心处理类
  2. AnnotationAwareAspectJAutoProxyCreator 实现了 BeanProcessor,其中 postProcessAfterInitialization 是核心方法。
  3. 核心实现分为 2 步 getAdvicesAndAdvisorsForBean 获取当前 bean 匹配的增强器 createProxy 为当前 bean 创建代理
  4. getAdvicesAndAdvisorsForBean 核心逻辑如下 a. 找所有增强器,也就是所有 @Aspect 注解的 Bean b. 找匹配的增强器,也就是根据 @Before,@After 等注解上的表达式,与当前 bean 进行匹配,暴露匹配上的。c. 对匹配的增强器进行扩展和排序,就是按照 @Order 或者 PriorityOrdered 的 getOrder 的数据值进行排序,越小的越靠前。
  5. createProxy 有 2 种创建方法,JDK 代理或 CGLIB a. 如果设置了 proxyTargetClass=true,一定是 CGLIB 代理 b. 如果 proxyTargetClass=false,目标对象实现了接口,走 JDK 代理 c. 如果没有实现接口,走 CGLIB 代理
相关文章
|
4月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
19天前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
2月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
40 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
25天前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
30 1
|
21天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
31 0
|
3月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
2月前
|
Java 编译器 Spring
Spring AOP 和 AspectJ 的区别
Spring AOP和AspectJ AOP都是面向切面编程(AOP)的实现,但它们在实现方式、灵活性、依赖性、性能和使用场景等方面存在显著区别。‌
85 2
|
2月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
134 9
|
2月前
|
XML Java 数据格式
Spring的IOC和AOP
Spring的IOC和AOP
48 0
|
3月前
|
Java 数据库连接 数据库
Spring基础3——AOP,事务管理
AOP简介、入门案例、工作流程、切入点表达式、环绕通知、通知获取参数或返回值或异常、事务管理
Spring基础3——AOP,事务管理