目录
2.1. 创建一个MetadataAwareAspectInstanceFactory对象
bean创建过程中,在createBean步骤的resolveBeforeInstantiation中会调用beanPostProcessor处理器执行各自的postProcessBeforeInstantiation方法。在Spring在引入了AOP的情况下,后置处理器会多出一个AnnotationAwareAspectJAutoProxyCreator。在创建bean进行到该步骤的时候,该beanPostProcessor会在postProcessBeforeInstantiation方法中进行代理类Pointcut,JointPoint,Advice,Advisor的解析和缓存。为后续初始化bean中实现bean的代理做好准备。
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
直接来看调用ibp.postProcessBeforeInstantiation(beanClass, beanName)的实现方法,
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
// 如果是普通bean,则返回beanName,如果是FactoryBean,则返回加上前缀&的&beanName
Object cacheKey = getCacheKey(beanClass, beanName);
// 第一次进入时,targetSourcedBeans还未缓存有对象,故会进入。
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// 如果this.advisedBeans有缓存值,说明该bean已经被解析过了,直接返回null就跳过了后续的解析
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 基础类不应该被代理
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 如果用户自定义了TargetSource,那么直接返回用户自定义的代理类。否则返回null,使得Spring框架能继续执行下去。
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;
}
首先getCacheKey是获取beanName,如果是FactoryBean,那么beanName是要加上前缀"&"。第一次进入时,if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName))肯定是会进入的。如果advisedBeans有缓存值,说明该bean已经被解析过了,直接返回null就跳过了后续的解析,否则进入第二个if分支。第一个条件isInfrastructureClass()是判断当前bean类型是否是基础类型,如果是则不会被代理。基础类型有Advice.class,Pointcut.class, Advisor.class, AopInfrastructureBean.class这4种。关键的核心代码是在shouldSkip(beanClass, beanName)中,返回的结果用于判断是否要跳过解析。但是执行的过程却远远不是一句话能说明白的,我们一起深入剖析shouldSkip方法。(后续的getCustomTargetSource方法是返回用户自定义的代理类。如果没有定义就返回null,使得Spring框架能继续执行下去。这里后续不再分析~)
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// findCandidateAdvisors最终会由BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans执行
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 找到的candidate中有beanName与AspectJPointcutAdvisor相同,也就是PointcutAdvisor的实现类,则不会进行作为代理的尝试。
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
// 根据ORIGINAL_INSTANCE_SUFFIX判断给定bean名称是“原始实例”类型,如果是就跳过代理的尝试。
return super.shouldSkip(beanClass, beanName);
}
核心的步骤是findCandidateAdvisors,用于寻找和解析advisor。然后再找到的advisor们中判断是否可以跳过。有两种情况可以被跳过:1.AspectName刚好就是这个bean的name;2.这个bean是原始实例,原始bean的后缀有“.ORIGINAL”标志。
接下来我们进入核心的findCandidateAdvisors方法分析:
protected List<Advisor> findCandidateAdvisors() {
List<Advisor> advisors = super.findCandidateAdvisors();
// 合并全局的advisors后返回
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
1. findCandidateAdvisors
super.findCandidateAdvisors()会借助BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans执行,我们直接来看findAdvisorBeans。
public List<Advisor> findAdvisorBeans() {
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 从bean工厂中寻找Advisor.class,并且是单例类型的beanName
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (th