【Spring 笔记】AOP 通知筛选相关整理
2020-02-12 本文已影响0人
58bc06151329
文前说明
作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。
本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。
1. 概述
- Pointcut(切点)解决了 where 问题,通知(Advice)解决了 when 和 how 问题,Aspect(切面)整合了切点和通知两个模块,从而解决了 何处方法(where)在何时(when 前置、后置、环绕等)执行如何(how)的横切逻辑 的问题。(概念可查看 Spring 笔记】AOP 基础相关整理)
- 织入是在切点的引导下,将通知逻辑插入到方法调用上,使得通知逻辑在方法调用时得以执行。
2. 原理
2.1 AbstractAutoProxyCreator
- Spring 通过 后置处理器 BeanPostProcessor 接口 实现织入过程。
- Spring AOP 抽象代理创建器(
AbstractAutoProxyCreator
)实现了BeanPostProcessor
接口,并在 bean 初始化后置处理过程中向 bean 中织入通知。

// AbstractAutoProxyCreator.java
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
// bean 初始化后置处理方法
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 如果需要,为 bean 生成代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
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;
}
/*
* 1. 如果是基础设施类(Pointcut、Advice、Advisor 等接口的实现类),或是应该跳过的类,
* 则不应该生成代理,此时直接返回 bean
*/
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
// 将 <cacheKey, FALSE> 键值对放入缓存中,供上面的 if 分支使用
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 2. 为目标 bean 查找合适的通知器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
/*
* 3. 若 specificInterceptors != null,即 specificInterceptors != DO_NOT_PROXY,
* 则为 bean 生成代理对象,否则直接返回 bean
*/
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());
/*
* 返回代理对象,此时 IOC 容器输入 bean,得到 proxy。此时,
* beanName 对应的 bean 是代理对象,而非原始的 bean
*/
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
// 4. specificInterceptors = null,直接返回 bean
return bean;
}
}
- 执行步骤。
- 步骤 1,若 bean 是 AOP 基础设施类型,则直接返回。
- 步骤 2,为 bean 查找合适的通知器。
- 步骤 3,如果通知器数组不为空,则为 bean 生成代理对象,并返回该对象。
- 步骤 4,若数组为空,则返回原始 bean。
2.1.1 getAdvicesAndAdvisorsForBean
- 在向目标 bean 中织入通知之前,先要为 bean 筛选出合适的 通知器(通知器持有通知)。
- 筛选的方式很多,可以通过正则表达式匹配方法名,更多时候是使用 AspectJ 表达式 进行匹配。
// AbstractAdvisorAutoProxyCreator.java
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
// 查找合适的通知器
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 2.1 查找所有的通知器
List<Advisor> candidateAdvisors = findCandidateAdvisors();
/*
* 2.2 筛选可应用在 beanClass 上的 Advisor,通过 ClassFilter 和 MethodMatcher
* 对目标类和方法进行匹配
*/
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 2.3 拓展操作
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
- 执行步骤。
- 步骤 2.1,查询出所有的通知器。
- 步骤 2.2,对通知器进行筛选。
- 步骤 2.3,拓展操作。
2.1.1.1 findCandidateAdvisors(查询所有的通知器)
-
Spring 提供了两种配置 AOP 的方式,一种是通过 XML 配置,另一种通过 注解配置。
-
用例 1。
// TestService.java
public interface TestService {
void save(String name);
void update(String name);
void delete(String name);
String findOne(String name);
List<String> findAll();
}
// TestServiceImpl.java
public class TestServiceImpl implements TestService {
public void save(String name) {
}
public void update(String name) {
}
public void delete(String name) {
System.out.println("TestServiceImpl`s delete");
}
public String findOne(String name) {
System.out.println("TestServiceImpl`s findOne");
return "";
}
public List<String> findAll() {
System.out.println("TestServiceImpl`s findAll");
return new ArrayList<String>();
}
}
// AopTest.java
public class AopTest {
public void before() {
System.out.println("AopTest`s before");
}
public void after() {
System.out.println("AopTest`s after");
}
}
// AnnotationAopTest.java
@Aspect
public class AnnotationAopTest {
@Pointcut("execution(* spring.test.aop.*.del*(..))")
public void pointcut() {
}
@Before("pointcut()")
public void before() {
System.out.println("AnnotationAopTest`s before");
}
@After("execution(* spring.test.aop.*.del*(..))")
public void after() {
System.out.println("AnnotationAopTest`s after");
}
}
// Test.java
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
TestService testService = (TestService) context.getBean("testServiceImpl");
testService.findAll();
testService.delete("test");
}
}
/* print
AopTest`s before
TestServiceImpl`s findAll
AopTest`s after
AnnotationAopTest`s before
TestServiceImpl`s delete
AnnotationAopTest`s after
*/
- Spring 配置文件。
<bean id="testServiceImpl" class="spring.test.aop.TestServiceImpl"/>
<aop:aspectj-autoproxy/>
<!-- 普通 bean,包含 AOP 切面逻辑 -->
<bean id="aopTest" class="spring.test.aop.AopTest"/>
<!-- 由 @Aspect 注解修饰的切面类 -->
<bean id="annotationAopTest" class="spring.test.aop.AnnotationAopTest"/>
<aop:config>
<aop:aspect ref="aopTest">
<!-- pointcut -->
<aop:pointcut id="testPointcut" expression="execution(* spring.test.aop.*.find*(..))" />
<!-- advoce -->
<aop:before method="before" pointcut-ref="testPointcut"/>
<aop:after method="after" pointcut-ref="testPointcut"/>
</aop:aspect>
</aop:config>
- 配置文件解析如下。

