public List<Advisor> buildAspectJAdvisors() { synchronized (this) { (1) String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); (2) for (String beanName : beanNames) { (3) if (this.advisorFactory.isAspect(beanType)) { MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName); (4) advisors.addAll(this.advisorFactory.getAdvisors(factory)); } (5) this.aspectBeanNames = aspectNames; return advisors; } } }
构建过程分析:
- 找到容器所有的BeanDefinition
- 遍历这些BeanDefinition
- 判断他是不是
isAspect
类: 此步(AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
查看其是不是被Aspect
标注 - 从此
Aspect
类中把所有的建议者提取出来,注册成Bean - 标配缓存(
spring 很多工具类都注重缓存的使用
)
建议者识别提取过程最重要的就在第4步中,我们再深入看看这一步到底干了什么。
这一步是由ReflectiveAspectJAdvisorFactory
完成的
从Aspect
类中识别建议者并注册Bean
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) { for (Method method : getAdvisorMethods(aspectClass)【1】) { Advisor advisor = 【2】getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName); if (advisor != null) { advisors.add(advisor); } } // Find introduction fields. for (Field field : aspectClass.getDeclaredFields()【3】) { Advisor advisor = 【4】getDeclareParentsAdvisor(field); if (advisor != null) { advisors.add(advisor); } } return advisors; }
流程:
- 先获取被
Aspect
注解的类中,所有的可能是建议者的方法:getAdvisorMethods
获取的是不被Pointcut
注解注释的方法,这些都可能是建议者方法,(包含父类,接口方法) - 遍历这些方法:
getAdvisor
尝试解析这些方法是不是建议者,通过查看其是否被以下注解标注来判断。
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] { Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
是的话,解析注解上的切点信息[列如:上文例子中@Before("webLog()")
注解里的weblog()所代表的切点] . 连同本方法信息包装成一个InstantiationModelAwarePointcutAdvisorImpl
建议者。
此时
- 本方法内容是建议内容,方法会包装为
AspectJMethodBeforeAdvice
建议 webLog()
是切点InstantiationModelAwarePointcutAdvisorImpl
就是建议者
- 获取被
@DeclareParents
注解的属性:这里也可以配置建议者。不同于Before
之类的注解标注的方法的是对存在方法的增强。 此种增强叫做引介增强,一个Java类,没有实现A接口,在不修改Java类的情况下,使其具备A接口的功能
.这就是引介增强
4.为配置的引介增强创建一个建议者:DeclareParentsAdvisor
此时@Aspect注解的类里配置的建议都被解析出来,并创建了建议者
- @Aspect注解的类:可以配置多个建议者
- @Aspect注解的类:可以配置两种增强,普通增强与引介增强
(3.事务建议者
我们再来看看事务建议者是如何被找到的呢?
启动事务注解EnableTransactionManagement
会注册一个ProxyTransactionManagementConfiguration
配置类
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() { BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor(); advisor.setTransactionAttributeSource(transactionAttributeSource()); advisor.setAdvice(transactionInterceptor()); advisor.setOrder(this.enableTx.<Integer>getNumber("order")); return advisor; } .... }
此配置类,直接注册一个建议者:
BeanFactoryTransactionAttributeSourceAdvisor
此建议者:以TransactionInterceptor
为建议,以TransactionAttributeSourcePointcut
为切点。
我们的@Transactional
注解在目标方法扮演的角色是标记,谁的标记?切点的标记,
我们回顾下切点的意义:表示对哪些进行增强,具体表现在其matches
方法上,来匹配范围
public boolean matches(Method method, Class<?> targetClass) { if (TransactionalProxy.class.isAssignableFrom(targetClass)) { return false; } TransactionAttributeSource tas = getTransactionAttributeSource(); return (tas == null || tas.getTransactionAttribute(method, targetClass) != null); }
TransactionAttributeSourcePointcut
切点的TransactionAttributeSource
的getTransactionAttribute方法,会计算目标方法是否符合被增强的条件,其中决定性的是否被@Transactional
标记
到此两种建议者的获取过程,我们已经知晓。有了建议者,接下来就是给目标方法创建创建代理,采纳这些建议。这里涉及到两个问题:
- 在什么时机创建代理?
- 如何创建代理?
2.2.3.代理的创建时机
这一块涉及到Bean的生命周期。
代理的创建时机肯定是有了目标对象后,才会创建代理啊。目标对象都没有,建议者又是建议的谁呢?
AbstractAdvisorAutoProxyCreator
在Bean创建的生命周期最后一步,即初始化完成后,会走一遍BeanPostProcessor.postProcessAfterInitialization
方法,再执行一次扩展。此时Bean已成型。
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { ...... ...... if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
其中BeanPostProcessor的抽象类AbstractAdvisorAutoProxyCreator
会根据是否存在给当前目标对象的建议者,来决定是否创建代理对象。
这块意思很清晰,一个Bean创建出现后,判断是是否有给他提建议的人,有将创建个代理。
2020-5-20修正:说到代理的创建时机,其实有另一种情况。Bean在创建过程中,会尽早暴露一个封装了Bean早期引用的ObjectFactory到第三级缓存,调用ObjectFactory.getObject() 会对Bean执行扩展逻辑。
- 当不存在循环引用时,第三缓存中的逻辑不会被执行,Bean创建完成后将其从第三缓存移除。
- 但是当出现循环依赖时,这个第三缓存中的逻辑会被执行 在获取此Bean时会提前执行 Bean的代理创建过程,但同时此Bean并没有走过生命周期。
所以准确的说,
创建的代理时机是在目标对象引用创建后。这个之后可能是属性赋值之前;也可能是Bean赋值属性,执行完初始化方法之后
.
创建代理的时机就在此处