文章目录


1、Spring AOP

(1)Spring AOP 概念

Spring AOP 默认为 AOP 代理使用标准 JDK 动态代理。这允许代理任何接口(或一组接口)

Spring AOP 也可以使用 CGLIB 代理。这对于代理类而不是接口是必要的。默认情况下,如果业务对象没有实现接口,则使用 CGLIB。由于使用接口而不是类编程是一种很好的实践,因此业务类通常实现一个或多个业务接口。在需要通知接口上没有声明的方法,或者需要将代理对象作为具体类型传递给方法的情况下(希望很少),可以强制使用 CGLIB

Spring 的关键组件之一是 AOP 框架。虽然 Spring IoC 容器不依赖于 AOP(这意味着如果您不想使用 AOP,就不需要使用 AOP),但 AOP 对 Spring IoC 进行了补充,提供了一个非常强大的中间件解决方案。下面列举了 aop 的核心属于,这些术语并不是 spring 特有的,spring 也有自己的术语,但是很反人类。​​spring aop 官方文档​

aop 的主要作用是:能在程序运行期间动态的将某段代码片段切入到指定的方法指定位置进行运行的编程方式

(2)Spring AOP 术语

名称

说明

通知(Advice)

就是你想要的功能,也就是上面说的 安全,事物,日志等。你给先定义好把,然后在想用的地方用一下

连接点(JoinPoint)

这个更好解释了,就是 spring 允许你使用通知的地方,那可真就多了,基本每个方法的前,后(两者都有也行),或抛出异常时都可以是连接点,spring 只支持方法连接点.其他如 aspectJ 还可以让你在构造器或属性注入时都行,不过那不是咱关注的,只要记住,和方法有关的前前后后(抛出异常),都是连接点

切入点(Pointcut)

上面说的连接点的基础上,来定义切入点,你的一个类里,有 15 个方法,那就有几十个连接点了对把,但是你并不想在所有方法附近都使用通知(使用叫织入,以后再说),你只想让其中的几个,在调用这几个方法之前,之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法

切面(Aspect)

切面是通知和切入点的结合。现在发现了吧,没连接点什么事情,连接点就是为了让你好理解切点,搞出来的,明白这个概念就行了。通知说明了干什么和什么时候干(什么时候通过方法名中的 before,after,around 等就能知道),而切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义

引入(introduction)

允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗

目标(target)

引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咱们织入切面。而自己专注于业务本身的逻辑

代理(proxy)

怎么实现整套 aop 机制的,都是通过代理,这个一会给细说

织入(weaving)

把切面应用到目标对象来创建新的代理对象的过程。有 3 种方式,spring 采用的是运行时,为什么是运行时,后面解释


切点定义了哪些连接点会得到通知


(3)Spring AOP 通知类型

对应注解

通知类型

作用时机

@Before

运行之前通知

在连接点之前运行但不能阻止执行流继续到连接点的通知(除非它抛出异常)

@After

运行之后通知

通知将在连接点正常完成后运行(例如,如果方法返回时没有抛出异常)

@AfterReturning

通知之后(最后)

无论连接点以何种方式退出(正常或异常返回),都要运行的通知

@AfterThrowing

抛出异常通知

如果方法通过抛出异常而退出,则将运行通知

@Around

环绕通知

围绕连接点(如方法调用)的通知。Around 通知可以在方法调用之前和之后执行自定义行为。它还负责选择是继续到连接点,还是通过返回自己的返回值或抛出异常来简化建议的方法的执行

2、Spring AOP 功能测试

aop 测试代码也是比较简单的, 定义一个配置类 AppConfig,然后定义一个 MathService 的 bean,其中写一个计算的方法, 再定义一个切面类和测试类即可,核心主要是在业务逻辑调用前后以及异常时进行自定义逻辑处理,相关依赖为​​spring-aspects​

配置类:开启 aop 代理

package cn.tellsea.aop;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
* @author Tellsea
* @date 2020-9-9
*/
@ComponentScan("cn.tellsea.aop")
@EnableAspectJAutoProxy
public class AppConfig {
}

MathService:模拟业务逻辑

package cn.tellsea.aop;

import org.springframework.stereotype.Component;

/**
* @author Tellsea
* @date 2020-9-9
*/
@Component
public class MathService {

public int calculation(int a, int b) {
return a / b;
}
}

切面类

