Spring系列(五):Spring AOP源码解析
一、@EnableAspectJAutoProxy注解
在主配置类中添加@EnableAspectJAutoProxy注解,开启aop支持,那么@EnableAspectJAutoProxy到底做了什么?接下来分析下:
@EnableAspectJAutoProxy点进去如下:
此时看到了我们非常熟悉的@Import注解,@Import(AspectJAutoProxyRegistrar.class),进入到AspectJAutoProxyRegistrar发现实现了ImportBeanDefinitionRegistrar如下:
复制代码
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);
}
}
}
}
复制代码
会调用registerBeanDefinitions方法,跟进到这个方法里面,主要作用就是往Spring容器中注册AnnotationAwareAspectJAutoProxyCreator的Bean的定义信息:
二、AnnotationAwareAspectJAutoProxyCreator继承图
三、AnnotationAwareAspectJAutoProxyCreator创建代理
首先AnnotationAwareAspectJAutoProxyCreator继承了AbstractAutoProxyCreator实现了BeanFactoryAware接口:
所以在创建AnnotationAwareAspectJAutoProxyCreatorBean的过程中初始化方法里面会调用setBeanFactory方法:
在setBeanFactory方法里面调用initBeanFactory来初始化通知者检索帮助类,后面检索通知会用到。
复制代码
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
}
复制代码
其次AnnotationAwareAspectJAutoProxyCreator继承了AbstractAutoProxyCreator实现了InstantiationAwareBeanPostProcessor接口:
该接口定义了2个方法:postProcessBeforeInstantiation和postProcessAfterInstantiation,所以AbstractAutoProxyCreator实现了这2个方法;还记得我们在Spring IoC源码解析篇分析到如下代码:
resolveBeforeInstantiation方法进去就会调到AbstractAutoProxyCreator的postProcessBeforeInstantiation方法
复制代码
/**
* 在创建Bean的流程中还没调用构造器来实例化Bean的时候进行调用(实例化前后)
* AOP解析切面以及事务解析事务注解都是在这里完成的
* @param beanClass 当前正在创建的Bean的Class对象
* @param beanName beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInstantiation(Class> beanClass, String beanName) throws BeansException {
//构建我们的缓存key
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
//如果被解析过直接返回
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
/**
* 判断是不是基础的Bean(Advice、PointCut、Advisor、AopInfrastructureBean)是就直接跳过
* 判断是不是应该跳过 (AOP解析直接解析出我们的切面信息(并且把我们的切面信息进行缓存),而事务在这里是不会解析的)
*/
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
复制代码
接下来进入到shouldSkip(beanClass, beanName)方法(很重要):
复制代码
protected boolean shouldSkip(Class> beanClass, String beanName) {
/**
* 找到候选的Advisors(通知者或者增强器对象)
*/
List candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
复制代码
接下来看如何找候选的Advisors,findCandidateAdvisors()方法如下:
复制代码
@Override
protected List findCandidateAdvisors() {
//找出事务相关的advisor
List advisors = super.findCandidateAdvisors();
//找出Aspect相关的信息之后封装为一个advisor
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
//返回我们所有的通知
return advisors;
}
复制代码
第一步找事务相关的Advisor:
复制代码
protected List findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
/**
* 通过通知者检测帮助类来帮助我们找到通知
*
*/
return this.advisorRetrievalHelper.findAdvisorBeans();
}
复制代码
第二步找构建AspectJAdvisors:
复制代码
/**
* 去容器中获取到所有的切面信息保存到缓存中
*/
public List buildAspectJAdvisors() {
List aspectNames = this.aspectBeanNames;
//缓存字段aspectNames没有值 注意实例化第一个单实例bean的时候就会触发解析切面
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
//用于保存所有解析出来的Advisors集合对象
List advisors = new ArrayList<>();
//用于保存切面的名称的集合
aspectNames = new ArrayList<>();
/**
* AOP功能中在这里传入的是Object对象,代表去容器中获取到所有的组件的名称,然后再
* 进行遍历,这个过程是十分的消耗性能的,所以说Spring会再这里加入了保存切面信息的缓存。
* 但是事务功能不一样,事务模块的功能是直接去容器中获取Advisor类型的,选择范围小,且不消耗性能。
* 所以Spring在事务模块中没有加入缓存来保存我们的事务相关的advisor
*/
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
//遍历我们从IOC容器中获取处的所有Bean的名称
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
//通过beanName去容器中获取到对应class对象
Class> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
//根据class对象判断是不是切面 @Aspect
if (this.advisorFactory.isAspect(beanType)) {
//是切面类
//加入到缓存中
aspectNames.add(beanName);
//把beanName和class对象构建成为一个AspectMetadata
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
//构建切面注解的实例工厂
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//真正的去获取我们的Advisor
List classAdvisors = this.advisorFactory.getAdvisors(factory);
//加入到缓存中
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
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;
}
复制代码
① org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect:
② 真正的去获取我们的Advisor,this.advisorFactory.getAdvisors(factory)方法如下:
复制代码
@Override
public List getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
//获取我们的标记为Aspect的类
Class> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
//获取我们的切面类的名称
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
//校验我们的切面类
validate(aspectClass);
//我们使用的是包装模式来包装我们的MetadataAwareAspectInstanceFactory构建为MetadataAwareAspectInstanceFactory
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List advisors = new ArrayList<>();
//获取到切面类中的所有方法,但是该方法不会解析到标注了@PointCut注解的方法
for (Method method : getAdvisorMethods(aspectClass)) {
//循环解析我们切面中的方法
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
复制代码
获取切面上的通知方法,并按照规则排序,getAdvisorMethods(aspectClass):
复制代码
private List getAdvisorMethods(Class> aspectClass) {
final List methods = new ArrayList<>();
ReflectionUtils.doWithMethods(aspectClass, method -> {
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
});
methods.sort(METHOD_COMPARATOR);
return methods;
}
复制代码
排序(该顺序在代理调用的时候会用到)规则如下:
根据通知的方法创建增强器:getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName)如下:
复制代码
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
//切面的方法上构建切点表达式
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
//实例化我们的切面通知对象
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
复制代码
实例化我们的切面通知对象,new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName):
复制代码
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
//当前的切点表达式
this.declaredPointcut = declaredPointcut;