专栏名称: Java专栏
一个Java、Python、数据库、中间件、业内资讯、面试、学习资源等干货的知识分享社区。
目录
相关文章推荐
厦门日报  ·  突发!一客机舱内起火,紧急备降福州! ·  昨天  
厦门日报  ·  刚刚,百度发布声明! ·  2 天前  
厦门日报  ·  俄突发坠机!机组人员全部遇难 ·  2 天前  
厦门日报  ·  即将反转!关窗!关窗!记得关窗! ·  2 天前  
51好读  ›  专栏  ›  Java专栏

Spring如何实现AOP,请不要再说cglib了!

Java专栏  · 公众号  ·  · 2021-03-09 12:20

正文

超全面!Java核心知识总结(点击查看)

超全面!Java核心知识总结(点击查看)


作者:温安适

https://juejin.im/post/6844903970658320391

1. 从注解入手找到对应核心类

最近工作中我都是基于注解实现 AOP 功能,常用的开启 AOP 的注解是 @EnableAspectJAutoProxy,我们就从它入手。

上面的动图的流程的步骤就是:
@EnableAspectJAutoProxy
--> AspectJAutoProxyRegistrar
-->AopConfigUtils .registerAspectJAnnotationAutoProxyCreatorIfNecessary
-->AnnotationAwareAspectJAutoProxyCreator.class

AnnotationAwareAspectJAutoProxyCreator 查看其中文注释(如下),确定它就是 AOP 的核心类!-- 温安适 20191020

  1. AspectJAwareAdvisorAutoProxyCreator的子类 ,用于处理当前应用上下文中的注解切面

  2. 任何被AspectJ注解的类将自动被识别。

  3. 若SpringAOP代理模式可以识别,优先使用Spring代理模式。

  4. 它覆盖了方法执行连接点

  5. 如果使用aop:include元素, 则只有名称与include模式匹配的@aspectj bean才被视为切面 ,并由spring自动代理。

  6. Spring Advisors的处理请查阅,

org.springframework.aop
.framework.autoproxy.AbstractAdvisorAutoProxyCreator

@SuppressWarnings("serial")
public class AnnotationAwareAspectJAutoProxyCreator
extends AspectJAwareAdvisorAutoProxyCreator {
//...省略实现
}注解切面

虽然找到了核心类,但是并没有找到核心方法!下面我们尝试画类图确定核心方法。

2. 画核心类类图,猜测核心方法

AnnotationAwareAspectJAutoProxyCreator 的部分类图。

AnnotationAwareAspectJAutoProxyCreator
从类图看到了 AnnotationAwareAspectJAutoProxyCreator 实现了 BeanPostProcessor,而 AOP 功能应该在创建完 Bean 之后执行,猜测 AnnotationAwareAspectJAutoProxyCreator 实现 BeanPostProcessor 的 postProcessAfterInitialization(实例化 bean 后处理)是核心方法。查看 AnnotationAwareAspectJAutoProxyCreator 实现的 postProcessAfterInitialization 方法,实际该方法在其父类 AbstractAutoProxyCreator 中。

//AbstractAutoProxyCreator中的postProcessAfterInitialization实现
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

发现发现疑似方法 wrapIfNecessary,查看其源码如下,发现 createProxy 方法。确定找对了地方。

protected Object wrapIfNecessary
(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass())
|| shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

// 创建代理
Object\[\] specificInterceptors =
getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO\_NOT\_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName,
specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}

this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

即 AnnotationAwareAspectJAutoProxyCreator 实现 BeanPostProcessor 的 postProcessAfterInitialization 方法,在该方法中由 wrapIfNecessary 实现了 AOP 的功能。wrapIfNecessary 中有 2 个和核心方法

  • getAdvicesAndAdvisorsForBean 获取当前 bean 匹配的增强器

  • createProxy 为当前 bean 创建代理
    要想明白核心流程还需要分析这 2 个方法。

3. 读重点方法,理核心流程

3.1 getAdvicesAndAdvisorsForBean 获取当前 bean 匹配的增强器

查看源码如下,默认实现在 AbstractAdvisorAutoProxyCreator 中。

@Override
@Nullable
protected Object\[\] getAdvicesAndAdvisorsForBean(
Class> beanClass, String beanName,
@Nullable TargetSource targetSource) {
List advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO\_NOT\_PROXY;
}
return advisors.toArray();
}

查阅 findEligibleAdvisors 方法,就干了 3 件事

  • 找所有增强器,也就是所有 @Aspect 注解的 Bean

  • 找匹配的增强器,也就是根据 @Before,@After 等注解上的表达式,与当前 bean 进行匹配,暴露匹配上的。

  • 对匹配的增强器进行扩展和排序,就是按照 @Order 或者 PriorityOrdered 的 getOrder 的数据值进行排序,越小的越靠前。

protected List findEligibleAdvisors(Class> beanClass, String beanName) {
//找所有增强器
List candidateAdvisors = findCandidateAdvisors();
//找所有匹配的增强器
List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
//排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}

AnnotationAwareAspectJAutoProxyCreator 重写了 findCandidateAdvisors,下面我们看看具体实现了什么

3.1.1findCandidateAdvisors 找所有增强器,也就是所有 @Aspect 注解的 Bean

@Override
protected List findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
//@Aspect注解的类在这里除了
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}

从该方法我们可以看到 处理 @Aspect 注解的 bean 的方法是:this.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<>();
//找到所有BeanName
String\[\] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// 必须注意,bean会提前暴露,并被Spring容器缓存,但是这时还不能织入。
Class> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
//找到所有被@Aspect注解的类
aspectNames.add(beanName);
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






请到「今天看啥」查看全文