package cn.tellsea.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
* 定义切面
*
* @author Tellsea
* @date 2020-9-9
*/
@Aspect
@Component
public class AppAspects {

// 定义切入点
@Pointcut("execution(* cn.tellsea.aop.MathService.*(..))")
public void pointCut() {
}

@Before("pointCut()")
public void before(JoinPoint joinPoint) {
System.out.println("运行之前通知 ...");
}

@After("pointCut()")
public void after(JoinPoint joinPoint) {
System.out.println("运行之后通知 ...");
}

@AfterReturning(value = "pointCut()", returning = "result")
public void afterReturning(Object result) {
System.out.println("通知之后(最后) ...");
}

@AfterThrowing(value = "pointCut()", throwing = "exception")
public void afterThrowing(JoinPoint joinPoint, Exception exception) {
System.out.println("抛出异常通知 ...");
}
}

测试类

package cn.tellsea.aop;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
* @author Tellsea
* @date 2020-9-9
*/
public class AppTest {

public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MathService mathService = applicationContext.getBean(MathService.class);
Integer result = mathService.calculation(100, 100);
System.out.println(result);
}
}

测试结果

运行之前通知 ...
通知之后(最后) ...
运行之后通知 ...
1

将被除数改为 0 之后,模拟业务抛出异常

运行之前通知 ...
抛出异常通知 ...
运行之后通知 ...
Exception in thread "main" java.lang.ArithmeticException: / by zero
at cn.tellsea.aop.MathService.calculation(MathService.java:13)
at cn.tellsea.aop.MathService$$FastClassBySpringCGLIB$$daebdd0e.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:55)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:47)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
at cn.tellsea.aop.MathService$$EnhancerBySpringCGLIB$$f551641a.calculation(<generated>)
at cn.tellsea.aop.AppTest.main(AppTest.java:14)

3、Spring AOP 原理

通过上面的示例会发现,有​​@EnableAspectJAutoProxy​​​则可以使用 aop,没有则不能使用,那么我们从​​@EnableAspectJAutoProxy​​开始分析 aop 原理

(1)@EnableAspectJAutoProxy 分析

EnableAspectJAutoProxy 源码没有什么内容,需要注意的是​​@Import(AspectJAutoProxyRegistrar.class)​​​这句代码,前面我们在​​【spring 组件注册】​​中说过,@Import 为给 spring 快速导入一个组件

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

