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

80 篇文章 4 订阅

1.@EnableAspectJAutoProxy

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

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)

该类的源码如下:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

 /**
  * Register, escalate, and configure the AspectJ auto proxy creator based on the value
  * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
  * {@code @Configuration} class.
  */
 @Override
 public void registerBeanDefinitions(
   AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

  AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

  AnnotationAttributes enableAspectJAutoProxy =
    AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
  if (enableAspectJAutoProxy != null) {
   if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
   }
   if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
    AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
   }
  }
 }

}

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

重点看这行代码:

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

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

private static BeanDefinition registerOrEscalateApcAsRequired(
   Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

  Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

  if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
   BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
   if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
    int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
    int requiredPriority = findPriorityForClass(cls);
    if (currentPriority < requiredPriority) {
     apcDefinition.setBeanClassName(cls.getName());
    }
   }
   return null;
  }

  RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
  beanDefinition.setSource(source);
  beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
  beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
  registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
  return beanDefinition;
 }

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

2.准备AOP代码材料

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

  • 被增强对象以及方法:

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

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

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

    before......
    print().......
    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,代码如下:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
  if (System.getSecurityManager() != null) {
   AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    invokeAwareMethods(beanName, bean);
    return null;
   }, getAccessControlContext());
  }
  else {
      //处理Aware接口的方法回调
   invokeAwareMethods(beanName, bean);
  }

  Object wrappedBean = bean;
  if (mbd == null || !mbd.isSynthetic()) {
      //遍历所有后置处理器 调用后置处理器的postProcessBeforeInitialization方法
   wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  }

  try {
      //执行自定义初始化方法如自定义的:init方法
   invokeInitMethods(beanName, wrappedBean, mbd);
  }
  catch (Throwable ex) {
   throw new BeanCreationException(
     (mbd != null ? mbd.getResourceDescription() : null),
     beanName, "Invocation of init method failed", ex);
  }
  if (mbd == null || !mbd.isSynthetic()) {
      //遍历所有后置处理器 调用postProcessAfterInitialization
   wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  }

  return wrappedBean;
 }

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

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

public interface BeanPostProcessor {
 //bean实例化前的回调操作
 @Nullable
 default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  return bean;
 }
//bean实例化后的回调操作
 @Nullable
 default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  return bean;
 }

}

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

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

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
  if (bean != null) {
   Object cacheKey = getCacheKey(bean.getClass(), beanName);
   if (this.earlyProxyReferences.remove(cacheKey) != bean) {
    return wrapIfNecessary(bean, beanName, cacheKey);
   }
  }
  return bean;
 }
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   if (StringUtils.hasLength(beanName) && 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;
   }

   // Create proxy if we have advice.
   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;
}

真正的代理对象是在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 自动创建代理

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


原文链接

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值