一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情。
源码揭秘系列|目录
源码揭秘! Spring IOC之Autowired注解!
源码揭秘! Spring中Bean扫描的原理!
源码揭秘! Spring和Mybatis整合的原理!
源码揭秘! Spring中AOP编程实现原理! (一) 准备动作
源码揭秘! Spring中AOP编程实现原理! (二) Advice类的注册流程
前言
在上一章节中,讲到了我们Advice类在postProcessBeforeInstantiation方法中是如何操作的,由于Bean是Advice的,所以下面代码的第一个条件就进入了。
今天这篇文章来看下被注入类的一个床就流程是什么样的。
正式开始
在注入类中,isInfrastructureClass方法肯定为false,所以此时会进入shouldSkip方法。
shouldSkip方法
Abstract中的shouldSkip方法是下面这样。
由于子类有重写方法,所以此时调用的方法应该是在AspectJAwareAdvisorAutoProxyCreator类中,代码如下。
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
// TODO: 考虑通过缓存方面名称列表进行优化
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
首先看下下面的第一个方法findCandidateAdvisors(),根据方法字面意思查找候选的Advisors。这里要进去看一下。
findCandidateAdvisors
这个方法在AnnotationAwareAspectJAutoProxyCreator类中有重写。
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 添加根据超类规则找到的所有 Spring 顾问。
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
// 为 bean 工厂中的所有 AspectJ 方面构建顾问。
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
该方法构成比较简单,第一个是调用了父类的findCandidateAdvisors方法,随后使用aspectJAdvisorsBuilder去构建,然后塞入advisors中。
这里先看一下父类的findCandidateAdvisors方法。
父类的findCandidateAdvisors方法
这里代码接着往下追。
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
// 确定顾问 bean 名称列表(如果尚未缓存)。
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
// 不要在此处初始化 FactoryBeans:
// 我们需要保留所有常规 bean未初始化让自动代理创建者适用于他们!
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 (this.beanFactory.isCurrentlyInCreation(name)) {
// ... log
}
else {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
// ... log
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
这个方法开始有两个If,第一个If用来判断,判断缓存的advior为空的话,要为其初始化,也就是从BeanFactory获取一下祖先类中包含Adviosr.class的BeanName。
第二个If是判断如果拿到为空的话就返回一个空的ArrayList。
接下来就是遍历刚刚获取到的BeanName,然后判断遍历到的Bean是否正在创建,这里通常情况下,是为False的,随后走入Else逻辑,也就是像advisors中添加当前的Bean。遍历完后返回advisors。
由于我们前没有设置这些Advisor,所以这个方法不出意外是返回一个空的ArrayList。
打断点查看后,不出所料。
findCandidateAdvisors剩余的逻辑
// Build Advisors for all AspectJ aspects in the bean factory.
// 为bean factory中的所有AspectJ方面构建 Advisors。
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
aspectJAdvisorsBuilder此处是不等于null。因为我们的BeanFactory时,创建的DefaultListableBeanFactory,会调用这里的一个initBeanFacotry方法。给这个属性赋值。
buildAspectJAdvisors 方法
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
// ...
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
// ...
}
return advisors;
}
先看下这个方法的大体结构,方法刚开始,创建了一个aspectNames变量,随后判断这个Names是否为空,为Null的话,进入If中,猜测是初始化的逻辑。
随后遍历了这个Name,应该是把aspectName具像化了。最后返回了advisors。
第一个If中的代码
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
// ...
// 不是Aspect类会进行continue操作。
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> 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
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
看这一片代码,跳过一些检验的过程。把这个Beanname加入aspectNames中。然后获取Aspect元数据。然后进行判断,这里会进入If。
根据BeanName创建了一个MetadataAwareAspectInstanceFactory。因为这个里面会有Aspect的Metadata。所以这里可以获取到当前的Advisors,从这里可以知道了,Advisors其实指的就是每一个切入点的指标。随后把指标放入了AdvisorsCache中。然后返回Advisors数据。
后续的代码其实意思相同,因为等于null时,会把数据放入缓存了,所以不等于null时的场景就是,从缓存中获取,然后会出去。
should方法剩余的逻辑
这里就是判断一下,当前beanName是否和刚刚获取到的切入点的操作类的Name一致,如果一致的话,返回True。不一致返回False。剩余很明显返回false。
BeforeInstantiation方法剩余逻辑
在这个地方的代码中,可以看到创建代理了。有几个关键点要说明一下。
specificInterceptors变量赋值了Advices。也就是切入点集合。这里转换了数组。
可以看到的是,在下方的createProxy方法中,放入了这个变量。
告一段落
往后面写文章字数有点多了,此篇文章先到这里,在下一篇中继续讲解。
都看到这了,点个赞再走呗,宝~
结束语
写文章的目的是为了帮助自己巩固知识,写的不好或者错误的地方可以在评论区指出。如果您看了文章觉得对您有所帮助可以点个赞,如果发现有些问题产生了疑惑,或者不明白的可以评论、加我微信,一定知无不言。当然也希望和大家交个朋友,相互学习。