/**
* 是否强制使用CGLIB代理,默认jdk代理
* 指示是否创建基于子类的(CGLIB)代理到标准的基于Java接口的代理。默认值是{@code false}。
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
boolean proxyTargetClass() default false;

/**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
boolean exposeProxy() default false;

}

那么继续查看@Import 导入的 AspectJAutoProxyRegistrar 类干了什么

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}

}

@Import 给容器中导入 AspectJAutoProxyRegistrar,利用 AspectJAutoProxyRegistrar 自定义给容器中注册 bean,只是注册的是 BeanDefinetion,定义的类型是 internalAutoProxyCreator,定义的信息是​​AnnotationAwareAspectJAutoProxyCreator​​​, 最终的作用就是给容器中注册了一个​​AnnotationAwareAspectJAutoProxyCreator​​​组件,也就是说,搞懂了​​AnnotationAwareAspectJAutoProxyCreator​​组件干了什么事,那么 aop 的原理就分析出来了,相关继承关系如下

(2)AnnotationAwareAspectJAutoProxyCreator 分析

【Spring源码分析】9、Spring AOP 案例学习、原理分析、源码分析_spring

我们核心重点主要走的流程是以下步骤,主要关注后置处理器做了些什么事情,因为它是在在 bean 初始化完成前后做事情

AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator
AspectJAwareAdvisorAutoProxyCreator
AbstractAdvisorAutoProxyCreator
AbstractAutoProxyCreator
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware

简单的分析了相关继承关系后,下面的常规流程就是注册​​AnnotationAwareAspectJAutoProxyCreator​​组件了

首先,启动测试类,创建 IOC 容器,调用 refresh()刷新容器,这里重点关注刷新容器的​​registerBeanPostProcessors(beanFactory)​​方法,因为后置处理器的注册是在这个方法中完成的,该方法主要作用是注册 bean 的后置处理器来方便拦截 bean 的创建,下面分析相关源码,在 PostProcessorRegistrationDelegate 类中

public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

// 注册BeanPostProcessorChecker,该日志将在以下情况下记录信息消息
// 在BeanPostProcessor实例化期间,即当
// 一个bean不适合所有BeanPostProcessor处理。
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

// 将实现PriorityOrdered的BeanPostProcessor之间分开,
// 排序和其他的
// 优先选择的后置处理器
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
// 内部的后置处理器
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
// 排序名称
List<String> orderedPostProcessorNames = new ArrayList<>();
// 没有排序名称
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}

// 首先,注册实现PriorityOrdered的BeanPostProcessor。
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

// 接下来,注册实现Ordered的BeanPostProcessor。
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);

// 现在,注册所有常规BeanPostProcessor。
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

// 最后,重新注册所有内部BeanPostProcessor。
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);

// 重新注册用于将内部bean检测为ApplicationListener的后处理器,
// 将其移动到处理器链的末尾(用于拾取代理等)。
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

上面的源码注释说明的很详细,现在简单说一下主要干了些什么事,实际上,相关的代码主要分成两部分,第一个是 BeanPostProcessor 接口的处理,另一部分是 bean 的创建过程,可以参照一下两篇文章更进一步深入学习,我们这类主要探讨 aop 的核心相关处理

1)、先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor
2)、给容器中加别的BeanPostProcessor
3)、优先注册实现了PriorityOrdered接口的BeanPostProcessor;
4)、再给容器中注册实现了Ordered接口的BeanPostProcessor;
5)、注册没实现优先级接口的BeanPostProcessor;
6)、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;
创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
1)、创建Bean的实例
2)、populateBean;给bean的各种属性赋值
3)、initializeBean:初始化bean;
1)、invokeAwareMethods():处理Aware接口的方法回调
2)、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
3)、invokeInitMethods();执行自定义的初始化方法
4)、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();
4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--》aspectJAdvisorsBuilder
7)、把BeanPostProcessor注册到BeanFactory中;
beanFactory.addBeanPostProcessor(postProcessor);

走完以上步骤,相当于我们创建和注册​​AnnotationAwareAspectJAutoProxyCreator​​到 spring 容器中

AnnotationAwareAspectJAutoProxyCreator 实现了 InstantiationAwareBeanPostProcessor,通过继承关系,在 AbstractAutoProxyCreator 类中找到重写的 postProcessBeforeInstantiation()方法,我们主要关心自定义的 mathService 和 appAspects 的创建,debug 增加条件:beanName.equals(“mathService”) || beanName.equals(“appAspects”)

【Spring源码分析】9、Spring AOP 案例学习、原理分析、源码分析_java_02

当前执行的 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;
}
}

1、首先判断当前 beanName 是否在 advisedBeans 中,advisedBeans 保存了所有需要增强的 bean

2、然后判断当前 bean 是否是基础类型的 Advice.class、Pointcut.class、Advisor.class、AopInfrastructureBean.class 或者是否切面@Aspects

3、shouldSkip() 是否需要跳过,实际判断的是是否原始实例,这里是避免循环依赖问题

(3)创建 AOP 代理分析

然后继续执行 AbstractAutoProxyCreator.postProcessAfterInitialization()源码,如果 bean 被子类识别为要代理的,那么创建一个带有配置拦截器的代理

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

其中调用了 wrapIfNecessary()方法,方法中主要做的事是满足条件, 则创建代理

/**
* 如有必要,包装给定的bean,即如果它符合代理的条件
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
* @param bean the raw bean instance
* @param beanName the name of the bean
* @param cacheKey the cache key for metadata access
* @return a proxy wrapping the bean, or the raw bean instance as-is
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && 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;
}

// 创建代理,如果我们有advice
// Create proxy if we have advice.
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;
}

上面的代码中,继续逐步分析,首先首先找到当前 bean 的所有增强器(通知方法)

// 首先找到当前bean的所有增强器(通知方法)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

getAdvicesAndAdvisorsForBean()是 AbstractAutoProxyCreator 接口的方法, Ctrl + alt + b 然后进入实现类​​AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean()​​方法,又调用了 findEligibleAdvisors()方法

/**
* 找到自动代理的通知方法
* Find all eligible Advisors for auto-proxying this class.
* @param beanClass the clazz to find advisors for
* @param beanName the name of the currently proxied bean
* @return the empty List, not {@code null},
* if there are no pointcuts or interceptors
* @see #findCandidateAdvisors
* @see #sortAdvisors
* @see #extendAdvisors
*/
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的)
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 获取到能在bean使用的增强器
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
// 给增强器排序
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}

然后回到 wrapIfNecessary()方法中,如果当前 bean 需要代理,则将找到的通知方法,保存在当前 bean 在 advisedBeans 中,并将当前代理对象,存放在 proxyTypes 中

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;
}

继续分析​​createProxy()​​方法的执行,源码

/**
* 为给定的bean创建一个AOP代理
* Create an AOP proxy for the given bean.
* @param beanClass the class of the bean
* @param beanName the name of the bean
* @param specificInterceptors the set of interceptors that is
* specific to this bean (may be empty, but not null)
* @param targetSource the TargetSource for the proxy,
* already pre-configured to access the bean
* @return the AOP proxy for the bean
* @see #buildAdvisors
*/
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {

if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}

// 代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);

