• 【@EnableAspectJAutoProxy为符合切点的目标 bean 自动创建代理】


    1.@EnableAspectJAutoProxy

    我们从@EnableAspectJAutoProxy这个注解开始说起,因为我们都知道想要开启基于注解的AOP的自动代理就需要加上这个注解。

    进入这个注解,它通过@Import标签向容器当中导入了一个注册器。AspectJAutoProxyRegistrar

    1. @Target(ElementType.TYPE)
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Documented
    4. @Import(AspectJAutoProxyRegistrar.class)

    该类的源码如下:

    1. class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    2.  /**
    3.   * Register, escalate, and configure the AspectJ auto proxy creator based on the value
    4.   * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
    5.   * {@code @Configurationclass.
    6.   */
    7.  @Override
    8.  public void registerBeanDefinitions(
    9.    AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    10.   AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
    11.   AnnotationAttributes enableAspectJAutoProxy =
    12.     AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
    13.   if (enableAspectJAutoProxy != null) {
    14.    if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
    15.     AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
    16.    }
    17.    if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
    18.     AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
    19.    }
    20.   }
    21.  }
    22. }

    实现了ImportBeanDefinitionRegistrar接口以及其中的唯一一个方法:registerBeanDefinitions

    重点看这行代码:

    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
    

    该方法跟进去最底层其实就是注册一个BeanDefinition,源码如下:

    1. private static BeanDefinition registerOrEscalateApcAsRequired(
    2.    Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
    3.   Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    4.   if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
    5.    BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
    6.    if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
    7.     int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
    8.     int requiredPriority = findPriorityForClass(cls);
    9.     if (currentPriority < requiredPriority) {
    10.      apcDefinition.setBeanClassName(cls.getName());
    11.     }
    12.    }
    13.    return null;
    14.   }
    15.   RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
    16.   beanDefinition.setSource(source);
    17.   beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
    18.   beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    19.   registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
    20.   return beanDefinition;
    21.  }

    以上代码就是首先判断容器中是否一个名字为:AUTO_PROXY_CREATOR_BEAN_NAME 的一个BeanDefinition,如果没有就创建对应的bean,并根据AUTO_PROXY_CREATOR_BEAN_NAME作为keyName,Value就是:AnnotationAwareAspectJAutoProxyCreator

    2.准备AOP代码材料

    我们可以写一段非常简单的AOP代码:

    • 被增强对象以及方法:

      1. public class MyTarget {
      2.     public void print(){
      3.         System.out.println("print().......");
      4.     }
      5. }
    • 切面类以及切入的点:

      1. @Aspect
      2. public class MyAdvice {
      3.     @Pointcut(value="execution(public void com.itheima.aop.MyTarget.*(..))")
      4.     public void pointcut(){
      5.     }
      6.     @Around(value = "pointcut()")
      7.     public Object testAround(ProceedingJoinPoint point)throws Throwable{
      8.         System.out.println("before......");
      9.         // 这个就是方法的返回值
      10.         Object proceed = point.proceed();
      11.         System.out.println("after....");
      12.         return proceed;
      13.     }
      14. }
    • 配置自动代理以及加入Spring容器进行管理:

      1. @EnableAspectJAutoProxy
      2. @Configuration
      3. public class MyConfigAop {
      4.     //将业务逻辑组件和切面类都加入到容器中;告诉Spring哪个是切面类(@Aspect)需要交给spring管理
      5.     @Bean
      6.     public MyTarget myTarget(){
      7.         return new MyTarget();
      8.     }
      9.     @Bean
      10.     public MyAdvice myAdvice(){
      11.         return new MyAdvice();
      12.     }
      13. }
    • 运行结果:

      1. before......
      2. print().......
      3. after....
    • Debug查看:

      image-20211214181740191

    创建的就是AnnotationAwareAspectJAutoProxyCreator

    3.继承结构

    image-20211214183327446

    顶部基类实现了BeanPostProcessor接口和BeanFactoryAware,说明这个类是一个后置处理器,并且初始化的时候,会自动装配BeanFactory。

    注意:我们的AnnotationAwareAspectJAutoProxyCreator是在容器初始化的过程中进行创建,具体调用时机是在registerBeanPostProcessors(beanFactory);方法

    4.getBean的执行流程

    当我们通过 beanFactory去 getBean() 的时候,调用过程是 getBean---->doGetBean----->getSingleton------->getObject-------->CreatBean------->doCreatBean,我们通过debug也能看到:

    在doCreate方法会调用initializeBean初始化bean,代码如下:

    1. protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    2.   if (System.getSecurityManager() != null) {
    3.    AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    4.     invokeAwareMethods(beanName, bean);
    5.     return null;
    6.    }, getAccessControlContext());
    7.   }
    8.   else {
    9.       //处理Aware接口的方法回调
    10.    invokeAwareMethods(beanName, bean);
    11.   }
    12.   Object wrappedBean = bean;
    13.   if (mbd == null || !mbd.isSynthetic()) {
    14.       //遍历所有后置处理器 调用后置处理器的postProcessBeforeInitialization方法
    15.    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    16.   }
    17.   try {
    18.       //执行自定义初始化方法如自定义的:init方法
    19.    invokeInitMethods(beanName, wrappedBean, mbd);
    20.   }
    21.   catch (Throwable ex) {
    22.    throw new BeanCreationException(
    23.      (mbd != null ? mbd.getResourceDescription() : null),
    24.      beanName, "Invocation of init method failed", ex);
    25.   }
    26.   if (mbd == null || !mbd.isSynthetic()) {
    27.       //遍历所有后置处理器 调用postProcessAfterInitialization
    28.    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    29.   }
    30.   return wrappedBean;
    31.  }

    这也验证了后置处理器是在创建完成 初始化前后起作用的

    而从AnnotationAwareAspectJAutoProxyCreator继承结构中也可以到看到,它是间接继承了后置处理器BeanPostProcessor接口,其中的方法就是以下两个:

    1. public interface BeanPostProcessor {
    2.  //bean实例化前的回调操作
    3.  @Nullable
    4.  default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    5.   return bean;
    6.  }
    7. //bean实例化后的回调操作
    8.  @Nullable
    9.  default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    10.   return bean;
    11.  }
    12. }

    也就是说该类会在bean的实例化和初始化的前后起作用

    那我们的代码对象是在哪儿创建的呢?我们Debug一路追踪发现,其实是在bean初始化完成后调用 postProcessAfterInitialization方法中完成代理对象的创建

    1. public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    2.   if (bean != null) {
    3.    Object cacheKey = getCacheKey(bean.getClass(), beanName);
    4.    if (this.earlyProxyReferences.remove(cacheKey) != bean) {
    5.     return wrapIfNecessary(bean, beanName, cacheKey);
    6.    }
    7.   }
    8.   return bean;
    9.  }
    1. protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    2.    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
    3.       return bean;
    4.    }
    5.    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    6.       return bean;
    7.    }
    8.    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    9.       this.advisedBeans.put(cacheKey, Boolean.FALSE);
    10.       return bean;
    11.    }
    12.    // Create proxy if we have advice.
    13.    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    14.    if (specificInterceptors != DO_NOT_PROXY) {
    15.       this.advisedBeans.put(cacheKey, Boolean.TRUE);
    16.       Object proxy = createProxy(
    17.             bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    18.       this.proxyTypes.put(cacheKey, proxy.getClass());
    19.       return proxy;
    20.    }
    21.    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    22.    return bean;
    23. }

    真正的代理对象是在wrapIfNecessary方法中,Debug也能看到:

    image-20211214192732274

    小结:一下这个包装方法wrapIfNecessary

    1)、获取当前bean的所有增强器(通知方法)  Object[]  specificInterceptors

    1. 找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的)

    2. 获取到能在bean使用的增强器。

    3. 给增强器排序

    2)、保存当前bean在advisedBeans中

    3)、如果当前bean需要增强,创建当前bean的代理对象;

    1. 获取所有增强器(通知方法)

    2. 保存到proxyFactory

    3. 创建代理对象:Spring自动决定 JdkDynamicAopProxy(config);jdk动态代理;ObjenesisCglibAopProxy(config);cglib的动态代理;

    4. 给容器中返回当前组件使用cglib增强了的代理对象;

    总结

    至此,我们Spring Refresh启动过程的第六步源码分析完毕:

    • bean 后处理器,充当 bean 的扩展点,可以工作在 bean 的实例化、依赖注入、初始化阶段

    • AutowiredAnnotationBeanPostProcessor 功能有:解析 @Autowired,@Value 注解

    • CommonAnnotationBeanPostProcessor 功能有:解析 @Resource,@PostConstruct,@PreDestroy

    • AnnotationAwareAspectJAutoProxyCreator 功能有:为符合切点的目标 bean 自动创建代理

    主要涉及到以上三个核心处理器的讲解,最后通过一张图进行总结:


    原文链接

  • 相关阅读:
    【重走 java 路】面向对象之对象数组
    YOLOv8改进实战 | 更换主干网络Backbone(五)之2023最新轻量化主干网络VanillaNet,深度学习中极简主义的力量
    Unity坐标系入门
    JSP SSH 产品质量追溯管理统myeclipse开发mysql数据库MVC模式java编程网页设计
    关于WEB端实现电子海图研究二GeoServer
    Java异常学习
    信奥中的数学:同余
    限制容器中的进程
    Servlet学习(四):urlPattern配置与XML配置
    Elesticsearch使用总结
  • 原文地址:https://blog.csdn.net/u012632105/article/details/126672960