总结摘要
Spring AOP Aspect 源码01
关键方法列表
- 解析 AOP 配置
- Spring 扩展点
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation方法。 - org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#postProcessBeforeInstantiation
- org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
- 根据 AOP 配置包装 bean
- Spring 扩展点
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation方法。 - org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#postProcessAfterInitialization
- org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
解析 AOP 配置
AbstractAutoProxyCreator#postProcessBeforeInstantiation
源码摘录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| // org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
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;
}
|
流程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| // org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#postProcessBeforeInstantiation 继承父类 postProcessBeforeInstantiation 方法。
// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
--> 构建缓存 key
--|> org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getCacheKey
--> if 存在 beanName 且为 FactoryBean,返回`BeanFactory.FACTORY_BEAN_PREFIX + beanName`。
--> else-if 存在 beanName,返回 beanName。
--> else 返回 beanClass。
--> 如果 beanName 为空或缓存`AbstractAutoProxyCreator#targetSourcedBeans`中不存在 key。
--> 如果缓存`AbstractAutoProxyCreator#advisedBeans`中已经解析 bean 解析结果,则退出方法。
--> 匹配`isInfrastructureClass(beanClass)`条件的 bean 不需要 AOP 代理,退出方法。
--|> org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#isInfrastructureClass
--|> 功能1:Advice, Advisor, Pointcut, AopInfrastructureBean 类型的 Bean 满足条件 isInfrastructureClass,不需要被代理。
--|> 底层调用 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#isInfrastructureClass
--|> 功能2:注解 @Aspect 修饰,且非 ajc 编译的 bean 满足条件 isAspect,进而满足条件 isInfrastructureClass,不需要被代理。
--|> 底层调用 org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect
--> 匹配`shouldSkip(beanClass, beanName)`条件的 bean 不需要 AOP 代理。
--|> org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#shouldSkip
--> 获取所有的 Advisor。
--|> org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors。
--|> 详情参见《分支 findCandidateAdvisors》
--> 如果当前 bean 实现了 AspectJPointcutAdvisor,则跳过。
--|> 目前未看到 AspectJPointcutAdvisor 使用场景,当前的 advisor 均为 InstantiationModelAwarePointcutAdvisorImpl,并未继承 AspectJPointcutAdvisor。
--|> 且 Advisor 类型的 bean,在之前步骤`isInfrastructureClass`中已经过滤了,应当不会执行到这里。
--> 判断是否是`OriginalInstance`,即 bean name 后缀为 “.ORIGINAL”,则跳过。
--|> org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#shouldSkip
--> org.springframework.aop.framework.autoproxy.AutoProxyUtils#isOriginalInstance
--> 如果存在用户自定义的创建代理逻辑 customTargetSourceCreators,则使用该工具创建代理。默认无。
|
AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
源码摘录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
// org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
| // org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
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!
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)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
}
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)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
// Ignore: indicates a reference back to the bean we're trying to advise.
// We want to find advisors other than the currently created bean itself.
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
| // org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
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) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
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 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<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> 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;
}
|
流程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
| // org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
--> 从 beanFactory 中获取所有的 Advisor bean。
--|> org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
--> 从 beanFactory 中获取所有的 Advisor bean。
--|> this.advisorRetrievalHelper.findAdvisorBeans();
--|> org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
--> 如果缓存`BeanFactoryAdvisorRetrievalHelper#cachedAdvisorBeanNames`不为空,表示已经完成查询,可以则直接使用缓存。从第2次查询起可以使用缓存。
--> 第1次查询时,不存在缓存,需构建 bean name 缓存。
--> 从 beanFactory 及祖先 beanFactory 中找到所有`Advisor`类型的 bean name,存储到缓存中。
--|> BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);
--|> org.springframework.beans.factory.BeanFactoryUtils#beanNamesForTypeIncludingAncestors(org.springframework.beans.factory.ListableBeanFactory, java.lang.Class, boolean, boolean)
--> 遍历上一步骤获取的 bean name,如果满足`isEligibleBean`条件,则创建 advisor bean。
--> 匹配条件
--|> isEligibleBean(name)
--|> org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.BeanFactoryAdvisorRetrievalHelperAdapter#isEligibleBean
--> AbstractAdvisorAutoProxyCreator.this.isEligibleAdvisorBean(beanName);
--|> org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#isEligibleAdvisorBean
--|> 始终返回 true。
--|> return true;
--> 创建 bean。
--|> this.beanFactory.getBean(name, Advisor.class)
--|> org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String, java.lang.Class<T>)
--> 构建 Advisor,即获取所有 Spring AOP 配置的切面 Bean。
--|> this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
--|> org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
--> 如果缓存`BeanFactoryAspectJAdvisorsBuilder#aspectBeanNames`为空,需构建 bean name 缓存。第1次查询时,不存在缓存。
--> 从 beanFactory 及祖先 beanFactory 中查询所有的对象,方式是找到所有`Object`类型的 bean name。
--|> BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
--|> org.springframework.beans.factory.BeanFactoryUtils#beanNamesForTypeIncludingAncestors(org.springframework.beans.factory.ListableBeanFactory, java.lang.Class<?>, boolean, boolean)
--> 遍历上一步骤获取的 bean name,如果满足`isEligibleBean`条件且是 AOP 切面 bean,则创建并缓存 advisor。
--> 匹配条件`isEligibleBean(beanName)`,默认始终为 true。不满足条件则跳过。
--|> org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.BeanFactoryAspectJAdvisorsBuilderAdapter#isEligibleBean
--> org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#isEligibleAspectBean
--|> 包含与`<aop:include>`配置相关的匹配条件。
--|> 当前使用 Spring 注解配置,未进行 XML 配置,因此满足 isEligibleBean 条件。
--> 获取 beanType,如果无法获取,则跳过。部分 FactoryBean 场景下无法获取。
--> 匹配条件`this.advisorFactory.isAspect(beanType)`,即是否是 AOP 切面。不满足条件则跳过。
--|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect
--> 判断 bean 是否被注解`@Aspect`修饰,且非 ajc 编译。
--|> 原因是使用AspectJ语言(非 Spring AOP)编写的切面在通过 ajc 编译得到时也会存在`@Aspect`注解。但其并非 Spring 期望的注解方式。
--> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#hasAspectAnnotation
--> AnnotationUtils.findAnnotation(clazz, Aspect.class) != null
--> !compiledByAjc(clazz)
--> 如果切面 bean 的 AjType 特性(Aspect 注解的 value 值配置)是单例,封装为`BeanFactoryAspectInstanceFactory`。
--|> 调用`advisorFactory#getAdvisors` 构造 Advisor。
--|> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
--|> 如果 bean 是单例,则存储到缓存`BeanFactoryAspectJAdvisorsBuilder#advisorsCache`,否则存储到缓存`BeanFactoryAspectJAdvisorsBuilder#aspectFactoryCache`。
--> 如果切面 bean 的 AjType 特性非单例,则 bean 也必须是非单例的,否则抛出异常。
--|> 封装为`PrototypeAspectInstanceFactory`,存储到缓存`BeanFactoryAspectJAdvisorsBuilder#aspectFactoryCache`。
--|> 调用`advisorFactory#getAdvisors`构造 Advisor。
--> 返回所有的 advisor。
--> 如果缓存`BeanFactoryAspectJAdvisorsBuilder#aspectBeanNames`不为空,则基于缓存获取或创建 advisor。从第2次查询起可以使用缓存。
--> 遍历缓存中的 aspectNames。
--> 如果存在于缓存 BeanFactoryAspectJAdvisorsBuilder#advisorsCache 中,则直接使用缓存中的 advisor。
--|> 表示单例 advisor。
--> 如果存在于缓存 BeanFactoryAspectJAdvisorsBuilder#aspectFactoryCache 中,则调用 advisorFactory#getAdvisors 构造 advisor。
--|> 表示非单例 advisor。
--> 返回所有的 advisor。
|
此处的 advisor 有
org.springframework.transaction.config.internalTransactionAdvisor注解驱动事务相关的 AOP。
AbstractAdvisorAutoProxyCreator.this.isEligibleAdvisorBean(beanName);有3种实现
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#isEligibleAdvisorBean- 始终返回 true。
- 启用注解驱动的 Spring AOP 后的默认实现。即已注册
AnnotationAwareAspectJAutoProxyCreator。 - Advisor 查询条件最宽松,可以获取所有 advisor。
org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator#isEligibleAdvisorBean- 校验 bean 的 role 为
BeanDefinition.ROLE_INFRASTRUCTURE。 - 当未启用注解驱动的 Spring AOP,仅支持 Spring 内置的 AOP 场景。即未注册
AnnotationAwareAspectJAutoProxyCreator,而是注册InfrastructureAdvisorAutoProxyCreator时。例如仅启用了注解驱动事务。
org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator#isEligibleAdvisorBean- 校验 bean name 前缀。
- 特殊工具类。
AbstractAspectJAdvisorFactory#isAspect 扩展知识
org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect
We consider something to be an AspectJ aspect suitable for use by the Spring AOP system if it has the @Aspect annotation, and was not compiled by ajc. The reason for this latter test is that aspects written in the code-style (AspectJ language) also have the annotation present when compiled by ajc with the -1.5 flag, yet they cannot be consumed by Spring AOP.
我们认为一个对象是适合由Spring AOP系统使用的AspectJ切面,如果它具有@Aspect注解,并且不是由ajc(AspectJ编译器)编译的。进行后者的检查的原因是,使用AspectJ语言(代码风格)编写的切面在通过ajc编译时(使用-1.5标志),也会存在@Aspect注解,但它们无法被Spring AOP使用。
org.aspectj.internal.lang.reflect.AjTypeImpl#getPerClause
org.aspectj.lang.annotation.Aspect 是 AspectJ 提供的注解,用于定义切面(Aspect)。它的 value 属性用于指定切面的实例化模式(即切面的生命周期),默认是单例(singleton),但也可以通过特定语法配置其他作用域。
可选值
| 值 | 说明 | 示例 |
|---|
<font style="color:rgb(85, 85, 85);">""</font> (空字符串) | 默认值,表示切面是单例(Singleton)模式,整个应用共享同一个实例。 | <font style="color:rgb(85, 85, 85);">@Aspect("")</font> 或 <font style="color:rgb(85, 85, 85);">@Aspect</font> |
<font style="color:rgb(85, 85, 85);">"perthis(...)"</font> | 为每个匹配切点的目标对象(this)创建一个切面实例。 | <font style="color:rgb(85, 85, 85);">@Aspect("perthis(execution(* com.example.Service.*(..)))")</font> |
<font style="color:rgb(85, 85, 85);">"pertarget(...)"</font> | 为每个匹配切点的被代理对象(target)创建一个切面实例。 | <font style="color:rgb(85, 85, 85);">@Aspect("pertarget(execution(* com.example.Dao.*(..)))")</font> |
<font style="color:rgb(85, 85, 85);">"percflow(...)"</font> | 为每个控制流(例如方法调用栈)创建一个切面实例。 | <font style="color:rgb(85, 85, 85);">@Aspect("percflow(execution(* com.example.Controller.*(..)))")</font> |
<font style="color:rgb(85, 85, 85);">"percflowbelow(...)"</font> | 为每个控制流及子控制流创建一个切面实例。 | <font style="color:rgb(85, 85, 85);">@Aspect("percflowbelow(execution(* com.example.Service.*(..)))")</font> |
ReflectiveAspectJAdvisorFactory#getAdvisors
源码摘录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| // org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
for (Method method : getAdvisorMethods(aspectClass)) {
// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
// to getAdvisor(...) to represent the "current position" in the declared methods list.
// However, since Java 7 the "current position" is not valid since the JDK no longer
// returns declared methods in the order in which they are declared in the source code.
// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
// discovered via reflection in order to support reliable advice ordering across JVM launches.
// Specifically, a value of 0 aligns with the default value used in
// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| // org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory
// 工厂,可以根据遵循 AspectJ 注解语法的 AspectJ 类,通过反射调用相应的通知方法,从而创建 Spring AOP 通知器。
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {
// Exclude @Pointcut methods
private static final MethodFilter adviceMethodFilter = ReflectionUtils.USER_DECLARED_METHODS
.and(method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null));
private static final Comparator<Method> adviceMethodComparator;
static {
// Note: although @After is ordered before @AfterReturning and @AfterThrowing,
// an @After advice method will actually be invoked after @AfterReturning and
// @AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation)
// invokes proceed() in a `try` block and only invokes the @After advice method
// in a corresponding `finally` block.
Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
new InstanceComparator<>(
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
(Converter<Method, Annotation>) method -> {
AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return (ann != null ? ann.getAnnotation() : null);
});
Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator);
}
}
|
流程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
| // org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
--> 获取切面 bean 的 class。
--> 获取切面 bean 的 beanName。
--> 校验切面 bean 的 class。
--|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#validate
--> Aspect 注解校验等,忽略。
--> Spring AOP 不支持 `ajType.getPerClause().getKind()`为`PerClauseKind.PERCFLOW`或`PerClauseKind.PERCFLOWBELOW`。
--> 懒加载包装器。new LazySingletonAspectInstanceFactoryDecorator。
--> 获取切面 bean 的 class 中所有的切面方法,并根据指定规则排序。
--|> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisorMethods
--> 筛选条件:用户自定义方法,且方法未被注解`@Pointcut`修饰(“Exclude @Pointcut methods”)。
--|> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#adviceMethodFilter
--> 注意:此处可能包含无效的切面方法,即切面类中未被任何切面相关注解修饰的方法。
--> 排序规则:首先,注解顺序递增 Around.class,Before.class,After.class,AfterReturning.class,AfterThrowing.class;其次,方法名称顺序。
--|> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#adviceMethodComparator
--> for-each 遍历切面方法,构建 advisor。
--> 构建 advisor。
--|> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisor
--> 校验切面 bean 的 class。
--|> 在前面步骤中已经进行校验。
--|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#validate。
--> 构建`Pointcut`,封装为`AspectJExpressionPointcut`。
--|> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getPointcut
--> 获取方法上的 AspectJ 注解,只取第一个找到的注解(预期方法仅被一个注解修饰),查询顺序为 Pointcut.class,Around.class,Before.class,After.class,AfterReturning.class,AfterThrowing.class。
--|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#findAspectJAnnotationOnMethod
--> 注意,因为在获取 AspectJ 方法时已经排除了注解 @Pointcut,因此此处该注解无效。
--> 封装为`AspectJExpressionPointcut`。`new AspectJExpressionPointcut`。
--> 配置 AspectJExpressionPointcut 的表达式,beanFactory。
--> 如果方法是无效的 AspectJ 方法,则返回 null,并在上层方法中被忽略。
--> 封装为`InstantiationModelAwarePointcutAdvisorImpl`。
--|> `new InstantiationModelAwarePointcutAdvisorImpl`
--|> org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#InstantiationModelAwarePointcutAdvisorImpl
--> 如果具有 lazy 属性(包括 PerClauseKind.PERTHIS,PerClauseKind.PERTARGET,PerClauseKind.PERTYPEWITHIN),进行相关适配,并结束方法。
--> else (即如果是单例类),实例化 advice。
--|> org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#instantiateAdvice
--> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
--> 如果 AspectJ bean 具有 lazy 属性,则添加`SyntheticInstantiationAdvisor` 作为第一个 advisor。
--|> Synthetic advisor that instantiates the aspect. Triggered by per-clause pointcut on non-singleton aspect. The advice has no effect.
--|> 合成通知器,用于实例化切面。当非单例切面上的每个子句切入点被触发时激活。该通知没有实际效果。
--> 获取 AspectJ bean 中的所有字段。
--|> java.lang.Class#getDeclaredFields
--|> This includes public, protected, default (package) access, and private fields, but excludes inherited fields.
--|> 这包括公共、受保护、默认(包级)访问和私有字段,但不包括继承的字段。
--> for-each fields 遍历所有字段,构造引入(接口)字段。
--|> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getDeclareParentsAdvisor
--> 如果字段未被注解`@DeclareParents`修饰,则忽略。该注解修饰1个接口,注解属性标识接口的默认实现类。
--> 封装为`DeclareParentsAdvisor`。`new DeclareParentsAdvisor`。
--|> org.springframework.aop.aspectj.DeclareParentsAdvisor#DeclareParentsAdvisor(java.lang.Class<?>, java.lang.String, java.lang.Class<?>)
--> `new DelegatePerTargetObjectIntroductionInterceptor(defaultImpl, interfaceType))`
--> 以反射调用无参构造方法的方式创建 defaultImpl。
--|> createNewDelegate();
|
引入通知示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| @Aspect
public class IntroductionAspect {
@DeclareParents(value = "tech.gdev.springbasicexplore.aop.springaop.AspectAction+",
defaultImpl = IntroductionServiceImpl.class)
public IntroductionService introductionService;
}
public interface IntroductionService {
void service();
}
public class IntroductionServiceImpl implements IntroductionService {
@Override
public void service() {
System.out.println("[SpringAOP][IntroductionAdvice] IntroductionServiceImpl#service");
}
}
public class AspectExplore {
public static void main(String[] args) throws InterruptedException {
// ...
// 验证引入通知
AspectAction aspectAction = applicationContext.getBean(AspectAction.class);
if (aspectAction instanceof IntroductionService) {
((IntroductionService) aspectAction).service();
} else {
System.out.println("not a IntroductionService");
}
}
}
|
ReflectiveAspectJAdvisorFactory#getAdvice
源码摘录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
| // org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// If we get here, we know we have an AspectJ method.
// Check that it's an AspectJ-annotated class
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// Now to configure the advice...
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
|
流程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| // org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
--> 获取切面 bean 的 class。
--> 校验切面 bean 的 class。在前面步骤中已经进行校验。
--|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#validate。
--> 获取方法上的 AspectJ 注解,只取第一个找到的注解(预期方法仅被一个注解修饰)。
--|> 查询顺序为 Pointcut.class,Around.class,Before.class,After.class,AfterReturning.class,AfterThrowing.class。
--|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#findAspectJAnnotationOnMethod。
--> 如果方法是无效的 AspectJ 方法,则返回 null,并在上层方法中被忽略。
--> 如果非 Spring AOP 切面,则抛出异常。
--|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect
--|> 在之前步骤中已进行过校验,`org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors`
--> 解析方法上的 AspectJ 注解,封装为 Advice。
--|> switch (aspectJAnnotation.getAnnotationType())
--> case AtPointcut: null。忽略 Pointcut 注解。
--> case AtAround: new AspectJAroundAdvice
--> case AtBefore: new AspectJMethodBeforeAdvice
--> case AtAfter: new AspectJAfterAdvice
--> case AtAfterReturning: new AspectJAfterReturningAdvice
--> case AtAfterThrowing: new AspectJAfterThrowingAdvice
--> 配置属性,包括切面 bean name,定义顺序等。
--> 获取切面方法的切面注解属性`argNames`。
--|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.AspectJAnnotationParameterNameDiscoverer#getParameterNames(java.lang.reflect.Method)
--|> When compiling without debug info, or when interpreting pointcuts at runtime, the names of any arguments used in the advice declaration are not available.
--|> Under these circumstances only, it is necessary to provide the arg names in the annotation - these MUST duplicate the names used in the annotated method. Format is a simple comma-separated list.
--|> 在不带调试信息编译,或者在运行时解释切入点时,通知声明中使用的任何参数名称是不可用的。
--|> 在这种情况下,必须在注解中提供参数名称——这些名称必须与注解方法中使用的名称一致。格式是一个简单的逗号分隔列表。
--> for-each 遍历 argNames,trim 后校验是否 Java 标识符规范。
--> 如果切面的方法声明的参数数量大于 argNames,表示使用了内置参数`JoinPoint`或`ProceedingJoinPoint`或`JoinPoint.StaticPart`,进行相关适配。
--> 如果`argNames`不为空,绑定相关参数,略。
--|> org.springframework.aop.aspectj.AbstractAspectJAdvice#setArgumentNamesFromStringArray
--> 绑定参数(通过形参名称映射)。
--|> org.springframework.aop.aspectj.AbstractAspectJAdvice#calculateArgumentBindings
--> 首先尝试绑定第1个参数,如果其是内置参数`JoinPoint`或`ProceedingJoinPoint`或`JoinPoint.StaticPart`。
--> 通过形参名称映射绑定非内置参数。
--|> org.springframework.aop.aspectj.AbstractAspectJAdvice#bindArgumentsByName
--> 待补充。
|
切面方法入参示例
前置通知/后置通知的内置参数是org.aspectj.lang.JoinPoint;环绕通知的内置参数是org.aspectj.lang.ProceedingJoinPoint;被切入点的参数信息都被封装到JoinPoint或ProceedingJoinPoint中。除此之外,允许声明通过切入点表达式(如args()、@annotation()等)显式绑定的参数。
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| @Before("execution(* com.example.service.*.*(..)) && args(name)")
public void logBefore(JoinPoint joinPoint, String name) {
System.out.println("Method: " + joinPoint.getSignature().getName());
System.out.println("Argument: " + name);
}
@Before("@annotation(logExec)")
public void logBefore(JoinPoint jp, LogExec logExec) {
// 这里可以拿到注解的全部属性
System.out.println("[@Before] 方法=" + jp.getSignature().getName()
+ " | 注解value=" + logExec.value());
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExec {
String value() default ""; // 随便定义一个属性,演示用
}
|
END