SpringAOP源码阅读-@EnableAspectJAutoProxy

想使用AspectJ注解定义切面需要使用@EnableAspectJAutoProxy开启。话不多说直接开看

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy 
{

 /**
  * 是否强制使用Cglib
  */

 boolean proxyTargetClass() default false;

 /**
  * 是否可以在AopContext中获取到
  */

 boolean exposeProxy() default false;

}

这个注解的关键在于@Import了一个AspectJAutoProxyRegistrar,下面我们看一下它是干啥的?

AspectJAutoProxyRegistrar

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
 @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);
   }
  }
 }

}

代码真的好短啊

  1. AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary():注册AspectJAnnotationAutoProxyCreatorBeanDefinition
  2. 获取@EnableAspectJAutoProxy注解中的属性并设置到BeanDefinition

注册AspectJAnnotationAutoProxyCreator

public abstract class AopConfigUtils {
 public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
  return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
 }

 @Nullable
 public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
   BeanDefinitionRegistry registry, @Nullable Object source)
 
{

  return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.classregistrysource);
 }

 @Nullable
 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;
 }   
}

代码不能说是简单,只能说是相当容易,就是为AnnotationAwareAspectJAutoProxyCreator定义BeanDefinition,beanName为org.springframework.aop.config.internalAutoProxyCreator

设置注解的属性

注解中两个属性

  • proxyTargetClass
  • exposeProxy
public abstract class AopConfigUtils {
    public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
        }
    }

    public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
        }
    }
}

就是将这两个Boolean值设置到BeanDefinitionMutablePropertyValues

AspectJAnnotationAutoProxyCreator

SpringAOP源码阅读-@EnableAspectJAutoProxy从类图中可以看到它是个BeanPostProcessor

何时为目标类创建代理

单例Bean是在初始化阶段完成Aop代理的创建,完成这项工作的类就是AspectJAnnotationAutoProxyCreator

 protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
     //......................
  if (mbd == null || !mbd.isSynthetic()) {
   wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  }

  return wrappedBean;
 }

该类何时准备好(创建好)

目标类在初始化阶段完成Aop代理,Aop代理的创建需要AspectJAnnotationAutoProxyCreator这个类。那必然需要其在所有目标类创建前,完成创建。

 @Override
 public void refresh() throws BeansException, IllegalStateException {
  synchronized (this.startupShutdownMonitor) {
   StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

   try {
    // Register bean processors that intercept bean creation.
    registerBeanPostProcessors(beanFactory);
   }
   catch (BeansException ex) {
    throw ex;
   }
   finally {
   }
  }
 }

看一下应用上下文刷新方法。有一个地方registerBeanPostProcessors

 protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
  PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
 }
 public static void registerBeanPostProcessors(
   ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext)
 
{
  String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.classtruefalse);
     //............................
    }

我们就看第一行,获取所有BeanPostProcessor的beanName,那必然有AspectJAnnotationAutoProxyCreator。在这一阶段,Spring应用上下文已经为我们准备好了AspectJAnnotationAutoProxyCreator

总结

本文介绍了@EnableAspectJAutoProxy为我们开启了Aop代理的功能,其主要原理就是为我们注册了AspectJAnnotationAutoProxyCreator这么一个BeanPostProcessor,在Bean的初始化阶段会调用该类的postProcessAfterInitialization完成Aop代理的创建工作。


原文始发于微信公众号(溪溪技术笔记):SpringAOP源码阅读-@EnableAspectJAutoProxy

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/207171.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!