- 蓝色部分为 切点 的定义,类型为
AspectJExpressionPointcut
。 - 黄色部分为 通知器 的定义,类型为
AspectJPointcutAdvisor
- 红色部分为普通 bean 的定义。
-
AopTest
是 普通 bean 包含 AOP 切面逻辑。 -
AnnotationAopTest
是 由 @Aspect 注解修饰的切面类。- 该 bean 会在查找通知器的过程中被解析,并被构建为一个或多个
Advisor
。
- 该 bean 会在查找通知器的过程中被解析,并被构建为一个或多个
-
-
AnnotationAwareAspectJAutoProxyCreator
覆写了父类方法findCandidateAdvisors()
,增加了解析 @Aspect 注解,并构建成通知器的操作。
// AnnotationAwareAspectJAutoProxyCreator.java
protected List<Advisor> findCandidateAdvisors() {
// 调用父类方法从容器中查找所有的通知器
List<Advisor> advisors = super.findCandidateAdvisors();
// 解析 @Aspect 注解,并构建通知器
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
return advisors;
}
// AbstractAdvisorAutoProxyCreator.java
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
- 由
AnnotationAwareAspectJAutoProxyCreator
的findCandidateAdvisors()
方法调用AbstractAdvisorAutoProxyCreator
的findCandidateAdvisors()
方法,最终调用BeanFactoryAdvisorRetrievalHelper
的findAdvisorBeans()
方法。
// BeanFactoryAdvisorRetrievalHelper.java
public List<Advisor> findAdvisorBeans() {
String[] advisorNames = null;
synchronized (this) {
// cachedAdvisorBeanNames 是 advisor 名称的缓存
advisorNames = this.cachedAdvisorBeanNames;
/*
* 如果 cachedAdvisorBeanNames 为空,这里到容器中查找,
* 并设置缓存,后续直接使用缓存即可
*/
if (advisorNames == null) {
// 2.1.1 从容器中查找 Advisor 类型 bean 的名称
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
// 设置缓存
this.cachedAdvisorBeanNames = advisorNames;
}
}
if (advisorNames.length == 0) {
return new LinkedList<Advisor>();
}
List<Advisor> advisors = new LinkedList<Advisor>();
// 2.1.2 遍历 advisorNames
for (String name : advisorNames) {
if (isEligibleBean(name)) {
// 忽略正在创建中的 advisor bean
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
/*
* 调用 getBean 方法从容器中获取名称为 name 的 bean,
* 并将 bean 添加到 advisors 中
*/
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
- 执行步骤。
-
步骤 2.1.1,从容器中查找所有类型为
Advisor
的 bean 对应的名称。 - 步骤 2.1.2,遍历 advisorNames,并从容器中获取对应的 bean。
-
步骤 2.1.1,从容器中查找所有类型为
- 执行 用例 1,跟踪 <步骤 2.1.1> 获得 advisorNames 值为。

- 执行 用例 1,跟踪 <步骤 2.1.2> 获得 advisors 的值为。

buildAspectJAdvisors
- @Aspect 注解的解析过程。
// BeanFactoryAspectJAdvisorsBuilder.java
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new LinkedList<Advisor>();
aspectNames = new LinkedList<String>();
// 2.1.3 从容器中获取所有 bean 的名称
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 2.1.4 遍历 beanNames
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// 2.1.4 根据 beanName 获取 bean 的类型
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// 2.1.5 检测 beanType 是否包含 Aspect 注解
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);
// 2.1.6 获取通知器
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 {
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 LinkedList<Advisor>();
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;
}
- 执行步骤。
- 步骤 2.1.3,获取容器中所有 bean 的名称(beanName)。
- 步骤 2.1.4,遍历上一步获取到的 bean 名称数组,并获取当前 beanName 对应的 bean 类型(beanType)。
-
步骤 2.1.5,根据 beanType 判断当前 bean 是否是一个的
Aspect
注解类,若不是则不做任何处理。 -
步骤 2.1.6,调用
advisorFactory.getAdvisors()
获取通知器。
- 执行 用例 1,跟踪 <步骤 2.1.5> 获取到符合条件的 bean 为
AnnotationAopTest
。
getAdvisors(注解方式获取通知器过程)
// ReflectiveAspectJAdvisorFactory.java
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 获取 aspectClass 和 aspectName
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new LinkedList<Advisor>();
// getAdvisorMethods 用于返回不包含 @Pointcut 注解的方法
for (Method method : getAdvisorMethods(aspectClass)) {
// 为每个方法分别调用 getAdvisor 方法
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), 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;
}
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;
}
// 创建 Advisor 实现类
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
- 执行步骤。
- 步骤 2.1.7,获取 AspectJ 表达式切点。
-
步骤 2.1.8,创建
Advisor
实现类。
getPointcut
// ReflectiveAspectJAdvisorFactory.java
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 获取方法上的 AspectJ 相关注解,包括 @Before,@After 等
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// 创建一个 AspectJExpressionPointcut 对象
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
// 设置切点表达式
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
ajexp.setBeanFactory(this.beanFactory);
return ajexp;
}
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
Class<?>[] classesToLookFor = new Class<?>[] {
Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
for (Class<?> c : classesToLookFor) {
// 查找注解
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
- 注意,如 用例 1 中
AnnotationAopTest
类中before()
方法。
// AnnotationAopTest.java
@Aspect
public class AnnotationAopTest {
@Pointcut("execution(* spring.test.aop.*.del*(..))")
public void pointcut() {
}
@Before("pointcut()")
public void before() {
System.out.println("AnnotationAopTest`s before");
}
@After("execution(* spring.test.aop.*.del*(..))")
public void after() {
System.out.println("AnnotationAopTest`s after");
}
}
-
@Before 注解中的表达式是
pointcut()
,只是一个中间值,而不是最终值execution(* spring.test.aop.*.del*(..))
,所以后续还会将表达式进行转换。
InstantiationModelAwarePointcutAdvisorImpl
-
Advisor
实现类的创建过程。
// InstantiationModelAwarePointcutAdvisorImpl.java
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
this.declaredPointcut = declaredPointcut;
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 按照注解解析 Advice
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
instantiateAdvice
- 通知器
Advisor
是通知Advice
的持有者,所以在Advisor
实现类的构造方法中创建通知也是合适的。
// InstantiationModelAwarePointcutAdvisorImpl.java
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
}
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
// 获取 Advice 注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
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;
// 按照注解类型生成相应的 Advice 实现类
switch (aspectJAnnotation.getAnnotationType()) {
case AtBefore: // @Before -> AspectJMethodBeforeAdvice
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter: // @After -> AspectJAfterAdvice
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning: // @AfterReturning -> AspectJAfterAdvice
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing: // @AfterThrowing -> AspectJAfterThrowingAdvice
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
case AtAround: // @Around -> AspectJAroundAdvice
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
/*
* 直接返回 null。
*/
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
/*
* 获取方法的参数列表名称,比如方法 int sum(int numX, int numY),
* getParameterNames(sum) 得到 argNames = [numX, numY]
*/
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
// 设置参数名
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
- 主要的逻辑就是根据注解类型生成与之对应的通知对象。
- 总结 <步骤 2.1.6> 注解获取通知器的过程,执行步骤如下。
-
步骤 1,从目标 bean 中获取不包含
Pointcut
注解的方法列表。 -
步骤 2,遍历上一步获取的方法列表,并调用
getAdvisor()
获取当前方法对应的Advisor
。 -
步骤 3,创建
AspectJExpressionPointcut
对象,并从方法的注解中获取表达式,最后设置到切点对象中。 -
步骤 4,创建
Advisor
实现类对象InstantiationModelAwarePointcutAdvisorImpl
。 -
步骤 5,调用
instantiateAdvice()
方法构建通知。 -
步骤 6,调用
getAdvice()
方法,并根据注解类型创建相应的通知。
-
步骤 1,从目标 bean 中获取不包含
- 不同的注解类型会创建不同的通知,以
AspectJMethodBeforeAdvice
为例,其他注解类似。
AspectJMethodBeforeAdvice
// AspectJMethodBeforeAdvice.java
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice {
public AspectJMethodBeforeAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJBeforeAdviceMethod, pointcut, aif);
}
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
// 调用通知方法
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
@Override
public boolean isBeforeAdvice() {
return true;
}
@Override
public boolean isAfterAdvice() {
return false;
}
}
protected Object invokeAdviceMethod(JoinPointMatch jpMatch, Object returnValue, Throwable ex) throws Throwable {
// 调用通知方法,并向其传递参数
return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterTypes().length == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// 通过反射调用通知方法
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
2.1.1.2 findAdvisorsThatCanApply(对通知器进行筛选)
// AbstractAdvisorAutoProxyCreator.java
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
// 调用重载方法
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
// AopUtils.java
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
for (Advisor candidate : candidateAdvisors) {
// 筛选 IntroductionAdvisor 类型的通知器
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
continue;
}
// 筛选普通类型的通知器
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
// AopUtils.java
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
/*
* 从通知器中获取类型过滤器 ClassFilter,并调用 matchers 方法进行匹配。
* ClassFilter 接口的实现类 AspectJExpressionPointcut 为例,该类的
* 匹配工作由 AspectJ 表达式解析器负责。
*/
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
// 对于普通类型的通知器,这里继续调用重载方法进行筛选
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
return true;
}
}
// AopUtils.java
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
// 使用 ClassFilter 匹配 class
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
/*
* 查找当前类及其父类(以及父类的父类等等)所实现的接口,由于接口中的方法是 public,
* 所以当前类可以继承其父类,和父类的父类中所有的接口方法
*/
Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for (Class<?> clazz : classes) {
// 获取当前类的方法列表,包括从父类中继承的方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
// 使用 methodMatcher 匹配方法,匹配成功即可立即返回
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
- 筛选的工作主要由
ClassFilter
和MethodMatcher
完成。(可以查看 【Spring 笔记】AOP 基础相关整理 了解)
2.1.1.3 extendAdvisors(拓展操作)
// AbstractAdvisorAutoProxyCreator.java
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
// AspectJAwareAdvisorAutoProxyCreator.java
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// 如果通知器列表是一个空列表,则什么都不做
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
/*
* 下面的 for 循环用于检测 advisors 列表中是否存在
* AspectJ 类型的 Advisor 或 Advice
*/
for (Advisor advisor : advisors) {
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
}
}
/*
* 向 advisors 列表的首部添加 DefaultPointcutAdvisor
*/
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
// 向通知器列表中添加 ExposeInvocationInterceptor.ADVISOR
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}
// AspectJProxyUtils.java
private static boolean isAspectJAdvice(Advisor advisor) {
return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
advisor.getAdvice() instanceof AbstractAspectJAdvice ||
(advisor instanceof PointcutAdvisor &&
((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
}
- 上述操作主要的目的是向通知器列表首部添加
DefaultPointcutAdvisor
类型的通知器,也就是ExposeInvocationInterceptor.ADVISOR
。
ExposeInvocationInterceptor
- 拦截器相关可以查看 【Spring 笔记】AOP 拦截器链相关整理 了解。
// ExposeInvocationInterceptor.java
public class ExposeInvocationInterceptor implements MethodInterceptor, PriorityOrdered, Serializable {
public static final ExposeInvocationInterceptor INSTANCE = new ExposeInvocationInterceptor();
// 创建 DefaultPointcutAdvisor 匿名对象
public static final Advisor ADVISOR = new DefaultPointcutAdvisor(INSTANCE) {
@Override
public String toString() {
return ExposeInvocationInterceptor.class.getName() +".ADVISOR";
}
};
private static final ThreadLocal<MethodInvocation> invocation =
new NamedThreadLocal<MethodInvocation>("Current AOP method invocation");
public static MethodInvocation currentInvocation() throws IllegalStateException {
MethodInvocation mi = invocation.get();
if (mi == null)
throw new IllegalStateException(
"No MethodInvocation found: Check that an AOP invocation is in progress, and that the " +
"ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that " +
"advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!");
return mi;
}
// 私有构造方法
private ExposeInvocationInterceptor() {
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
// 将 mi 设置到 ThreadLocal 中
invocation.set(mi);
try {
// 调用下一个拦截器
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
//...
}
-
ExposeInvocationInterceptor.ADVISOR
经过registry.getInterceptors()
方法处理后,即可得到ExposeInvocationInterceptor
。 -
ExposeInvocationInterceptor
的作用是用于暴露MethodInvocation
对象到ThreadLocal
中。 - 如果其他地方需要当前的
MethodInvocation
对象,直接通过调用currentInvocation
方法取出。
- Spring 为目标 bean 筛选到合适的通知器,再通过 创建代理对象 的方式将 Advisor(通知器)所持有的 Advice(通知)织入到 bean 的某些方法前后。