一. 前置知识

1 动态代理

1.1 JDK动态代理

基于接口的动态代理机制。它允许在运行时动态创建实现接口的代理类,并通过代理类来控制对目标对象的访问

核心在于代理类会将所有方法调用转发给 InvocationHandler.invoke 方法,从而可以在方法调用前后插入自定义逻辑。

核心组件

  1. InvocationHandler 接口:用来定义代理对象的方法拦截逻辑。

    • ava.lang.reflect.InvocationHandler 用于定义方法调用的具体处理逻辑

    • invoke 方法

1
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
1
2
3
- proxy : 代理对象
- method:被调用的真实方法
- args: 方法参数
  1. Proxy 类:用来生成动态代理类。
  • java.lang.reflect.Proxy 生成动态代理类和实例的静态方法

  • newProxyInstance 方法

1
static Object newProxyInstance(ClassLoader loader, Class<?>[] 
1
2
3
- loader:类加载器,通常是目标类的类加载器
- interfaces: 被代理对象(目标对象)实现的接口数组
- h: InvocationHandler 实例

使用示例

示例一 添加用户

  1. 定义接口
1
2
3
public interface UserService {
String addUser();
}
  1. 实现类
1
2
3
4
5
6
7
class UserServiceImpl implements UserService {
@Override
public String addUser() {
System.out.println("adduser running...");
return "adduser successfully";
}
}
  1. 代理拦截逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class UserServiceProxy implements InvocationHandler {
private final Object target;

public UserServiceProxy(Object target) {
this.target = target;
}


@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before addUser");
Object invoke = method.invoke(target, args);
System.out.println("after addUser");
return invoke;
}
}
  1. 测试
1
2
3
4
5
6
7
class UserServiceProxyTest {
public static void main(String[] args) {
UserService target = new UserServiceImpl();
UserService userService = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]{UserService.class}, new UserServiceProxy(target));
System.out.println(userService.addUser());
}
}

输出

1
2
3
4
before addUser
adduser running...
after addUser
adduser successfully

示例二 Mybatis Mapper接口代理

以UserMapper为例

  1. 接口
1
2
3
public interface UserMapper {
User getUserById(String id);
}
  1. 代理工厂
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MapperProxyFactory {

//在实际开发中时动态的
private final Class<?> mapperInterface = UserMapper.class;


protected UserMapper newInstance(MapperProxy mapperProxy) {
return (UserMapper) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

//创建代理对象
public UserMapper newInstance() {
final MapperProxy mapperProxy = new MapperProxy(mapperInterface);
return newInstance(mapperProxy);
}
}
  1. 代理逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class MapperProxy implements InvocationHandler {
private final Class<?> mapperInterface;
//private final SqlSession sqlSession;
//private final Map<Method, MapperMethod> methodCache;

public MapperProxy(Class<?> mapperInterface) {
this.mapperInterface = mapperInterface;
//this.sqlSession = sqlSession;

}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行代理方法");
//利用sqlSession查询数据库返回结果 user
return user
}
}
  1. 测试
1
2
3
4
5
6
7
8
public class Test {
public static void main(String[] args) {
MapperProxyFactory mapperProxyFactory = new MapperProxyFactory();
UserMapper userMapper = mapperProxyFactory.newInstance();
User userById = userMapper.getUserById("1");
System.out.println(userById);
}
}

1.2 CGLIB动态代理

1.用来代理 没有实现接口的类。

2.CGLIB 动态代理基于字节码操作,通过继承目标类并重写其方法的方式实现代理。代理类在运行时生成,实际调用时会将方法调用委托给 MethodInterceptor

核心组件

  1. Enhancer

    • net.sf.cglib.proxy.Enhancer 核心类用来生成代理对象
    • 配置被代理类及拦截器后,调用 create() 方法生成代理对象
  2. MethodInterceptor

    • net.sf.cglib.proxy.MethodInterceptor 核心接口用来实现方法拦截逻辑

    • 方法签名 intercept

1
Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable;
 - obj: 代理对象
 - method: 被调用的真实方法
 - args : 方法参数
 - proxy : 用于调用目标类方法的 `MethodProxy` 对象。 由CGLIB生成,提供了对目标方法的直接访问,可以避免反射带来的性能损耗。

使用示例

示例 以添加用户为例

  1. 定义目标类(需要代理的类)