if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 获取所有增强器(通知方法)
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
// 定制代理工厂
customizeProxyFactory(proxyFactory);

proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}

return proxyFactory.getProxy(getProxyClassLoader());
}

然后调用​​getProxy()​​方法

/**
* 根据这个工厂的设置创建一个新的代理
* Create a new proxy according to the settings in this factory.
* <p>Can be called repeatedly. Effect will vary if we've added
* or removed interfaces. Can add and remove interceptors.
* <p>Uses the given class loader (if necessary for proxy creation).
* @param classLoader the class loader to create the proxy with
* (or {@code null} for the low-level proxy facility's default)
* @return the proxy object
*/
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}

继续调用​​createAopProxy()​​方法,在 ProxyCreatorSupport 类中

/**
* 子类应该调用它来获得一个新的AOP代理,他们不应该用this作为参数创建一个AOP代理
* Subclasses should call this to get a new AOP proxy. They should <b>not</b>
* create an AOP proxy with {@code this} as an argument.
*/
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}

继续调用​​createAopProxy(this)​​方法,是 AopProxyFactory 接口的方法, Ctrl + alt + B 进入实现类,来到 DefaultAopProxyFactory 中

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}

到这里我们发现有两种代理对象的创建方式,JdkDynamicAopProxy(config)和 ObjenesisCglibAopProxy(config),这里是 spring 自动决定的动态代理,也可以强制使用 cglib 代理,到这里我们可以发现,当前的 mathService 对象已经被代理了

最终给容器中返回了 cglib 代理了的对象,以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程

【Spring源码分析】9、Spring AOP 案例学习、原理分析、源码分析_java_03

(4)AOP 获取拦截器链分析

现在,我们获得的 bean 实际上已经是经过 cglib 增强了的,所以容器中保存的是代理对象,在测试中打一个断点,发现当前的 mathService 中,不仅是 cglib 增强了,其中 advisorArray 中还存放了所有的通知方法

【Spring源码分析】9、Spring AOP 案例学习、原理分析、源码分析_动态代理_04

当调用计算方法的时候,debug 进入方法调用底层,idea 是 F5(Step Into),进入了​​CglibAopProxy.intercept()​​方法, 实际作用是拦截目标方法的执行,是一个拦截器

@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// 在必要时使调用可用
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 尽可能晚到,以减少我们“拥有”目标的时间,以防它来自一个池
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
//根据ProxyFactory对象获取将要执行的目标方法拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
//检查我们是否只有一个InvokerInterceptor:
//没有真正的advice,只是对目标的反射调用。
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
//如果没有拦截器链,直接执行目标方法;
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
// 如果有拦截器链,把需要执行的目标对象,目标方法
// 拦截器链等信息传入创建一个 CglibMethodInvocation 对象,并调用 Object retVal = mi.proceed();
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

重点分析怎么获取拦截器,也就是上面的代码

//根据ProxyFactory对象获取将要执行的目标方法拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

进入​​getInterceptorsAndDynamicInterceptionAdvice()​​方法中,

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}

然后再进入​​getInterceptorsAndDynamicInterceptionAdvice()​​方法,是 AdvisorChainFactory 接口的方法,进入实现类,在 DefaultAdvisorChainFactory 类中

@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {

// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
// 需要保持最终列表的顺序
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors();
// 长度5: 一个默认的ExposeInvocationInterceptor 和 4个增强器
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;

//遍历所有的增强器,将其转为Interceptor
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
if (match) {
//将增强器转为MethodInterceptor
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}

return interceptorList;
}

将增强器转为 MethodInterceptor 调用了​​registry.getInterceptors(advisor)​​方法, 这里简单分析一下,它是 AdvisorAdapterRegistry 接口的方法,实现类在 DefaultAdvisorAdapterRegistry 类中

@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
// 如果是MethodInterceptor,直接加入到集合中
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// 如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor(适配器模式)
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
// 转换完成返回MethodInterceptor数组
return interceptors.toArray(new MethodInterceptor[0]);
}

(5)AOP 链式调用通知分析

前面我们拿到了拦截器链,查看源码可知,继续调用了​​proceed()​​,这个方法实际上就是拦截器链的触发过程,它是一个递归方法

@Override
@Nullable
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}

Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}

1、如果没有拦截器执行目标方法,或者拦截器的索引和拦截器数组-1 大小一样(指定到了最后一个拦截器)执行目标方法

2、链式获取每一个拦截器,拦截器执行 invoke 方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行


拦截器链的机制,保证通知方法与目标方法的执行顺序


4、更多细节学习

技术分享区

【Spring源码分析】9、Spring AOP 案例学习、原理分析、源码分析_aop_05