创意电子
标题:
Spring AOP 源码一(注解)
[打印本页]
作者:
军无天下
时间:
2021-10-8 14:13
标题:
Spring AOP 源码一(注解)
使用@EnableAspectJAutoProxy这么一个注解就可以开启Spring的AOP,接下来就可以使用AOP的功能了。
注入AnnotationAwareAspectJAutoProxyCreator
在@EnableAspectJAutoProxy中有个@Import注解,这个注解中的类分为三种:
实现ImportBeanDefinitionRegistrar
实现ImportSelector
普通类
在这个注解中实现了第一种ImportBeanDefinitionRegistrar,在AspectJAutoProxyRegistrar#registerBeanDefinitions方法中注入了AnnotationAwareAspectJAutoProxyCreator类。
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(AspectJAutoProxyRegistrar.class)public @interface EnableAspectJAutoProxy { boolean proxyTargetClass() default false; boolean exposeProxy() default false;}class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // AnnotationAwareAspectJAutoProxyCreator的注入在该类中实现 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); } } }}<hr>
AnnotationAwareAspectJAutoProxyCreator UML图
登录/注册后可看大图
AnnotationAwareAspectJAutoProxyCreator UML图
通过上面的UML图可以看到该类实现了左上角的几个接口,这几个接口是在bean实例化和初始化进行的操作。
<hr>
实例化前的操作
AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessor接口,那么在refresh方法中就会将该类放入beanPostProcessors集合中而且该类又实现了InstantiationAwareBeanPostProcessor接口,会将hasInstantiationAwareBeanPostProcessors变量置为true,这是一个volatile的成员变量,这里将该变量置为true,那么后续普通对象在进行实例化时会调用对应的applyBeanPostProcessorsBeforeInstantiation方法(
AnnotationAwareAspectJAutoProxyCreator类会在普通类实例化前初始化好
)。
我们定义的普通类在调用AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])方法时会调用resolveBeforeInstantiation方法,在该方法中就会调用AnnotationAwareAspectJAutoProxyCreator类或者其父类中相关AOP的方法,其他InstantiationAwareBeanPostProcessor接口的实现类默认返回的是null。
public Object postProcessBeforeInstantiation(Class beanClass, String beanName) { // 1. 为给定beanClass和beanName生成缓存key Object cacheKey = getCacheKey(beanClass, beanName); // 2. 如果没设置beanName,或者targetSourcedBeans缓存不包含该beanName if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) { // 3. 判断是否已经包含 bean 的增强器 如果advisedBeans缓存包含该beanName,表示已经被处置惩罚了,返回null if (this.advisedBeans.containsKey(cacheKey)) { //返回null,表示会走Spring创建对象的逻辑,但是后面的postProcessAfterInitialization方法中不会再创建代理 return null; } // 4. 判断 bean 的范例:Advice,Pointcut,Advisor,AopInfrastructureBean // 如果当前bean是Spring AOP的基础结构类,或者shouldSkip返回true,表示不需要代理 // 这个shouldSkip方法,在AspectJAwareAdvisorAutoProxyCreator子类中将会被重写并初始化全部的Advisor通知器实例 // 对于isInfrastructureClass这个方法,如果是注解式的AOP使用的话,进入的是AnnotationAwareAspectJAutoProxyCreator类 // 验证是否含有@Aspect注解,如果含有这个注解,则返回null,会进行后续的实例化、属性注入、初始化等操作然后进行代理。 // 如果不含有这个注解,则继续判断shouldSkip这个方法,那么这个方法在AspectJAwareAdvisorAutoProxyCreator中 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { // 那么当前cacheKey和value=false存入advisedBeans缓存,表示已处置惩罚过而且无需代理 this.advisedBeans.put(cacheKey, Boolean.FALSE); // 返回null,表示会走Spring创建对象的逻辑,但是后面的postProcessAfterInitialization方法中不会再创建代理 return null; } } // 如果我们有自定义的TargetSource,那么目标bean没必要通过Spring的机制实例化 // 而是使用自定义的TargetSource将以自定义方式实例化目标实例,进而在此处创建代理对象 // 根据beanClass和beanName获取对应的自定义TargetSource // Create proxy here if we have a custom TargetSource. // Suppresses unnecessary default instantiation of the target bean: // The TargetSource will handle target instances in a custom fashion. TargetSource targetSource = getCustomTargetSource(beanClass, beanName); // 如果获取到了自定义目标源,那么需要再当前方法创建代理 if (targetSource != null) { if (StringUtils.hasLength(beanName)) { // 参加targetSourcedBeans缓存集合,表示已处置惩罚过,后面的postProcessAfterInitialization方法中不会再创建代理 this.targetSourcedBeans.add(beanName); } // 获取当前bean的Advisor通知器 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); // 5. 创建代理类 Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); // 将当前cacheKey和代理对象class存入proxyTypes缓存中 this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } // 返回null,表示会走Spring创建对象的逻辑 return null; }<hr>
isInfrastructureClass
使用注解方式的AOP的话,该方法会进入AnnotationAwareAspectJAutoProxyCreator类中对应的方法
protected boolean isInfrastructureClass(Class beanClass) { return (super.isInfrastructureClass(beanClass) || (this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass)));}
isInfrastructureClass方法是判断传入的类是否实现了Advice,Pointcut,Advisor几个接口,如果实现了直接返回true,如果没有实现接着判断传入的类是否含有@Aspect注解。
备注:
我们在写AOP相关实现时一般不会实现Advice,Pointcut,Advisor这几个接口,以是一般都会返回false;而普通的bean是不会有@Aspect注解的。以是如果是普通的bean这里整体返回false;如果是含有@Aspect注解的bean,这里返回true
<hr>
shouldSkip
如果isInfrastructureClass方法返回false的话,那么就要接着判断该方法。该方法重要做了两件事
扫描bean中符合条件的Advisor
判断该bean是否是原始bean
扫描bean中符合条件的Advisor
shouldSkip方法会调用AspectJAwareAdvisorAutoProxyCreator类中对应的方法
protected boolean shouldSkip(Class beanClass, String beanName) { // TODO: Consider optimization by caching the list of the aspect names /** * 此处如果是注解式的AOP,那么调用的是{@link AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors()} 方法 * 否则调用的是{@link AbstractAdvisorAutoProxyCreator#findCandidateAdvisors()} 方法 */ List candidateAdvisors = findCandidateAdvisors(); for (Advisor advisor : candidateAdvisors) { if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) { return true; } } return super.shouldSkip(beanClass, beanName);}
从上面代码也可以看出做了两件事,针对注解式的AOP,findCandidateAdvisors方法肯定调用的是AnnotationAwareAspectJAutoProxyCreator类中方法。
protected List findCandidateAdvisors() { // Add all the Spring advisors found according to superclass rules. // 当使用注解方式配置AOP的时候并不是丢弃了对XML配置的支持, // 在这里调用父类方法加载配置文件中的AOP声明 List advisors = super.findCandidateAdvisors(); // Build Advisors for all AspectJ aspects in the bean factory. if (this.aspectJAdvisorsBuilder != null) { /** * AnnotationAwareAspectJAutoProxyCreator间接继承了AbstractAdvisorAutoProxyCreator, * 在实现获取增强的方法中除了保留父类的获取配置文件中定义的增强外,同时添加了获取Bean的注解增强的功能, * 那么实在现正是由this.aspectJAdvisorsBuilder.buildAspectJAdvisors()来实现的。 * 从beanFactory中查找所有@Aspect注解的切面bean定义中的通知并构建,将切面类中全部合法的通知方法和引介字段转换为Advisor,最后返回所有的Advisor集合 */ advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }
注解的AOP,在第一行代码返回的结果为null,接着会进入aspectJAdvisorsBuilder.buildAspectJAdvisors()进行扫描。
public List buildAspectJAdvisors() { // 获取缓存的切面名称集合 List aspectNames = this.aspectBeanNames; if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { List advisors = new ArrayList(); aspectNames = new ArrayList(); /* * 获取全部Object范例的bean定义的beanName数组,注意这里获取的范例是Object范例 */ String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); // System.out.println(Arrays.toString(beanNames)); // 循环所有的beanName找出对应的增强方法 for (String beanName : beanNames) { /* * 判断切面bean的名称是否及格,也就是符合子标签的配置模式 * 该方法在BeanFactoryAspectJAdvisorsBuilder中默认返回true, * 被子类BeanFactoryAspectJAdvisorsBuilderAdapter重写,重写的方法中会 * 调用AnnotationAwareAspectJAutoProxyCreator的isEligibleAspectBean继续判断 */ if (!isEligibleBean(beanName)) { continue; } // We must be careful not to instantiate beans eagerly as in this case they // would be cached by the Spring container but would not have been weaved. // 获取对应的bean的Class范例 Class beanType = this.beanFactory.getType(beanName); if (beanType == null) { continue; } /* * 判断是否是切面类,即判断当前类以及它集成的超类或者实现的接口上是否具有@Aspect注解 * 只有具有该注解的类才气进一步处置惩罚,也就是解析为Advisor * * 从这里能够看出来,bean定义只有仙贝注册到容易中才气进一步解析@Aspect注解,因此 * 对于切面类我们通常需要同时添加@Component和@Aspect注解 */ if (this.advisorFactory.isAspect(beanType)) { // 当前beanName添加到aspectNames集合中,后续从该集合中直接获取 aspectNames.add(beanName); // 根据当前beanType和beanName,新建一个AspectMetaData切面元数据,生存了@Aspect注解的信息以及当前切面类的信息 AspectMetadata amd = new AspectMetadata(beanType, beanName); /* * 如果没有设置@Aspect注解的value属性值,那么就是默认单例的切面类 * value可以设置为值的有perthis() pertarget() perflow() 等等,可以设置切面类的作用域 */ if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { // 新建一个BeanFactoryAspectInstanceFactory工厂对象,用于创建 AspectJ 切面实例 MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); // 解析标志Aspect注解中的增强方法,这个算是最复杂的了 /* * 通过 advisorFactory 调用 getAdvisors 方法 * 将当前切面类中全部合法的通知方法和引介字段转换为Advisor通知器集合 */ List classAdvisors = this.advisorFactory.getAdvisors(factory); // 如果当前切面类是单例bean if (this.beanFactory.isSingleton(beanName)) { // 将单签切面类beanName和内部的通知器集合存入advisorsCache缓存中 this.advisorsCache.put(beanName, classAdvisors); } else { // 否则将当前切面类beanName和切面实例工厂存入aspectFactoryCache缓存中 this.aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors); } else { // 对于其他切面类的作用域处置惩罚 // Per target or per this. // 如果当前切面类的bean是单例,那么抛出非常 if (this.beanFactory.isSingleton(beanName)) { throw new IllegalArgumentException("Bean with name '" + beanName + "' is a singleton, but aspect instantiation model is not singleton"); } // 新建一个PrototypeAspectInstanceFactory工厂对象,用于创建AspectJ切面实例,可能会多次创建 MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName); this.aspectFactoryCache.put(beanName, factory); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } } this.aspectBeanNames = aspectNames; return advisors; } } } // 如果切面集合为null,返回一个空list if (aspectNames.isEmpty()) { return Collections.emptyList(); } // 记载在缓存中 List advisors = new ArrayList(); for (String aspectName : aspectNames) { List 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; }
扫描出所有Object范例的beanName,然后依次判断该bean是否含有@Aspect注解。如果含有该注解,那么会调用advisorFactory.getAdvisors方法获取所有符合条件的切面包装成Advisor范例(实际是InstantiationModelAwarePointcutAdvisor范例),如果该bean输入单例则放入advisorsCache缓存中,否则放入aspectFactoryCache中。
找到所有的Advisor判断该advisor是否是AspectJPointcutAdvisor范例,如果是该范例而且获取到的aspectName和beanName相等,那么就返回true。
<hr>
判断该bean是否是原始bean
实际这里获取到的advisor不是AspectJPointcutAdvisor范例,那么就接着往下走,调用父类的shouldSkip方法
static boolean isOriginalInstance(String beanName, Class beanClass) { if (!StringUtils.hasLength(beanName) || beanName.length() != beanClass.getName().length() + AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX.length()) { return false; } return (beanName.startsWith(beanClass.getName()) && beanName.endsWith(AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX)); }<hr>
自定义目标源
如果我们有自定义目标源,那么就会从getCustomTargetSource方法中获取TargetSource,然后返回代理类,就不继续后面的实例化、属性注入和初始化等一系列操作了
如果TargetSource返回null,那么整个postProcessBeforeInstantiation方法返回null,就会继续进行后续的一系列操作。
<hr>
总结
针对这块做一下总结,针对bean的实例化等操作分为三个部分:实现了BeanFactoryPostProcessor接口的bean、实现了BeanPostProcessor接口的bean和普通bean,前两种bean在普通bean实例化之前先辈行初始化好,因为普通bean的一系列操作需要用到这些特殊bean。具体的可以看ConfigurationClassPostProcessor的处置惩罚和refresh方法中的registerPostProcessor方法。
在实例化前都会先调用实现了InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation方法。这里需要注意的一点是hasInstantiationAwareBeanPostProcessors变量的由来。
一般实现了InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation方法是直接返回null,因为不返回的null的话就无法继续后序的实例化、属性注入、初始化等操作了。针对AOP的话会调用AbstractAutoProxyCreator#postProcessBeforeInstantiation,在该方法中重要做了如下四件事:
1. 调用isInfrastructureClass方法判断该beanClass是否实现了Advice,Pointcut,Advisor接口或者该beanClass是否含有@Aspect注解,如果该结果为true,那么将cacheKey放入advisedBeans集合中并返回null,后续实例化等操作会由spring来完成
2. 如果isInfrastructureClass返回false,那么继续调用shouldSkip方法判断是否需要跳过,如果返回true,那么也是和第一步操作一样将cacheKey放入advisedBeans集合中并返回null,后续实例化等操作会由spring来完成。这里需要注意一点的是针对注解式的AOP需要查询出所有符合条件的通知放入缓存中
3. 如果前两点都返回false,那么调用getCustomTargetSource方法判断返回的TargetSource是否为null,如果不为null,返回Proxy,不继续后续的实例化等操作了
4. 如果第三点返回null,那么该方法返回null,后续的实例化等操作交由spring完成
如果是普通的bean,那么前两个条件都返回false,第三个TargetSource结果为null,最后会走到第四步返回null;如果是含有@Aspect注解的bean,那么就会在第一步就结束。
初始化后的操作放在下一篇文章
欢迎光临 创意电子 (https://wxcydz.cc/)
Powered by Discuz! X3.4