1
2
3
4
5
public class UserService {
public void addUser(String name) {
System.out.println("Adding user: " + name);
}
}
  1. 创建MethodInterceptor(方法拦截器)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class UserServiceMethodInterceptor implements MethodInterceptor {

private final Object target;


public UserServiceMethodInterceptor(Object target) {
this.target = target;
}


@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = methodProxy.invoke(target, objects);
System.out.println("After method: " + method.getName());
return result;
}
}
  1. 使用 Enhancer 创建代理对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class CGLIBProxyExample {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//创建代理对象
Enhancer enhancer = new Enhancer();
//需要代理的类
UserService target = new UserService();
//设置需要代理的类
enhancer.setSuperclass(target.getClass());
//设置回调函数
enhancer.setCallback(new UserServiceMethodInterceptor(target));
//创建代理对象
UserService proxy = (UserService) enhancer.create();
Method method = target.getClass().getMethod("addUser", String.class);
String result = (String) method.invoke(proxy, "Alice");
System.out.println(result);
//或者下面这种调用方式
// String result = proxy.addUser("Alice");
// System.out.println(result);
}
}

输出

1
2
3
4
Before method: addUser
Adding user running: Alice
After method: addUser
addUser success

CGLIB单独使用需要引入相关依赖

1
2
3
4
5
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>

1.3 CGLIB 动态代理与 JDK 动态代理对比

特性 CGLIB 动态代理 JDK 动态代理
代理目标 任何类(不需要实现接口) 必须实现接口
原理 字节码生成(基于 ASM) 反射机制
性能 较高(直接操作字节码) 较低(通过反射调用)
final 限制 无法代理 final 类或方法 无限制

性能对比

  1. CGLIB 性能优于 JDK 动态代理
    • JDK 动态代理依赖反射调用,性能较低。
    • CGLIB 直接生成字节码,调用开销小。
  2. 但生成代理类时间较长
    • CGLIB 在第一次创建代理对象时,需要生成代理类字节码,消耗时间较多。

2 Spring ProxyFactory

简化了代理对象的创建过程,并集成了 Spring 的 AOP 功能。利用 ProxyFactory 可以更方便地创建动态代理,同时享受 Spring 提供的更多功能。

使用示例

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

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import java.lang.reflect.Method;
public interface UserService {
void addUser(String name);
}

// 实现接口的目标类
class UserServiceImpl implements UserService {
@Override
public void addUser(String name) {
System.out.println("Adding user: " + name);
}
}


class BeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("Before method: " + method.getName());
}
}

class ProxyFactoryExample{
public static void main(String[] args) {
// 创建目标对象
UserService target = new UserServiceImpl();
// 创建 ProxyFactory 并设置目标
ProxyFactory proxyFactory = new ProxyFactory();
// 设置目标对象
proxyFactory.setTarget(target);
// 设置接口,如果没有设置会采用cglib代理
proxyFactory.setInterfaces(UserService.class);
// 添加通知
proxyFactory.addAdvice(new BeforeAdvice());
// 设置启用优化后会采用cglib代理
// proxyFactory.setOptimize(true);
// 设置为不透明
// proxyFactory.setOpaque(true);
// 暴露代理
proxyFactory.setExposeProxy(true);
// 设置冻结
proxyFactory.setFrozen(true);
// 设置为true, 会采用cglib代理
// proxyFactory.setProxyTargetClass(true);
// 获取代理对象
UserService proxy = (UserService) proxyFactory.getProxy();
// 调用方法
proxy.addUser("Alice");
// 设置冻结后试修改代理配置(将抛出异常)
// try {
// proxyFactory.addAdvice(new BeforeAdvice());
// } catch (Exception e) {
// System.out.println("Cannot modify proxy configuration");
// }
//boolean b = proxy instanceof Advised;//设置不透明后将返回false
System.out.println(b);
// Object o = AopContext.currentProxy();
// System.out.println(o);
}
}

Spring Aop主要时通过这个类创建代理对象 ,在创建对象时会根据传入的目标类或者接口决定使用哪种动态代理

如果是CGLB 会使用 CglibAopProxy 创建代理对象

image-20241209013917029

如果是JDK 会使用 JdkDynamicAopProxy 创建代理对象 继承关系图

image-20241209013820075

两者都实现了AopProxy

1
2
3
4
5
6
7
8
9
10
public interface AopProxy {

//创建代理对象
Object getProxy();

//创建代理对象
Object getProxy(@Nullable ClassLoader classLoader);

}

在 Spring 框架中,面向切面编程(AOP) 通过 @Aspect 注解来定义切面(Aspect),以实现横切关注点(如日志记录、事务管理、权限校验等)的模块化。@Aspect AOP 的实现贯穿于 Spring 容器的生命周期中,主要依赖于 Bean 后处理器(BeanPostProcessor)代理机制。本文将详细介绍 @Aspect AOP 在 Spring 生命周期中的具体实现位置及其工作原理。


二. Spring AOP 概述

面向切面编程(AOP) 允许开发者将横切关注点(Cross-Cutting Concerns)从业务逻辑中分离出来,以提高代码的模块化和可维护性。Spring AOP 提供了基于代理的 AOP 实现,支持使用 @Aspect 注解定义切面。

1. 主要概念

  • 切面(Aspect):模块化的横切关注点,例如日志记录、事务管理。
  • 连接点(Join Point):程序执行的特定点,如方法调用。
  • 通知(Advice):在连接点执行的动作,如前置通知、后置通知。
  • 切点(Pointcut):定义通知应用的连接点。
  • 织入(Weaving):将切面应用到目标对象的过程,通常通过代理实现。

2. Spring 容器生命周期简介

Spring 容器的生命周期主要包括以下几个阶段:

  1. 加载 Bean 定义:解析配置文件或注解,加载 Bean 的定义信息。
  2. 实例化 Bean:创建 Bean 的实例。
  3. 填充 Bean 属性:注入依赖(依赖注入)。
  4. 初始化 Bean:调用初始化方法(如 @PostConstruct 注解的方法)。
  5. 使用 Bean:应用程序使用 Bean。
  6. 销毁 Bean:容器关闭时,销毁 Bean。

其中在实例化,初始化过程中都可以**应用 Bean 后处理器(BeanPostProcessor)**:对 Bean 进行进一步处理,如代理创建(初始化后前)。

3. 工作流程

以下是 @Aspect AOP 在 Spring 容器生命周期中的详细工作流程:

  1. 扫描与注册切面

    • Spring 扫描到被 @Aspect 注解标记的类,并将其注册为切面 Bean。
  2. 实例化切面 Bean

    • Spring 创建切面类的实例,并注入其依赖。
  3. **应用 AnnotationAwareAspectJAutoProxyCreator**:

    • 作为一个 BeanPostProcessor,AnnotationAwareAspectJAutoProxyCreator 会在目标 Bean 创建后检查是否需要为其创建代理。
  4. 解析切点与通知

    • AnnotationAwareAspectJAutoProxyCreator 解析切面的切点表达式,确定哪些目标 Bean 的哪些方法需要被拦截。
  5. 创建代理对象

    • 对于符合条件的目标 Bean,ProxyFactory 会创建代理对象,并将通知(Advice)织入其中。
    • 选择代理方式:
      • JDK 动态代理:如果目标 Bean 实现了至少一个接口,默认使用 JDK 动态代理。
      • CGLIB 代理:如果目标 Bean 没有实现接口,或者强制要求使用 CGLIB 代理,则使用 CGLIB。
  6. 初始化与使用

    • 代理对象完成后,Spring 继续完成 Bean 的初始化过程。
    • 应用程序在使用 Bean 时,实际上操作的是代理对象,从而实现了 AOP 织入的功能。

4. 流程原理解析

4.1. Advisor接口

Advisor 是一个结合了 Pointcut(切入点)Advice(通知) 的对象。它定义了特定的切入点以及在这些切入点上执行的具体通知逻辑。通过 Advisor,AOP 框架能够在运行时动态地将横切关注点应用到目标对象的合适位置。

4.2. AnnotationAwareAspectJAutoProxyCreator

image-20241209020339630

这是 Spring AOP 的核心组件之一 ,Bean后置处理器,负责自动创建代理对象。其主要职责包括:

  • 扫描解析切面类:识别被 @Aspect 注解标记的类。 ——- 实例化前阶段
  • 解析切点表达式:通过 @Pointcut 或切点表达式,定义哪些方法会被切面通知所拦截。
  • 创建代理:为符合切点条件的 Bean 创建代理对象,并将通知织入其中。 ——— 初始化后阶段

4.2.1. 扫描解析切面类

实例化前阶段会解析切面类

AbstractAutoProxyCreator#postProcessBeforeInstantiation

1
2
3
4
5
6
7
8
9
10
11
12
13
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;
}
}
//..............
}

往下跟进

AspectJAwareAdvisorAutoProxyCreator#shouldSkip

1
2
3
4
5
6
7
8
9
10
11
12
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}

跟进

AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors 方法

1
2
3
4
5
6
7
8
9
10
@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;
}

super.findCandidateAdvisors(): 调用父类的方法加载事务相关的Advisor

buildAspectJAdvisors(): 解析切面类

跟进

BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors

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
80
81
82
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<>();
//从容器中获取所有的beanname
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
//遍历
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}

//拿到bean类型
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
continue;
}
//判断类上否有Aspect注解
if (this.advisorFactory.isAspect(beanType)) {
//如果有添加到集合中
aspectNames.add(beanName);

//创建Aspect元数据对象(切面名称,所属类),解析Aspect注解
AspectMetadata amd = new AspectMetadata(beanType, beanName);
//判断是否为单例,默认情况下都是单例
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
//创建切面类实例工厂(包含Aspect元数据)
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//解析切面类获取所有的Advisor(主要是解析切面类中的通知方法)
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;
}
}
}

//遍历切面类拿到所有的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;
}

跟进

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
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
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);

//切面类实例工厂-保证容器中只有一个实例
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

List<Advisor> advisors = new ArrayList<>();
//解析切面类的所有方法
for (Method method : getAdvisorMethods(aspectClass)) {

//根据方法创建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.
//解析切面类的字段,主要是解析DeclareParents注解
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}

return advisors;
}

//主要是获取通知方法及带有Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.clas注解的方法
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
List<Method> methods = new ArrayList<>();

//adviceMethodFilter 会排除掉带有Pointcut注解的方法
ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
if (methods.size() > 1) {
//排序
//所有的方法按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class)
//尽管@After在@AfterReturn和@AfterThrowing之前排序,但@After通知方法实际上会在@AfterReturning和@AfterThrowing方法之后被调用, //因为在“try”块中调用invokes proceed(),而“finally”块中只调用@After注解的通知
methods.sort(adviceMethodComparator);
}
return methods;
}


@Override
@Nullable
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);
}

有关排序Spring官方解释

==所有的方法按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class)排序, 尽管@After在@AfterReturn和@AfterThrowing之前排序,但@After通知方法实际上会在@AfterReturning和@AfterThrowing方法之后被调用, 因为在“try”块中调用invokes proceed(),而“finally”块中只调用@After注解的通知==

跟进 InstantiationModelAwarePointcutAdvisorImpl

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
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;
//Advisor 工厂
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
//切面实例工厂
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
//切面名称
this.aspectName = aspectName;

//除了单例以外的几个类型会返回true
//判断是否要延迟实例化
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
// A singleton aspect.
//切点
this.pointcut = this.declaredPointcut;
this.lazy = false;
//实例化通知-通过aspectJAdvisorFactory获取对应的通知实例
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}

private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}

跟进 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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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;
}

//是否有Aspect注解
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;

//根据注解类型实例化对应的通知 (Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class)
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);
}
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
//解析通知上的参数名
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();

return springAdvice;
}


// AbstractAspectJAdvice#calculateArgumentBindings
public final synchronized void calculateArgumentBindings() {
// The simple case... nothing to bind.
if (this.argumentsIntrospected || this.parameterTypes.length == 0) {
return;
}

int numUnboundArgs = this.parameterTypes.length;
Class<?>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
//通知方法的参数可以是JoinPoint,ProceedingJoinPoint(只有环绕通知才可以使用这个参数,其他通知不支持),JoinPoint.StaticPart
if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0]) ||
maybeBindJoinPointStaticPart(parameterTypes[0])) {
numUnboundArgs--;
}
//如果通知的方法大于一个,按照切入点表达式进行匹配参数名
if (numUnboundArgs > 0) {
// need to bind arguments by name as returned from the pointcut match
bindArgumentsByName(numUnboundArgs);
}

this.argumentsIntrospected = true;
}

//对应方法
private boolean maybeBindProceedingJoinPoint(Class<?> candidateParameterType) {
if (ProceedingJoinPoint.class == candidateParameterType) {
if (!supportsProceedingJoinPoint()) {
throw new IllegalArgumentException("ProceedingJoinPoint is only supported for around advice");
}
this.joinPointArgumentIndex = 0;
return true;
}
else {
return false;
}
}

4.2.2. 解析切点,创建代理对象

初始化后阶段,会根据解析出来的通知匹配,从而创建代理对象

AbstractAutoProxyCreator#postProcessAfterInitialization

1
2
3
4
5
6
7
8
9
10
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
//beanname
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

跟进

wrapIfNecessary

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
//如果满足条件对bean进行处理
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;
}

// 如果目标类有通知可以应用则给给当前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;
}

isInfrastructureClass:和切面有关(切面类,切面接口实现类)的都不会被代理

shouldSkip : 如果advisor是AspectJPointcutAdvisor实例且当前的类的bean名称和切面名称相等也不会被代理

跟进

AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean

1
2
3
4
5
6
7
8
9
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
//根据当前的bean,修找符合条件的通知
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}

findEligibleAdvisors

1
2
3
4
5
6
7
8
9
10
11
12
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//获取所有的Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//获得可以应用当前bean的Advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
//添加扩展Advisor ExposeInvocationInterceptor
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}

findAdvisorsThatCanApply

1
2
3
4
5
6
7
8
9
10
11
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#findAdvisorsThatCanApply

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
//candidateAdvisors:在实例化前阶段解析的所有Advisor, clazz当前bean的class
//查找可以应用与给定类的Advisor
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
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) {
// already processed
continue;
}
//如果目标类存在方法成功匹配切点则将candidate添加到eligibleAdvisors中
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}

AopUtils#canApply

判断给定的 切点Pointcut)是否可以应用于目标类(targetClass)上

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
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
//IntroductionAdvisor
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
//判断是否是PointcutAdvisor的实例
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
//解析切点表达式,检查目标类是否符合切点的类匹配规则。
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}

//方法匹配器
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}

//判断 methodMatcher 是否是 IntroductionAwareMethodMatcher 的实例。
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}

//判断是否是代理类
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}

//获取目标类的所有接口
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

//遍历方法检查匹配规则
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
//内部会判断当前方法是否匹配通知切点
//如果有方法成功匹配切点则返回true返回
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}

return false;
}


//具体匹配逻辑
private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
ShadowMatch shadowMatch = this.shadowMatchCache.get(targetMethod);
if (shadowMatch == null) {
shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch);
//将目标方法和匹配规则存入缓存中
this.shadowMatchCache.put(targetMethod, shadowMatch);
}
return shadowMatch;
}
createProxy

用于创建代理对象

AbstractAutoProxyCreator#createProxy

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
//通过ProxyFactory创建代理对象
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {

//....
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (proxyFactory.isProxyTargetClass()) {
if (Proxy.isProxyClass(beanClass)) {
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
else {
// No proxyTargetClass flag enforced, let's apply our default checks...
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}

//获取与所有Advisor(通知,切点)
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
//目标类
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);

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

// Use original ClassLoader if bean class not locally loaded in overriding class loader
ClassLoader classLoader = getProxyClassLoader();
if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
}
//创建代理对象
return proxyFactory.getProxy(classLoader);
}

5. 实战示例

定义切面类1

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
@Slf4j
@Aspect
@Component
public class CustomAspect {
//-------------------------------------同一连接点-----------------------------------------

/**
* 前置通知
*/
@Before("@annotation(com.yang.demoservice.aop.Log)")
public void beforeAroundDemo(JoinPoint joinPoint) {
log.info("4.CustomAspect#before--aroundDemo方法执行前--" + joinPoint.getSignature());
}


/**
* 环绕通知 绑定参数
*/
@Around(value = "execution(* com.yang.demoservice.controller.DemoController.aroundDemo(..))&&args(name,age)", argNames = "joinPoint,name,age")
public Object aroundAroundDemoArgs(ProceedingJoinPoint joinPoint, String name, Integer age) throws Throwable {
log.info("2.CustomAspect#aroundAroundDemoArgs--环绕通知--aroundDemo方法执行前");
log.info("2.CustomAspect#aroundAroundDemoArgs--方法参数,name:{},参数2,age:{}", name, age);
Object proceed = joinPoint.proceed();
log.info("9.CustomAspect#aroundAroundDemoArgs--环绕通知--aroundDemo方法执行后");
return proceed;
}

/**
* 环绕通知 绑定参数
*/
@Around("@annotation(rel)")
public Object aroundAroundDemoLog(ProceedingJoinPoint joinPoint, Log rel) throws Throwable {
log.info("3.CustomAspect#aroundAroundDemoLog--环绕通知--aroundDemo方法执行前");
log.info("3.CustomAspect#aroundAroundDemoLog--注解参数,log.value:{}", rel.value());
Object proceed = joinPoint.proceed();
log.info("8.CustomAspect#aroundAroundDemoLog--注解参数,环绕通知--aroundDemo方法执行后");
return proceed;
}


/**
* 后置通知
*/
@After("@annotation(com.yang.demoservice.aop.Log))")
public void afterAroundDemo(JoinPoint joinPoint) {
log.info("7.CustomAspect#after--aroundDemo方法执行后--" + joinPoint.getSignature());
}


/**
* 方法正常执行完成 返回通知
*/
@AfterReturning(value = "@annotation(com.yang.demoservice.aop.Log)", returning = "result")
public void afterReturningAroundDemo(JoinPoint joinPoint, String result) {
log.info("6.CustomAspect#afterReturning--aroundDemo方法正常执行完成--" + joinPoint.getSignature());
log.info("6.CustomAspect#afterReturning--aroundDemo方法执行返回值:" + result);
}

/**
* 方法执行异常 异常通知
*/
@AfterThrowing(value = "@annotation(com.yang.demoservice.aop.Log)", throwing = "ex")
public void afterThrowingAroundDemo(JoinPoint joinPoint, Exception ex) {
log.info("--CustomAspect#afterThrowing--aroundDemo方法执行异常--" + joinPoint.getSignature());
log.info("--CustomAspect#afterThrowing--aroundDemo异常信息--" + ex);
}

//------------------------------------------------------------------------------


定义切面类2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Slf4j
@Aspect
@Component
public class Custom2Aspect {
@Pointcut("@annotation(com.yang.demoservice.aop.Log)")
public void pointCut() {

}

/**
* 前置通知
*/
@Before("pointCut()")
public void before(JoinPoint joinPoint) {
log.info("1.Custom2Aspect#before--aroundDemo方法执行前--"+joinPoint.getSignature());
}

}

controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Slf4j
@RestController
@RequestMapping("/demo")
public class DemoController {

@Log("环绕通知")
@RequestMapping("/d2")
public String aroundDemo(String name, Integer age) {
if (StrUtil.isNotBlank(name) && age != null) {
String result = name + ":" + age;
log.info("5.aroundDemo:" + result + "执行成功");
return "aroundDemo" + result;
} else {
log.info("5.aroundDemo:" + "执行失败");
throw new RuntimeException("aroundDemo" + "执行失败");
}
}

}

切面类1和切面类2 所有通知都作用于同一连接点

没抛出异常

访问 : http://localhost:8099/demo/d2?name=zhangsan&age=20

输出结果

image-20241209160631101

抛出异常

访问 : http://localhost:8099/demo/d2

输出结果

image-20241209160800075

结论:

  1. 在同一个切面类 CustomAspect
    • 没有抛出异常:通知的执行顺序是 Around, Before, AfterReturning, After
    • 抛出异常: 通知的执行顺序是 Around, Before, AfterThrowing, After

为什么Custom2Aspect内的切面类中的before会优先执行呢?

image-20241209161510547

在项目结构里面Custom2Aspect排在在CustomAspect前面,所以Spring在解析时会优先解析Custom2Aspect,可以通过@Order注解控制顺序

如果没指定Spring在解析bean时会按照文件排列顺序依次往下解析,由于Custom2Aspect优先被解析,所以Custom2Aspect内的通知优先被执行

  1. 在不同切面类中,可以通过@Order控制通知顺序

6. 关于切点表达式

SpringAop中文文档

7. 总结

在 Spring Boot 应用中,@Aspect AOP 的实现紧密集成于 Spring 容器的生命周期,主要通过 Bean 后处理器(BeanPostProcessor)代理机制 来完成。具体来说,AnnotationAwareAspectJAutoProxyCreator 作为一个重要的 BeanPostProcessor,负责扫描切面类、解析切点表达式,并为符合条件的目标 Bean 创建代理对象,将切面的通知织入其中。