代理 Proxy 反射 Reflect 与 Spring AOP

AOPAspect-Oriented Programming,面向切面编程)是一种编程范式,旨在通过横切关注点(Cross-cutting Concerns)的抽象和模块化,将系统的功能和非功能需求分离,从而提高代码的可维护性、可重用性和灵活性

代理模式

AOP的这种模式,底层就是基于代理模式实现

代理模式Proxy Pattern)是一种结构型设计模式,也叫委托模式,它允许通过一个代理对象来控制对另一个对象的访问。代理对象充当另一个对象的接口,以控制对该对象的访问,并在必要时添加额外的逻辑。代理模式主要用于对目标对象的访问进行控制,可以用于实现懒加载、访问控制、缓存、日志记录等功能

代理模式一般分为以下三个角色:

  1. 抽象主题(Subject):定义了目标对象和代理对象的共同接口,这样在任何使用目标对象的地方都可以使用代理对象

  2. 真实主题(Real Subject):也称为被代理对象或目标对象,它是代理模式中的真正业务逻辑的实现

  3. 代理(Proxy):代理对象,它持有对真实主题的引用,并实现了抽象主题的接口。代理对象通常在客户端与真实主题之间起到中介的作用,它可以在调用真实主题之前或之后执行一些附加操作

代理模式实现

下面是一个简单的Java中代理模式的实现示例,使用了静态代理方式:

  1. 定义抽象主题接口(Subject):
1
2
3
4
// Subject.java
public interface Subject {
void doSomething();
}
  1. 定义真实主题类(RealSubject):
1
2
3
4
5
6
7
// RealSubject.java
public class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("RealSubject is doing something...");
}
}
  1. 定义代理类(Proxy):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Proxy.java
public class Proxy implements Subject {
private RealSubject realSubject;

public Proxy() {
realSubject = new RealSubject();
}

@Override
public void doSomething() {
System.out.println("Proxy is doing something before the RealSubject...");
realSubject.doSomething();
System.out.println("Proxy is doing something after the RealSubject...");
}
}
  1. 客户端代码:
1
2
3
4
5
6
7
8
// Client.java
public class Client {
public static void main(String[] args) {
// 使用代理对象
Subject proxy = new Proxy();
proxy.doSomething();
}
}

输出结果:

1
2
3
Proxy is doing something before the RealSubject...
RealSubject is doing something...
Proxy is doing something after the RealSubject...

在上面的示例中,抽象主题(Subject)定义了一个接口,真实主题(RealSubject)实现了这个接口,代理类(Proxy)也实现了这个接口,并在方法中调用了真实主题对象的方法,同时添加了一些额外的操作。客户端通过代理对象来访问真实主题,而无需直接与真实主题交互。这样,代理对象就控制了对真实主题的访问,并且可以在调用前后添加一些自定义的逻辑

动态代理

动态代理与静态代理的区别,首先要了解两个前置知识点:Java程序的执行以及类加载机制

  • Java程序的执行过程
    • 编写源代码:首先,开发人员使用Java编程语言编写源代码,源代码通常以.java为扩展名
    • 编译源代码:使用Java编译器(javac)对源代码进行编译,将源代码转换为字节码文件。字节码文件以.class为扩展名,并包含Java虚拟机(JVM)可执行的中间代码
    • 执行.class 文件
  • 类加载机制
    • 加载(loading):通过一个类的全限定名来获取定义此类的二进制字节流,将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;在内存中生成一个代表这个类的 java.lang.class 对象,作为方法区这个类的各种数据访问入口
    • 连接(Linking):
      类加载的连接阶段包括三个子阶段:
      • 验证(Verification):对加载的类进行验证,确保其符合Java虚拟机规范和安全要求
      • 准备(Preparation):为类的静态变量分配内存空间,并设置默认初始值
      • 解析(Resolution):将类的符号引用(常量池中的符号)解析为直接引用,建立对其他类的引用关系
    • 初始化(Initialization):
      • 在初始化阶段,执行类的静态代码块和静态初始化语句,对类的静态变量进行初始化
      • 初始化阶段是类加载的最后一个阶段,在此阶段完成后,Java类对象被完全初始化,可以被使用

动态代理和静态代理是两种不同的代理模式实现方式,它们在代理对象的创建和使用方式上存在一些区别

  1. 创建时机和方式:

    • 静态代理:在编译阶段就需要创建代理类,代理类是由开发者手动编写的。对于每一个被代理的类,都需要创建一个相应的代理类
    • 动态代理:在运行时动态生成代理类,无需手动编写代理类。代理类是在程序运行时根据接口或类信息动态创建的
  2. 代理对象与目标对象的关系:

    • 静态代理:代理对象和目标对象之间的关系是静态的,即在编译时就已经确定了。每个代理类只能代理一个目标类,代理类与目标类是一一对应的关系
    • 动态代理:代理对象和目标对象之间的关系是动态的,即在程序运行时根据需要动态生成代理类。一个动态代理类可以代理多个目标类,代理对象的关联是在运行时决定的
  3. 实现方式:

    • 静态代理:通过手动编写代理类来实现,需要为每一个目标类创建一个代理类
    • 动态代理:使用Java的反射机制,在运行时动态生成代理类。Java提供了两种动态代理的方式:基于接口的代理(JDK动态代理)和基于类的代理(CGLIB动态代理)
  4. 灵活性:

    • 静态代理:代理类的创建和目标类的绑定是在编译时确定的,因此在程序运行时无法动态改变代理关系。
    • 动态代理:由于代理类是在运行时生成的,因此可以根据需要动态地改变代理关系,更加灵活。

总体而言,静态代理需要手动编写代理类,对于少量目标类的代理是可行的,但当目标类数量较多时会产生大量重复代码。而动态代理通过在运行时动态生成代理类,避免了手动编写代理类的繁琐过程,适用于代理对象较多、代理关系动态变化的情况

JDK动态代理

JDK动态代理是Java中实现动态代理的一种机制,它是Java标准库(java.lang.reflect包)提供的一种代理方式。JDK动态代理基于接口的代理方式,通过在运行时动态生成代理类来实现代理功能。JDK动态代理使用了Java的反射机制来实现,可以在运行时创建代理对象,无需手动编写代理类

JDK动态代理的核心类是java.lang.reflect.Proxy,它提供了静态方法newProxyInstance()来创建代理对象。newProxyInstance()方法接收三个参数:

  1. ClassLoader:用于加载动态生成的代理类的类加载器。
  2. Class[] interfaces:代理类要实现的接口数组,代理对象将实现这些接口。
  3. InvocationHandler:代理对象的调用处理程序,它定义了代理对象在执行方法时的行为。

以下是一个使用JDK动态代理的简单示例:

  1. 定义抽象主题接口(Subject):
1
2
3
4
// Subject.java
public interface Subject {
void doSomething();
}
  1. 定义真实主题类(RealSubject):
1
2
3
4
5
6
7
// RealSubject.java
public class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("RealSubject is doing something...");
}
}
  1. 定义代理处理程序(MyInvocationHandler):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// MyInvocationHandler.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {
private Object realSubject;

public MyInvocationHandler(Object realSubject) {
this.realSubject = realSubject;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Proxy is doing something before the RealSubject...");
Object result = method.invoke(realSubject, args);
System.out.println("Proxy is doing something after the RealSubject...");
return result;
}
}
  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
// Client.java
import java.lang.reflect.Proxy;

public class Client {
public static void main(String[] args) {
// 创建真实主题对象
Subject realSubject = new RealSubject();

// 创建代理处理程序
MyInvocationHandler handler = new MyInvocationHandler(realSubject);
// 获取对应的 ClassLoader
ClassLoader classLoader = realSubject.getClass().getClassLoader();
// 获取所有接口的Class,这里的UserServiceImpl只实现了一个接口UserService
Class[] interfaces = realSubject.getClass().getInterfaces()

// 创建代理对象
Subject proxy = (Subject) Proxy.newProxyInstance(
classLoader,
interfaces,
handler);

// 使用代理对象
proxy.doSomething();
}
}

输出结果:

1
2
3
Proxy is doing something before the RealSubject...
RealSubject is doing something...
Proxy is doing something after the RealSubject...

在上面的示例中,我们通过 Proxy.newProxyInstance() 方法创建了一个代理对象,该代理对象实现了Subject接口,并在调用方法时通过 MyInvocationHandler 中定义的逻辑来进行增强操作。这样,我们就实现了一个基于JDK动态代理的简单代理功能

JDK动态代理分析

Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)

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
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) {
Objects.requireNonNull(h);

final Class<?>[] intfs = interfaces.clone();
// 查询(在缓存中已经有)或生成指定的代理类的class对象。
Class<?> cl = getProxyClass0(loader, intfs);

try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
// 返回对应参数的公共构造函数
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
// 生成代理对象
return cons.newInstance(new Object[]{h});
}
... // 省略
}

最后来到 ProxyClassFactoryapply() 方法,代理类就是在这里生成的

CGLib动态代理

CGLib动态代理是另一种实现动态代理的方式,它与JDK动态代理不同,不基于接口,而是对类进行代理。CGLib是一个强大的代码生成库,它能够在运行时扩展Java类和实现代理功能。CGLib动态代理的原理是通过生成目标类的子类来实现代理,因此被代理的类不能是final类,且代理的方法不能是final或static的。两者的区别有以下几点:

  1. Java动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承);CGLIB能够代理普通类。
  2. Java动态代理使用Java原生的反射API进行操作,在生成类上比较高效;CGLIB 使用ASM框架直接对字节码进行操作,在类的执行过程中比较高效。

CGLib动态代理的核心类是 net.sf.cglib.proxy.Enhancer,它是CGLib库中的代理增强类,用于生成代理类的实例。使用CGLib动态代理需要依赖CGLib库。

以下是一个使用CGLib动态代理的简单示例:

  1. 定义目标类(RealSubject):
1
2
3
4
5
6
// RealSubject.java
public class RealSubject {
public void doSomething() {
System.out.println("RealSubject is doing something...");
}
}
  1. 定义代理处理程序(MyMethodInterceptor):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// MyMethodInterceptor.java
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// before
System.out.println("Proxy is doing something before the RealSubject...");
Object result = proxy.invokeSuper(obj, args);
// after
System.out.println("Proxy is doing something after the RealSubject...");
return result;
}
}

intercept方法四个参数的含义如下: obj: 代理类对象。 method: 被代理的类中的方法。 args: 调用方法需要的参数。 proxy: 生成的代理类对方法的代理引用

用户需要实现MethodInterceptor接口,实现对方法的拦截。这一点与JDK动态代理中用户需要实现InvocationHandler接口类似

  1. 客户端代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Client.java
import net.sf.cglib.proxy.Enhancer;

public class Client {
public static void main(String[] args) {
// 创建代理处理程序
MyMethodInterceptor interceptor = new MyMethodInterceptor();

// 使用Enhancer创建代理对象
Enhancer enhancer = new Enhancer();
// 设置继承被代理类
enhancer.setSuperclass(RealSubject.class);
// 设置回调
enhancer.setCallback(interceptor);
RealSubject proxy = (RealSubject) enhancer.create();

// 使用代理对象
proxy.doSomething();
}
}

输出结果:

1
2
3
Proxy is doing something before the RealSubject...
RealSubject is doing something...
Proxy is doing something after the RealSubject...

在上面的示例中使用CGLib的 Enhancer 类来创建了一个代理对象,该代理对象继承了 RealSubject 类,并在调用方法时通过 MyMethodInterceptor 中定义的逻辑来进行增强操作。这样就实现了一个基于CGLib动态代理的简单代理功能

需要注意的是,CGLib动态代理相比于JDK动态代理的优点在于它可以代理没有实现接口的类,而且在一些场景下由于继承的方式,可以更高效地执行代理。然而,CGLib动态代理也有一些限制,例如无法代理 final 类和 final 方法

CGLib动态代理分析

生成指定类Class对象字节数组,CGLib动态代理会选择目标类(被代理类)作为父类,然后生成代理类的字节码——首先创建Enhancer对象,设置SuperClass父类(被代理类),然后调用Enhancer对象的create()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public Object create() {
this.classOnly = false;
this.argumentTypes = null;
return this.createHelper();
}

private Object createHelper() {
//1.进行有效性验证
//1.1 callBack不能为空,也就是说至少要有一个callBack(callBack与代理类紧密相关)
//1.2 有多个callBack时必须有callBackFilter
this.preValidate();
//2.先根据KEY_FACTORY 以当前代理类的配置信息 生成一个组合Key,再利用这个组合Key,进行create
Object key = KEY_FACTORY.newInstance(this.superclass != null ? this.superclass.getName() : null,
ReflectUtils.getNames(this.interfaces),
this.filter == ALL_ZERO ? null : new WeakCacheKey(this.filter),
this.callbackTypes,
this.useFactory,
this.interceptDuringConstruction,
this.serialVersionUID);
this.currentKey = key;
//根据生成的key创建代理对象
Object result = super.create(key);
return result;
}

然后到了 Enhance 继承的 AbstractClassGenerator 类中的 create() 方法,这一步就是为了得到动态类的Class对象,之后通过反射生成具体的类的对象

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
protected Object create(Object key) {
try {
//1.获取当前类加载器,应用类加载器
ClassLoader loader = this.getClassLoader();
//2.缓存,一级缓存的key是类加载器,value是ClassLoaderData
//2.1 cache中有则直接获取
Map<ClassLoader, ClassLoaderData> cache = CACHE;
ClassLoaderData data = (ClassLoaderData)cache.get(loader);
//2.2 cache中没有则生成,双重检查🔒
if (data == null) {
Class var5 = AbstractClassGenerator.class;
synchronized(AbstractClassGenerator.class) {
cache = CACHE;
data = (ClassLoaderData)cache.get(loader);
if (data == null) {
Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap(cache);
data = new ClassLoaderData(loader);
newCache.put(loader, data);
CACHE = newCache;
}
}
}
this.key = key;
//3.调用 get方法获取字节码,如果没有字节码,则会创建字节码(Class对象)
Object obj = data.get(this, this.getUseCache());
//4.生成动态代理类
return obj instanceof Class ? this.firstInstance((Class)obj) : this.nextInstance(obj);
} catch (Error | RuntimeException var9) {
throw var9;
} catch (Exception var10) {
throw new CodeGenerationException(var10);
}
}

ClassLoaderData.get() 方法

1
2
3
4
5
6
7
8
9
public Object get(AbstractClassGenerator gen, boolean useCache) {
//判断是否开启缓存,可直接设置:enhancer.setUseCache(false); 默认为true
if (!useCache) {
return gen.generate(this);
} else {
Object cachedValue = this.generatedClasses.get(gen);
return gen.unwrapCachedValue(cachedValue);
}
}

进到 AbstractClassGenerator 的 generate() 方法

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
protected Class generate(ClassLoaderData data) {
Class gen;
Object save = CURRENT.get();
CURRENT.set(this);
try {
// 1.判断有无classLoader
ClassLoader classLoader = data.getClassLoader();
if (classLoader == null) {
throw new IllegalStateException("ClassLoader is null while trying to define class " +
getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " +
"Please file an issue at cglib's issue tracker.");
}
// 2.生成动态代理的类名
synchronized (classLoader) {
// 生成代理类名称
String name = generateClassName(data.getUniqueNamePredicate());
data.reserveName(name);
this.setClassName(name);
}
if (attemptLoad) {
try {
gen = classLoader.loadClass(getClassName());
return gen;
}
catch (ClassNotFoundException e) {
// ignore
}
}
// 3.生成动态代理类的字节码
byte[] b = strategy.generate(this);
String className = ClassNameReader.getClassName(new ClassReader(b));
ProtectionDomain protectionDomain = getProtectionDomain();
// 4.生成class文件
synchronized (classLoader) { // just in case
// SPRING PATCH BEGIN
gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain, contextClass);
// SPRING PATCH END
}
return gen;
}
catch (RuntimeException | Error ex) {
throw ex;
}
catch (Exception ex) {
throw new CodeGenerationException(ex);
}
finally {
CURRENT.set(save);
}
}

这里第三步的 strategy.generate() 方法是 DefaultGeneratorStrategy 中的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
public class DefaultGeneratorStrategy implements GeneratorStrategy {
public static final DefaultGeneratorStrategy INSTANCE = new DefaultGeneratorStrategy();

public DefaultGeneratorStrategy() {
}

public byte[] generate(ClassGenerator cg) throws Exception {
DebuggingClassWriter cw = this.getClassVisitor();
this.transform(cg).generateClass(cw);
return this.transform(cw.toByteArray());
}
...// 省略
}

这里的 getClassVistor 调用了asm的接口,生成了一个 DebuggingClassWriter 对象,这里的cg就是之前的 Enhancer 实例,点进 generateClass() 方法,又回到 Enhance 类:

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
public void generateClass(ClassVisitor v) throws Exception {
Class sc = (superclass == null) ? Object.class : superclass;

if (TypeUtils.isFinal(sc.getModifiers()))
throw new IllegalArgumentException("Cannot subclass final class " + sc.getName());
List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors()));
filterConstructors(sc, constructors);

// Order is very important: must add superclass, then
// its superclass chain, then each interface and
// its superinterfaces.
List actualMethods = new ArrayList();
List interfaceMethods = new ArrayList();
final Set forcePublic = new HashSet();
// 1.得到所有的方法,包括基类、接口
getMethods(sc, interfaces, actualMethods, interfaceMethods, forcePublic);

List methods = CollectionUtils.transform(actualMethods, new Transformer() {
public Object transform(Object value) {
Method method = (Method) value;
int modifiers = Constants.ACC_FINAL
| (method.getModifiers()
& ~Constants.ACC_ABSTRACT
& ~Constants.ACC_NATIVE
& ~Constants.ACC_SYNCHRONIZED);
if (forcePublic.contains(MethodWrapper.create(method))) {
modifiers = (modifiers & ~Constants.ACC_PROTECTED) | Constants.ACC_PUBLIC;
}
return ReflectUtils.getMethodInfo(method, modifiers);
}
});
// 2.生成字节码,参数还是之前的classWriter
// 2.1 这里的className就是之前生成的className
ClassEmitter e = new ClassEmitter(v);
if (currentData == null) {
e.begin_class(Constants.V1_8,
Constants.ACC_PUBLIC,
getClassName(),
Type.getType(sc),
(useFactory ?
TypeUtils.add(TypeUtils.getTypes(interfaces), FACTORY) :
TypeUtils.getTypes(interfaces)),
Constants.SOURCE_FILE);
}
else {
e.begin_class(Constants.V1_8,
Constants.ACC_PUBLIC,
getClassName(),
null,
new Type[]{FACTORY},
Constants.SOURCE_FILE);
}
List constructorInfo = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance());
// 2.2 这些都是字段,之后我们会在生成的文件中看到
e.declare_field(Constants.ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null);
e.declare_field(Constants.ACC_PUBLIC | Constants.ACC_STATIC, FACTORY_DATA_FIELD, OBJECT_TYPE, null);
if (!interceptDuringConstruction) {
e.declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null);
}
e.declare_field(Constants.PRIVATE_FINAL_STATIC, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null);
e.declare_field(Constants.PRIVATE_FINAL_STATIC, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null);
if (serialVersionUID != null) {
e.declare_field(Constants.PRIVATE_FINAL_STATIC, Constants.SUID_FIELD_NAME, Type.LONG_TYPE, serialVersionUID);
}
// 2.3 这里就是生成的callback,命名就是CGLIB&CALLBACK_在数组中的序号
for (int i = 0; i < callbackTypes.length; i++) {
e.declare_field(Constants.ACC_PRIVATE, getCallbackField(i), callbackTypes[i], null);
}
// This is declared private to avoid "public field" pollution
e.declare_field(Constants.ACC_PRIVATE | Constants.ACC_STATIC, CALLBACK_FILTER_FIELD, OBJECT_TYPE, null);

if (currentData == null) {
// 2.5 filter在这里发生作用
emitMethods(e, methods, actualMethods);
emitConstructors(e, constructorInfo);
}
else {
emitDefaultConstructor(e);
}
emitSetThreadCallbacks(e);
emitSetStaticCallbacks(e);
emitBindCallbacks(e);

if (useFactory || currentData != null) {
int[] keys = getCallbackKeys();
emitNewInstanceCallbacks(e);
emitNewInstanceCallback(e);
emitNewInstanceMultiarg(e, constructorInfo);
emitGetCallback(e, keys);
emitSetCallback(e, keys);
emitGetCallbacks(e);
emitSetCallbacks(e);
}

e.end_class();
}

回到前面 AbstractClassGenerator#create 方法

1
2
3
4
5
...
if (obj instanceof Class) {
return firstInstance((Class) obj);
}
...

点进 firstInstance() 方法里,来到 Enhancer#firstInstance

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
protected Object firstInstance(Class type) throws Exception {
if (classOnly) {
return type;
}
else {
return createUsingReflection(type);
}
}

private Object createUsingReflection(Class type) {
setThreadCallbacks(type, callbacks);
try {

if (argumentTypes != null) {

return ReflectUtils.newInstance(type, argumentTypes, arguments);

}
else {

return ReflectUtils.newInstance(type);

}
}
finally {
// clear thread callbacks to allow them to be gc'd
setThreadCallbacks(type, null);
}
}

这里使用了 ReflectUtils 反射工具类中的方法,完成了动态代理对象的生成

反射

动态代理里讲到了反射,在Java中,动态代理主要通过Java反射机制实现,可以在程序运行时动态创建代理对象,无需手动编写代理类

反射是Java语言中的一种机制,允许程序在运行时动态地获取、检查和操作类的信息以及对象的属性和方法。Java反射API位于java.lang.reflect包中,它提供了一组类和接口,用于实现反射功能。反射机制为开发者提供了在编译时无法确定的类结构信息,从而实现一些灵活、动态的操作

反射的基础知识包括以下几个关键概念:

  1. Class类java.lang.Class 是Java反射机制的核心类,它代表一个Java类的运行时信息。通过Class类,可以获取类的结构信息,如字段、方法、构造函数、父类、实现的接口等。

  2. 获取Class对象:可以通过三种方式来获取一个类的Class对象:

    • 使用Class.forName(String className):根据类的全限定名获取Class对象。需要处理ClassNotFoundException异常。
    • 使用.class语法:例如,String.class获取String类的Class对象。
    • 使用Object.getClass()方法:通过对象的getClass()方法获取对象所属类的Class对象。
  3. 获取类的信息:通过Class对象的方法,可以获取类的结构信息,例如:

    • getFields():获取类的公共字段。
    • getMethods():获取类的公共方法。
    • getConstructors():获取类的公共构造函数。
    • getDeclaredFields():获取类的所有字段(包括私有字段)。
    • getDeclaredMethods():获取类的所有方法(包括私有方法)。
  4. 创建对象:通过Class对象的newInstance()方法,可以创建类的实例。

  5. 访问字段和方法:通过反射可以动态地访问和修改类的字段值和调用类的方法。

反射机制的优点在于它提供了动态性和灵活性,使得开发者能够在运行时动态地获取和操作类的信息,避免了在编译时固定的限制。然而,由于反射涉及到动态生成代码和动态检查类型,其性能可能较低,不宜频繁地使用,最好在需要时再使用

反射原理

反射(Reflection)和类加载(Class Loading)是Java中两个重要的概念,它们之间有一定的关系。反射是Java语言提供的一种机制,允许在运行时动态地获取、检查和操作类的信息,而类加载Java虚拟机在将类字节码加载到内存并生成类对象的过程

类加载是反射的基础,反射的操作都是基于类加载完成的。在使用反射之前,需要先将类加载到内存中,然后通过类的Class对象来进行反射操作,java类的执行需要经历以下过程:

编译:java文件编译后生成 .class 字节码文件

类加载

Java 类加载机制- 类加载的时机和过程

  • 加载:类加载器负责根据一个类的全限定名来读取此类的二进制字节流到 JVM 内部,并存储在运行时内存区的方法区,然后将其转换为一个与目标类型对应的 java.lang.Class 对象实例

  • 连接

    • 验证:格式(class文件规范) 语义(final类是否有子类) 操作

    • 准备:静态变量赋初值和内存空间,final修饰的内存空间直接赋原值,此处不是用户指定的初值。

    • 解析:符号引用转化为直接引用,分配地址

  • 初始化:有父类先初始化父类,然后初始化自己;将static修饰代码执行一遍,如果是静态变量,则用用户指定值覆盖原有初值;如果是代码块,则执行一遍操作。

Java的反射就是利用上面第二步加载到jvm中的 .class 文件来进行操作。具体来说,在Java虚拟机对类进行加载和连接的过程中,反射主要在解析阶段进行,其中解析的主要目标是将类、字段、方法的符号引用转换为直接引用,建立类之间的关联关系

以下是一个使用反射调用方法的简单示例:

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
import java.lang.reflect.Method;

public class MyClass {
public void sayHello() {
System.out.println("Hello, World!");
}

public int add(int a, int b) {
return a + b;
}

public static void main(String[] args) throws Exception {
// 获取Class对象
Class<?> clazz = MyClass.class;

// 获取无参方法的Method对象并调用
Method sayHelloMethod = clazz.getMethod("sayHello");
sayHelloMethod.invoke(clazz.newInstance());

// 获取有参方法的Method对象并调用
Method addMethod = clazz.getMethod("add", int.class, int.class);
int result = (int) addMethod.invoke(clazz.newInstance(), 10, 20);
System.out.println("Result: " + result);
}
}

输出结果:

1
2
Hello, World!
Result: 30

需要注意的是,在使用反射调用方法时,要确保方法的名称、参数类型和调用的方法是一致的,否则会抛出 NoSuchMethodException IllegalArgumentException 异常

接下来主要解析一下获取 Method 对象和 Method.invoke() 方法

获取 Method 对象

在Java的反射机制中,可以通过Class对象获取Method对象,Method对象代表了类中的方法。通过Method对象可以在运行时动态地调用类的方法。Java反射中获取Method对象的方法主要有以下两个:

  1. getMethod(String name, Class<?>... parameterTypes)

    • 用于获取类的公共方法(包括从父类继承的公共方法)。
    • 参数name是要获取的方法的名称。
    • 参数parameterTypes是方法的参数类型数组,用于指定方法的参数类型。如果方法有参数,需要将参数类型以Class对象的形式传递进去。如果方法没有参数,可以不传递该参数。
    • 返回值是一个Method对象,表示与指定名称和参数类型匹配的公共方法。如果未找到对应的方法,则抛出NoSuchMethodException异常。
  2. getDeclaredMethod(String name, Class<?>... parameterTypes)

    • 用于获取类自身声明的方法(包括私有方法)。
    • 参数name是要获取的方法的名称。
    • 参数parameterTypes是方法的参数类型数组,用于指定方法的参数类型。如果方法有参数,需要将参数类型以Class对象的形式传递进去。如果方法没有参数,可以不传递该参数。
    • 返回值是一个Method对象,表示与指定名称和参数类型匹配的类自身声明的方法。如果未找到对应的方法,则抛出NoSuchMethodException异常。

上述两个方法都有获取复数个的方法,区别就是方法名后有 “s” 后缀

注意事项

  • 当获取私有方法时,使用getDeclaredMethod()方法;当获取公共方法时,使用getMethod()方法。
  • 如果获取的方法是私有方法,需要通过setAccessible(true)方法将其设置为可访问,以允许访问私有方法。

其实不管是getMethod还是getDeclaredMethod,底层都调用了同一个方法:privateGetDeclaredMethods

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
private Method privateGetMethodRecursive(String name,
Class<?>[] parameterTypes,
boolean includeStaticMethods,
MethodArray allInterfaceCandidates) {

// Must _not_ return root methods
Method res;
// Search declared public methods 搜索本来中声明的公共方法
if ((res = searchMethods(privateGetDeclaredMethods(true),
name,
parameterTypes)) != null) {
if (includeStaticMethods || !Modifier.isStatic(res.getModifiers()))
return res;
}
// 如果res为空,继续向父类搜索
// Search superclass's methods
if (!isInterface()) {
Class<? super T> c = getSuperclass();
if (c != null) {
// 递归调用getMethod0,获取父类的方法实现
if ((res = c.getMethod0(name, parameterTypes, true)) != null) {
return res;
}
}
}
// res仍然为空,继续向接口搜索
// Search superinterfaces' methods
Class<?>[] interfaces = getInterfaces();
for (Class<?> c : interfaces)
if ((res = c.getMethod0(name, parameterTypes, false)) != null)
allInterfaceCandidates.add(res);
// Not found
return null;
}

然后在看看 searchMethods() 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private static Method searchMethods(Method[] methods,
String name,
Class<?>[] parameterTypes)
{
Method res = null;
String internedName = name.intern();
for (int i = 0; i < methods.length; i++) {
Method m = methods[i];
if (m.getName() == internedName
&& arrayContentsEq(parameterTypes, m.getParameterTypes())
&& (res == null
|| res.getReturnType().isAssignableFrom(m.getReturnType())))
res = m;
}

return (res == null ? res : getReflectionFactory().copyMethod(res));
}

其中循环了 Method[] methods 这个数组,而这个参数是由 privateGetDeclaredMethods(boolean publicOnly) 获得的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private Method[] privateGetDeclaredMethods(boolean publicOnly) {
checkInitted();
Method[] res;
// 1.ReflectionData 存储反射数据的缓存结构
ReflectionData<T> rd = reflectionData();
if (rd != null) {
// 2.先从缓存中获取methods
res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods;
if (res != null) return res;
}
// No cached value available; request value from VM
// 3.没有缓存,通过 JVM 获取,native方法
res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));
if (rd != null) {
if (publicOnly) {
rd.declaredPublicMethods = res;
} else {
rd.declaredMethods = res;
}
}
return res;
}

其中的 ReflectionData<T>是类Class的静态内部类,<T>表示泛型,为具体的类对象。该缓存数据结构中存储了类的所有信息。redefinedCount是类的重定义次数,可以理解为缓存的版本号,每一个类对象理论上都会有(被垃圾回收或从来没被加载过就没没有)一个ReflectionData<T>的缓存,通过 reflectionData() 获取:

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
// Lazily create and cache ReflectionData
private ReflectionData<T> reflectionData() {
SoftReference<ReflectionData<T>> reflectionData = this.reflectionData;
int classRedefinedCount = this.classRedefinedCount;
ReflectionData<T> rd;
if (useCaches &&
reflectionData != null &&
(rd = reflectionData.get()) != null &&
rd.redefinedCount == classRedefinedCount) {
return rd;
}
// else no SoftReference or cleared SoftReference or stale ReflectionData
// -> create and replace new instance
return newReflectionData(reflectionData, classRedefinedCount);
}

private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData, int classRedefinedCount) {
// 不使用缓存则直接返回null
if (!useCaches) return null;

// 使用while+CAS方式更新数据,创建一个新的ReflectionData,如果更新成功直接返回
while (true) {
ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount);
// try to CAS it...
if (Atomic.casReflectionData(this, oldReflectionData, new SoftReference<>(rd))) {
return rd;
}
// else retry
// 获取到旧的reflectionData和classRedefinedCount的值,如果旧的值不为null, 并且缓存未失效,说明其他线程更新成功了,直接返回
oldReflectionData = this.reflectionData;
classRedefinedCount = this.classRedefinedCount;
if (oldReflectionData != null &&
(rd = oldReflectionData.get()) != null &&
rd.redefinedCount == classRedefinedCount) {
return rd;
}
}
}
Method.invoke()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
// 1.检查权限,如果 override == true,就跳过检查
// 通常在 Method#invoke 之前,会调用 Method#setAccessible(true),就是设置 override 值为 true
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
// 2.获取 MethodAccessor
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
// 2.1为空时创建MethodAccessor
ma = acquireMethodAccessor();
}
// 3.调用 MethodAccessor.invoke
return ma.invoke(obj, args);
}

这里会获取 MethodAccessor ,这个在之前 searchMethods() 最后会调用 Method#copy 会给 MethodmethodAccessor 赋值,如果为空则去创建 MethodAccessor

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
private MethodAccessor acquireMethodAccessor() {
// First check to see if one has been created yet, and take it
// if so
MethodAccessor tmp = null;
if (root != null) tmp = root.getMethodAccessor();
if (tmp != null) {
methodAccessor = tmp;
} else {
// Otherwise fabricate one and propagate it up to the root
tmp = reflectionFactory.newMethodAccessor(this);
setMethodAccessor(tmp);
}

return tmp;
}

public MethodAccessor newMethodAccessor(Method var1) {
checkInitted();
if (noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) {
return (new MethodAccessorGenerator()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers());
} else {
NativeMethodAccessorImpl var2 = new NativeMethodAccessorImpl(var1);
DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl(var2);
var2.setParent(var3);
return var3;
}
}

这里会先查找 rootMethodAccessor,这里的 root 在上面 Method#copy 中设置过。如果还是没有找到,就去创建 MethodAccessor

newMethodAccessor() 方法里可以看到一共有三种 MethodAccessor

  • MethodAccessorImpl
  • NativeMethodAccessorImpl
  • DelegatingMethodAccessorImpl

采用哪种 MethodAccessor 根据 noInflation 进行判断,noInflation 默认值为 false,只有指定了 sun.reflect.noInflation 属性为 true,才会采用 MethodAccessorImpl ,所以默认会调用 NativeMethodAccessorImpl

MethodAccessorImpl 是通过动态生成字节码来进行方法调用的,是 Java 版本的 MethodAccessor

DelegatingMethodAccessorImpl 就是单纯的代理,真正的实现还是 NativeMethodAccessorImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
private MethodAccessorImpl delegate;

DelegatingMethodAccessorImpl(MethodAccessorImpl delegate) {
setDelegate(delegate);
}

public Object invoke(Object obj, Object[] args)
throws IllegalArgumentException, InvocationTargetException
{
return delegate.invoke(obj, args);
}

void setDelegate(MethodAccessorImpl delegate) {
this.delegate = delegate;
}
}

NativeMethodAccessorImplNative 版本的 MethodAccessor 实现。

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
class NativeMethodAccessorImpl extends MethodAccessorImpl {
public Object invoke(Object obj, Object[] args)
throws IllegalArgumentException, InvocationTargetException
{
// We can't inflate methods belonging to vm-anonymous classes because
// that kind of class can't be referred to by name, hence can't be
// found from the generated bytecode.
if (++numInvocations > ReflectionFactory.inflationThreshold()
&& !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
// Java 版本的 MethodAccessor
MethodAccessorImpl acc = (MethodAccessorImpl)
new MethodAccessorGenerator().
generateMethod(method.getDeclaringClass(),
method.getName(),
method.getParameterTypes(),
method.getReturnType(),
method.getExceptionTypes(),
method.getModifiers());
parent.setDelegate(acc);
}
// Native 版本调用
return invoke0(method, obj, args);
}

private static native Object invoke0(Method m, Object obj, Object[] args);
}

NativeMethodAccessorImpl 的实现中,我们可以看到,有一个 numInvocations 阀值控制,numInvocations 表示调用次数。如果 numInvocations 大于 15(默认阀值是 15),那么就使用 Java 版本的 MethodAccessorImpl。 为什么采用这个策略呢,可以 JDK 中的注释:

1
// "Inflation" mechanism. Loading bytecodes to implement
1
// Method.invoke() and Constructor.newInstance() currently costs
1
2
3
4
5
6
7
8
9
10
11
12
// 3-4x more than an invocation via native code for the first
// invocation (though subsequent invocations have been benchmarked
// to be over 20x faster). Unfortunately this cost increases
// startup time for certain applications that use reflection
// intensively (but only once per class) to bootstrap themselves.
// To avoid this penalty we reuse the existing JVM entry points
// for the first few invocations of Methods and Constructors and
// then switch to the bytecode-based implementations.
//
// Package-private to be accessible to NativeMethodAccessorImpl
// and NativeConstructorAccessorImpl
private static boolean noInflation = false;

比起通过本地代码进行的首次调用,方法和构造函数的首次调用要快3-4倍(虽然后续的调用已经经过基准测试,速度可以达到原来的20倍以上)。然而,这个过程会增加某些密集使用反射(但每个类仅一次)来引导自身的应用程序的启动时间。为了避免这种性能损耗,我们在方法和构造函数的前几次调用中重用现有的JVM入口点,然后切换到基于字节码的实现

Method.invoke() 的最后,调用 MethodAccessor#invoke 实现方法的调用

AOP

说完了前置知识,终于可以开始正题了

在传统的面向对象编程中,系统的功能通常以对象的形式组织,但某些功能可能会散布在整个应用程序中,而不局限于单个对象或类。这些功能被称为横切关注点,如日志记录、安全性、事务处理等。AOP的目标就是通过把这些横切关注点从核心业务逻辑中分离出来,形成独立的模块,并通过特定的方式将其织入到应用程序中。通俗一点表达就是:AOP 要实现的是在我们原来写的代码的基础上,进行一定的包装,如在方法执行前、方法返回后、方法抛出异常后等地方进行一定的拦截处理或者叫增强处理

作为 Java 开发者都很熟悉 AspectJ 这个词,甚至于在提到 AOP 的时候,想到的往往就是 AspectJ。这里简单的将 AspectJ 和 Spring AOP 做个对比:

Spring AOP:
  • 它基于动态代理来实现。默认来说,如果使用接口,它会采用 JDK 提供的动态代理实现,如果没有接口,则会使用 CGLib 实现
  • Spring 3.2 以后,spring-core 直接就把 CGLIB 和 ASM 的源码包括进来了,所以平时开发时不需要显式引入这两个依赖
  • 如果你是 web 开发者,有些时候可能需要的是一个 Filter 或一个 Interceptor,而不一定是 AOP
  • Spring AOP 只能作用于 Spring 容器中的 Bean,它是使用纯粹的 Java 代码实现的,只能作用于 bean 的方法
  • Spring 提供了 AspectJ 的支持,但一般来说只用 Spring AOP 就够
  • 很多人会对比 Spring AOP 和 AspectJ 的性能,Spring AOP 是基于代理实现的,在容器启动的时候需要生成代理实例,在方法调用上也会增加栈的深度,使得 Spring AOP 的性能不如 AspectJ 那么好
AspectJ:
  • AspectJ 出身也是名门,来自于 Eclipse 基金会,https://www.eclipse.org/aspectj

  • 属于静态织入,它是通过修改代码来实现的,它的织入时机可以是:

    • Compile-time weaving:编译期织入,如类 A 使用 AspectJ 添加了一个属性,类 B 引用了它,这个场景就需要编译期的时候就进行织入,否则没法编译类 B。
    • Post-compile weaving:也就是已经生成了 .class 文件,或已经打成 jar 包了,这种情况我们需要增强处理的话,就要用到编译后织入。
    • Load-time weaving:指的是在加载类的时候进行织入,要实现这个时期的织入,有几种常见的方法。1、自定义类加载器来干这个,这个应该是最容易想到的办法,在被织入类加载到 JVM 前去对它进行加载,这样就可以在加载的时候定义行为了。2、在 JVM 启动的时候指定 AspectJ 提供的 agent:-javaagent:xxx/xxx/aspectjweaver.jar
  • AspectJ 能干很多 Spring AOP 干不了的事情,它是 AOP 编程的完全解决方案。Spring AOP 致力于解决的是企业级开发中最普遍的 AOP 需求(方法织入),而不是力求成为一个像 AspectJ 一样的 AOP 编程完全解决方案。

  • 因为 AspectJ 在实际代码运行前完成了织入,所以大家会说它生成的类是没有额外运行时开销的

AOP的关键概念:
  1. 切面(Aspect):切面是横切关注点的抽象表示,它包含了与某个横切关注点相关的一组通用功能。比如,日志记录是一个切面,它可以包含日志输出的功能

  2. 连接点(Join Point):连接点是应用程序中可能被切面影响的点。在Java中,连接点通常表示为方法的执行或异常的抛出

  3. 通知(Advice):通知是切面在特定连接点上执行的具体动作。通知包括前置通知(Before)、后置通知(After)、返回通知(After Returning)、异常通知(After Throwing)和环绕通知(Around)等

  4. 切点(Pointcut):切点是一组连接点的集合,它定义了切面在哪些连接点上起作用。切点使用表达式来匹配连接点,从而确定在哪些连接点上应用通知

  5. 引入(Introduction):引入允许在不修改代码的情况下向现有类添加新的方法和属性

  6. 织入(Weaving):织入是将切面应用到目标对象并创建新的代理对象的过程。织入可以在编译时、类加载时或运行时进行

Spring AOP

这里介绍的 Spring AOP 是纯的 Spring 代码,和 AspectJ 没什么关系,但是 Spring 延用了 AspectJ 中的概念,包括使用了 AspectJ 提供的 jar 包中的注解,但是不依赖于其实现功能

后面介绍的如 @Aspect、@Pointcut、@Before、@After 等注解都是来自于 AspectJ,但是功能的实现是纯 Spring AOP 自己实现的

在 Spring 的容器中,我们面向的对象是一个个的 bean 实例。我们可以简单理解 bean 是 BeanDefinition 的实例,Spring 会根据 BeanDefinition 中的信息为我们生产合适的 bean 实例出来

当我们需要使用 bean 的时候,通过 IOC 容器的 getBean() 方法从容器中获取 bean 实例,只不过大部分的场景下,我们都用了依赖注入,所以很少手动调用 getBean() 方法

Spring AOP 的原理很简单,就是动态代理,它和 AspectJ 不一样,AspectJ 是直接修改掉你的字节码

代理模式很简单,接口 + 真实实现类 + 代理类,其中 真实实现类代理类 都要实现接口,实例化的时候要使用代理类。所以,Spring AOP 需要做的是生成这么一个代理类,然后替换掉真实实现类来对外提供服务

替换这个操作在 Spring IOC 容器中非常容易实现,就是在 getBean() 的时候返回的实际上是代理类的实例,而这个代理类我们自己没写代码,它是 Spring 采用 JDK Proxy 或 CGLIB 动态生成的

Spring 2.0 @AspectJ 配置

在 Spring 2.0 之后引入了 @AspectJSchema-based 的两种配置方式,这里仅介绍 AspectJ 注解的方式。首先,我们需要依赖 aspectjweaver.jar 这个包,这个包来自于 AspectJ

并不是说基于 AspectJ 实现的,而仅仅是使用了 AspectJ 中的概念,包括使用的注解也是直接来自于 AspectJ 的包

1
2
3
4
5
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.11</version>
</dependency>

如果是使用 Spring Boot 的话,添加以下依赖即可:

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

首先,我们需要开启 @AspectJ 的注解配置方式:

  • 使用 @EnableAspectJAutoProxy
1
2
3
4
5
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {

}

一旦开启了上面的配置,那么所有使用 @Aspect 注解的 bean 都会被 Spring 当做用来实现 AOP 的配置类,我们称之为一个 Aspect

注意,@Aspect 注解要作用在 bean 上面,不管是使用 @Component 等注解方式,还是在 xml 中配置 bean,首先它需要是一个 bean

有些时候并不需要加这个注解就能使AOP生效,原因是依赖中直接或者间接的引入了 spring-boot-autoconfigure,这是自动装配的依赖,也就是会读取其下的 spring.factories 文件,在该文件中有下面的配置

1
2
3
4
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.**AopAutoConfiguration**

则会加载 AopAutoConfiguration

1
2
3
4
5
6
// Auto-configuration for Spring's AOP support. Equivalent to enabling @EnableAspectJAutoProxy in your configuration.
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
​ ....// 省略
}

默认等同于 @EnableAspectJAutoProxy

  1. 创建一个接口和实现类:
1
2
3
4
5
6
7
8
9
10
11
12
13
// 接口定义
public interface UserService {
void addUser(String username);
}

// 实现类
public class UserServiceImpl implements UserService {
@Override
public void addUser(String username) {
// 模拟添加用户的操作
System.out.println("User added: " + username);
}
}
  1. 创建一个切面类,用于添加横切逻辑,并定义Pointcut表达式:
1
2
3
4
5
6
7
8
9
10
11
12
13
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

// 定义Pointcut表达式,选择com.example.UserService接口的所有方法
@Pointcut("execution(* com.example.UserService.*(..))")
public void userServiceMethods() {}
}

我们看到,@Pointcut 中使用了 execution 来正则匹配方法签名,这也是最常用的,除了 execution,我们再看看其他的几个比较常用的匹配方式:

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
// 任意公共方法的执行:
execution(public * *(..))

// 任何一个名字以“set”开始的方法的执行:
execution(* set*(..))

// AccountService接口定义的任意方法的执行:
execution(* com.xyz.service.AccountService.*(..))

// 在service包中定义的任意方法的执行:
execution(* com.xyz.service.*.*(..))

// 在service包或其子包中定义的任意方法的执行:
execution(* com.xyz.service..*.*(..))

// 在service包中的任意连接点(在Spring AOP中只是方法执行):
within(com.xyz.service.*)

// 在service包或其子包中的任意连接点(在Spring AOP中只是方法执行):
within(com.xyz.service..*)

// 实现了AccountService接口的代理对象的任意连接点 (在Spring AOP中只是方法执行):
this(com.xyz.service.AccountService)// 'this'在绑定表单中更加常用

// 实现AccountService接口的目标对象的任意连接点 (在Spring AOP中只是方法执行):
target(com.xyz.service.AccountService) // 'target'在绑定表单中更加常用

// 任何一个只接受一个参数,并且运行时所传入的参数是Serializable 接口的连接点(在Spring AOP中只是方法执行)
args(java.io.Serializable) // 'args'在绑定表单中更加常用; 请注意在例子中给出的切入点不同于 execution(* *(java.io.Serializable)): args版本只有在动态运行时候传入参数是Serializable时才匹配,而execution版本在方法签名中声明只有一个 Serializable类型的参数时候匹配。

// 目标对象中有一个 @Transactional 注解的任意连接点 (在Spring AOP中只是方法执行)
@target(org.springframework.transaction.annotation.Transactional)// '@target'在绑定表单中更加常用

// 任何一个目标对象声明的类型有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行):
@within(org.springframework.transaction.annotation.Transactional) // '@within'在绑定表单中更加常用

// 任何一个执行的方法有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行)
@annotation(org.springframework.transaction.annotation.Transactional) // '@annotation'在绑定表单中更加常用

// 任何一个只接受一个参数,并且运行时所传入的参数类型具有@Classified 注解的连接点(在Spring AOP中只是方法执行)
@args(com.xyz.security.Classified) // '@args'在绑定表单中更加常用

// 任何一个在名为'tradeService'的Spring bean之上的连接点 (在Spring AOP中只是方法执行)
bean(tradeService)

// 任何一个在名字匹配通配符表达式'*Service'的Spring bean之上的连接点 (在Spring AOP中只是方法执行)
bean(*Service)

此外Spring 支持如下三个逻辑运算符来组合切入点表达式

1
2
3
&&:要求连接点同时匹配两个切入点表达式
||:要求连接点匹配任意个切入点表达式
!::要求连接点不匹配指定的切入点表达式

Spring AOP 用户可能会经常使用 execution 切入点指示符。执行表达式的格式如下:

1
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
  • ret-type-pattern 返回类型模式, name-pattern名字模式和param-pattern参数模式是必选的, 其它部分都是可选的。返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是*它代表了匹配任意的返回类型
  • declaring-type-pattern, 一个全限定的类型名将只会匹配返回给定类型的方法。
  • name-pattern 名字模式匹配的是方法名。 你可以使用*通配符作为所有或者部分命名模式。
  • param-pattern 参数模式稍微有点复杂:()匹配了一个不接受任何参数的方法, 而(..)匹配了一个接受任意数量参数的方法(零或者更多)。 模式()匹配了一个接受一个任何类型的参数的方法。 模式(,String)匹配了一个接受两个参数的方法,第一个可以是任意类型, 第二个则必须是String类型

上面匹配中,通常 “.” 代表一个包名,”..” 代表包及其子包,方法参数任意匹配使用两个点 “..”

  1. 配置 Advice
1
2
3
4
5
6
7
8
9
@Aspect
public class AdviceExample {

// 使用定义的Pointcut,在所有方法执行后添加额外逻辑
@After("com.javadoop.aop.LoggingAspect.userServiceMethods()")
public void logAfterExecution() {
System.out.println("Method execution completed.");
}
}
  1. 创建一个简单的Main类来测试:
1
2
3
4
5
6
7
8
9
10
11
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");

userService.addUser("John Doe");
}
}

在运行Main类时,你将看到类似以下输出:

1
2
User added: John Doe
Method execution completed.

这表明 addUser 方法执行后,切面中定义的 logAfterExecution 方法被调用。使用 Pointcut,你可以更细粒度地控制切入点,而不是直接在特定方法上定义切面逻辑

如果 Advice 方法需要获取入参,Spring 提供了非常简单的获取入参的方法,使用 org.aspectj.lang.JoinPoint 作为 Advice 的第一个参数即可,如:

1
2
3
4
@Before("com.javadoop.aop.LoggingAspect.userServiceMethods()")
public void logArgs(JoinPoint joinPoint) {
System.out.println("方法执行前,打印入参:" + Arrays.toString(joinPoint.getArgs()));
}

注意 org.aspectj.lang.JoinPoint 的使用方法:

  • 必须放置在第一个参数上
  • 如果是 @Around,我们通常会使用其子类 ProceedingJoinPoint,因为它有 procceed()/ procceed(args[]) 方法。

AOP的原理

所以理解Spring AOP的初始化必须要先理解Spring IOC的初始化

基于注解的切面代理创建

这里直接从之前说到的 @EnableAspectJAutoProxy 切入,它 @import 了 AspectJAutoProxyRegistrar.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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) {

// 注册 AspectJAnnotationAutoProxyCreator,如果需要的话
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
... // 省略
}

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry) 这个方法点进去

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
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {

// 注册 AnnotationAwareAspectJAutoProxyCreator.class
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

// 如果名为 org.springframework.aop.config.internalAutoProxyCreator 的 bean 已经在册
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 已经在册的 ProxyCreator 与当前期望的类型不一致,则依据优先级进行选择
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
// 选择优先级高的 ProxyCreator 更新注册
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}

// 没有对应在册的 ProxyCreator,注册一个新的
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}

总结下来就是注册了一个名为 org.springframework.aop.config.internalAutoProxyCreatorBeanDefinition,我们称之为代理创建器(ProxyCreator)。这里使用的默认实现为 AnnotationAwareAspectJAutoProxyCreator.class 类,如果存在多个候选实现,则选择优先级最高的进行注册

然后是 AspectJAutoProxyRegistrar#registerBeanDefinitions 后面省略的部分是:

1
2
3
4
5
6
7
8
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}

这里配置的 proxy-target-classexpose-proxy 属性添加到对应 BeanDefinition 的属性列表中

这是 AnnotationAwareAspectJAutoProxyCreator 的继承关系图:

image-20230721185238617

看得出它实现了两类接口:BeanPostProcessorAware

BeanPostProcessor 接口我们知道在容器启动过程中会在初始化 bean 实例的前后分别调用 BeanPostProcessor 中定义的 postProcessBeforeInitialization()postProcessAfterInitialization() 两个方法。针对这两个方法的实现主要位于继承链的 AbstractAutoProxyCreator 类中,并且主要是实现了 BeanPostProcessor#postProcessAfterInitialization 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 如果 beanName 不为空则直接使用 beanName(FactoryBean 则使用 &{beanName}),否则使用 bean 的 className
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 尝试对 bean 进行增强,创建返回增强后的代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

该方法的核心在于调用 AbstractAutoProxyCreator#wrapIfNecessary 方法,尝试基于 AOP 配置对当前 bean 进行增强,并返回增强后的代理对象。方法 AbstractAutoProxyCreator#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
29
30
31
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 已经处理过,直接返回
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 不需要进行增强的 bean 实例,直接跳过
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 对于 AOP 的基础支撑类,或者指定不需要被代理的类,设置为不进行代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

// Create proxy if we have advice.
// 获取适用于当前 bean 的 Advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 基于获取到的 Advisor 为当前 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());
return proxy;
}

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

上述方法主要的工作是对 bean 实例进行筛选,过滤掉那些已经增强过的、支持 AOP 基础运行的,以及指定不需要被代理的 bean 实例。对于剩下的 bean 实例来说,首先会调用 AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean 方法获取适用于当前 bean 的增强器(Advisor),并基于这些增强器调用 AbstractAutoProxyCreator#createProxy 方法为当前 bean 创建增强后的代理对象

筛选适用于 bean 的增强器

首先来看一下筛选适用于当前 bean 的合格增强器的过程,实现位于 AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean 方法中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 获取适用于当前 bean 的 Advisor
List<Advisor> advisors = this.findEligibleAdvisors(beanClass, beanName);
// 没有合格的 Advisor,不进行代理
if (advisors.isEmpty()) {
return DO_NOT_PROXY; // null
}
return advisors.toArray();
}

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 获取所有候选的 Advisor(包括注解的、XML 中配置的)
List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
// 从所有 Advisor 中寻找适用于当前 bean 的 Advisor
List<Advisor> eligibleAdvisors = this.findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 如果 Advisor 不为空,则在最前面追加一个 ExposeInvocationInterceptor
this.extendAdvisors(eligibleAdvisors);
// 对 Advisor 进行排序
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = this.sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}

整个方法的执行流程很简单,获取所有的候选增强器,并从中找出适用于当前 bean 的增强器。首先来看获取所有候选增强器的过程,实现位于 AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors 方法中:

1
2
3
4
5
6
7
8
9
protected List<Advisor> findCandidateAdvisors() {
// 调用父类的 findCandidateAdvisors 方法,兼容父类查找 Advisor 的规则
List<Advisor> advisors = super.findCandidateAdvisors();
// 获取所有注解定义的 Advisor
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}

方法首先调用了父类的实现,这主要是为了兼容父类查找候选增强器的规则,例如我们的示例中使用的是注解方式定义的增强,但是父类却是基于 XML 配置的方式查找增强器,这里的兼容能够让我们在以注解方式编程时兼容其它以 XML 配置的方式定义的增强。下面还是将主要精力放在解析注解式增强定义上,该过程位于 BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors 方法中。不过该方法实现比较冗长,但是逻辑却很清晰,所以这里主要概括一下其执行流程:

  1. 获取所有类型 bean 实例对应的 beanName 集合;
  2. 过滤不是切面类型的 bean 对应的 beanName,即没有被 @Aspect 注解,或包含以 ajc$ 开头的字段,同时支持覆盖 BeanFactoryAspectJAdvisorsBuilder#isEligibleBean 方法扩展过滤规则;
  3. 对于切面 bean 类型,获取 bean 中定义的所有切点,并为每个切点生成对应的增强器;
  4. 缓存解析得到的增强器,避免重复解析。

上述流程中我们重点看一下过程 3,实现位于 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
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 获取切面 aspect 对应的 class 和 beanName
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
// 校验切面定义的合法性
this.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<>();

// 1. 遍历处理切面中除被 @Pointcut 注解以外的方法
for (Method method : this.getAdvisorMethods(aspectClass)) {
Advisor advisor = this.getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}

// 2. 如果增强器不为空,同时又配置了增强延迟初始化,则需要追加实例化增强器 SyntheticInstantiationAdvisor
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}

// 3. 获取所有引介增强定义
for (Field field : aspectClass.getDeclaredFields()) {
// 创建引介增强器 DeclareParentsAdvisor
Advisor advisor = this.getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}

return advisors;
}

上述实现的整体执行流程如代码注释。拿到一个切面定义,Spring 首先会遍历获取切面中的增强方法,即被 @Around@Before@After@AfterReturning,以及 @AfterThrowing 注解的方法,并调用 ReflectiveAspectJAdvisorFactory#getAdvisor 方法为每一个增强方法生成对应的增强器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public Advisor getAdvisor(Method candidateAdviceMethod,
MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect,
String aspectName) {

// 校验切面类定义的合法性
this.validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

// 获取注解配置的切点信息,封装成 AspectJExpressionPointcut 对象
AspectJExpressionPointcut expressionPointcut = this.getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}

// 依据切点信息生成对应的增强器
return new InstantiationModelAwarePointcutAdvisorImpl(
expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

上述实现首先对当前切面定义执行合法性校验,如果切面配置合法则获取目标方法上的切点注解定义,并封装成 AspectJExpressionPointcut 对象。该过程位于 ReflectiveAspectJAdvisorFactory#getPointcut 方法中,实现比较简单。

拿到切点注解定义之后,方法会依据切点的配置信息使用 InstantiationModelAwarePointcutAdvisorImpl 实现类创建对应的增强器。类 InstantiationModelAwarePointcutAdvisorImpl 的实例化过程除了初始化了一些基本属性之外,主要是调用了 InstantiationModelAwarePointcutAdvisorImpl#instantiateAdvice 方法,依据增强类型对增强器实施相应的初始化操作:

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

// org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
public Advice getAdvice(Method candidateAdviceMethod,
AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrder,
String aspectName) {

// 获取切面 class 对象,并校验切面定义
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
this.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 (!this.isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" + candidateAspectClass.getName() + "]");
}

AbstractAspectJAdvice springAdvice;

// 依据切点注解类型使用对应的增强类进行封装
switch (aspectJAnnotation.getAnnotationType()) {
// @Pointcut
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
// @Around
case AtAround:
springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
// @Before
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
// @After
case AtAfter:
springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
// @AfterReturning
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
// @AfterThrowing
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;
}

方法的整体执行流程如代码注释,逻辑比较清晰,Spring 会依据具体的增强注解类型,选择相应的增强类对切点定义进行封装。这里我们以 @Before 为例说明一下增强的执行流程,AspectJMethodBeforeAdvice 增强类关联注册的处理器是 MethodBeforeAdviceInterceptor,当我们调用一个被前置增强的目标方法时,MethodBeforeAdviceInterceptor#invoke 方法会被触发:

1
2
3
4
5
6
public Object invoke(MethodInvocation mi) throws Throwable {
// 执行增强方法
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
// 执行目标方法
return mi.proceed();
}

这里执行的增强方法就对应着 AspectJMethodBeforeAdvice#before 方法,该方法会依据切点配置将相应的参数绑定传递给我们自定义的增强方法,并最终通过反射调用触发执行。

上面分析了普通方法级别增强的处理过程,对于另外一类增强(引介增强),方法 ReflectiveAspectJAdvisorFactory#getAdvisors 则使用专门的 DeclareParentsAdvisor 类创建对应的增强器:

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
// 3. 获取所有引介增强定义
for (Field field : aspectClass.getDeclaredFields()) {
// 创建引介增强器
Advisor advisor = this.getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}

private Advisor getDeclareParentsAdvisor(Field introductionField) {
// 获取 @DeclareParents 注解定义
DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class);
if (declareParents == null) {
return null;
}

// 没有指定默认的接口实现类
if (DeclareParents.class == declareParents.defaultImpl()) {
throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents");
}

// 使用 DeclareParentsAdvisor 类型创建对应的引介增强器
return new DeclareParentsAdvisor(
introductionField.getType(), declareParents.value(), declareParents.defaultImpl());
}

对于引介增强来说,Spring 会注入 DelegatePerTargetObjectIntroductionInterceptor 处理器对其进行专门的处理,思想上与前面分析前置增强大同小异,这里不再展开。

继续回到 AbstractAdvisorAutoProxyCreator#findEligibleAdvisors 方法,上面的过程我们分析了获取所有类型增强器的过程,但是这些增强器不一定都适用于当前 bean 实例,我们需要依据切点配置信息对其进行筛选。这一过程位于 AbstractAdvisorAutoProxyCreator#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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
} finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}

// org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
// 没有候选的增强器,直接返回
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();

// 1. 筛选引介增强器
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
// 表示是否含有引介增强
boolean hasIntroductions = !eligibleAdvisors.isEmpty();

// 2. 筛选其它类型的增强器
for (Advisor candidate : candidateAdvisors) {
// 引介增强已经处理过,这里直接跳过
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 筛选其它类型的增强器
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}

方法首先会使用类过滤器(ClassFilter)筛选引介增强器,除了我们手动注册的类过滤器外,这里默认还会使用 TypePatternClassFilter 类过滤器执行过滤操作。然后,方法会过滤筛选其它类型的增强器,这里除了使用类过滤器外,考虑方法级别增强的定义形式,还会使用方法匹配器(MethodMatcher)进行筛选。如果增强器适用于当前 bean 类型,则将其加入到集合中用于下一步为当前 bean 创建增强代理对象。如果没有任何一个增强器适用于当前 bean 类型,则方法 AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean 最终会返回值为 null 的 DO_NOT_PROXY 数组对象,表示当前 bean 不需要被增强。

为 bean 创建增强代理对象

完成了对于当前 bean 增强器的筛选,接下来我们继续回到 AbstractAutoProxyCreator#wrapIfNecessary 方法,看一下基于前面筛选出的增强器为当前 bean 创建增强代理对象的过程,实现位于 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
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 用于为目标 bean 实例创建代理对象
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);

// proxy-target-class = false,表示使用 JDK 原生动态代理
if (!proxyFactory.isProxyTargetClass()) {
// 检测当前 bean 是否应该基于类而非接口生成代理对象,即包含 preserveTargetClass=true 属性
if (this.shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
// 如果是基于接口生成代理,则添加需要代理的接口到 ProxyFactory 中(除内置 callback 接口、语言内在接口,以及标记接口)
else {
this.evaluateProxyInterfaces(beanClass, proxyFactory);
}
}

// 将拦截器封装成 Advisor 对象
Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
// 模板方法,定制代理工厂
this.customizeProxyFactory(proxyFactory);

// 设置代理工厂被配置之后是否还允许修改,默认为 false,表示不允许修改
proxyFactory.setFrozen(this.freezeProxy);
if (this.advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}

// 基于 ProxyFactory 创建代理类
return proxyFactory.getProxy(this.getProxyClassLoader());
}

方法的执行流程如代码注释。下面我们主要分析将拦截器封装成 Advisor 对象的过程,以及基于 ProxyFactory 创建增强代理对象的过程。

Spring 定义了非常多的拦截器、增强器,以及增强方法等,这里通过 AbstractAutoProxyCreator#buildAdvisors 方法统一将他们封装成 Advisor 对象,从而简化代理的创建过程。封装的核心步骤由 DefaultAdvisorAdapterRegistry#wrap 方法实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
// 已经是 Advisor,则无需多做处理
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
// 要求必须是 Advice 类型
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
// 如果是 MethodInterceptor,则直接使用 DefaultPointcutAdvisor 进行包装
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
// 否则遍历注册的适配器,如果存在关联的适配器则使用 DefaultPointcutAdvisor 进行包装
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}

接下来我们重点分析一下通过代理工厂 ProxyFactory 创建增强代理对象的过程,实现位于 ProxyFactory#getProxy 方法中:

1
2
3
4
public Object getProxy(@Nullable ClassLoader classLoader) {
return this.createAopProxy() // 1. 创建 AOP 代理
.getProxy(classLoader); // 2. 基于 AOP 代理创建目标类的增强代理对象
}

该方法的执行过程可以拆分成两个步骤:

  1. 创建 AOP 代理,Spring 默认提供了两种 AOP 代理实现,即 java 原生代理和 CGLib 代理;
  2. 基于 AOP 代理创建目标类的增强代理对象。

我们首先来看一下步骤 1 的实现,位于 ProxyCreatorSupport#createAopProxy 方法中:

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
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
this.activate();
}
return this.getAopProxyFactory().createAopProxy(this);
}

// org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() // 需要对代理策略进行优化
|| config.isProxyTargetClass() // // 指定使用 CGLib 生成代理对象
|| this.hasNoUserSuppliedProxyInterfaces(config)) // 当前类没有接口定义,不得不使用 CGLib
{
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.");
}
// 目标类是接口或代理类,使用 JDK 原生代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 使用 CGLib 动态代理
return new ObjenesisCglibAopProxy(config);
}
// 使用 JDK 原生动态代理
else {
return new JdkDynamicAopProxy(config);
}
}

这部分代码清晰说明了 Spring 在生成代理对象时如何在 java 原生代理和 CGLib 代理之间进行选择,可以概括如下:

  1. 如果目标类实现了接口,则 Spring 默认会使用 java 原生代理。
  2. 如果目标类未实现接口,则 Spring 会使用 CGLib 生成代理。
  3. 如果目标类实现了接口,但是在配置时指定了 proxy-target-class=true,则使用 CGLib 生成代理。

下面分别对基于 java 原生代理和 CGLib 代理生成增强代理对象的过程进行分析。

基于 Java 原生代理创建增强代理对象

首先来看一下基于 Java 原生代理生成增强代理对象的过程,位于 JdkDynamicAopProxy 类中。Java 原生代理要求代理类实现 InvocationHandler 接口,并在 InvocationHandler#invoke 方法中实现代理增强逻辑。JdkDynamicAopProxy 正好实现了该接口,对应的 JdkDynamicAopProxy#invoke 方法实现如下:

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
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;

TargetSource targetSource = this.advised.targetSource;
Object target = null;

try {
// 当前是 equals 方法,但是被代理类接口中未定义 equals 方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return this.equals(args[0]);
}
// 当前是 hashCode 方法,但是被代理类接口中未定义 hashCode 方法
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return this.hashCode();
}
// 如果是 DecoratingProxy 中定义的方法(即 DecoratingProxy#getDecoratedClass),直接返回目标类对象
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
} else if (!this.advised.opaque // 允许被转换成 Advised 类型
&& method.getDeclaringClass().isInterface() // 接口类型
&& method.getDeclaringClass().isAssignableFrom(Advised.class)) // 方法所在类是 Advised 类及其父类
{
// 直接反射调用该方法
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}

// 结果值
Object retVal;

// 指定内部间调用也需要代理
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);

// 获取当前方法的拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
// 拦截器链为空,则直接反射调用增强方法
if (chain.isEmpty()) {
// 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 = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
// 否则需要创建对应的 MethodInvocation,以链式调用拦截器方法和增强方法
else {
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}

// 处理返回值
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method is type-compatible.
// Note that we can't help if the target sets a reference to itself in another returned object.
retVal = proxy;
} else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
} finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

由上述方法实现,我们可以概括出整个增强代理的执行过程,如下:

  1. 特殊处理 Object#equalsObject#hashCodeDecoratingProxy#getDecoratedClass,以及 Advised 类及其父类中定义的方法;
  2. 如果配置了 expose-proxy 属性,则记录当前代理对象,以备在内部间调用时实施增强;
  3. 获取当前方法的拦截器链;
  4. 如果没有拦截器定义,则直接反射调用增强方法,否则先逐一执行拦截器方法,最后再应用增强方法;
  5. 处理返回值。

重点来看一下步骤 4 中应用拦截器方法的实现,位于 ReflectiveMethodInvocation#proceed 方法中:

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
public Object proceed() throws Throwable {
// 如果所有的增强都执行完成,则执行增强方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return this.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 {
return this.proceed();
}
}
// 静态拦截器,直接应用拦截方法
else {
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}

拦截器方法的执行流程如上述代码注释,是一个递归调用的过程,并在最后应用增强方法。

完成了对于 AOP 代理对象 JdkDynamicAopProxy 的创建,最后来看一下获取该对象的过程,实现位于 JdkDynamicAopProxy#getProxy 方法中:

1
2
3
4
5
6
7
8
public Object getProxy(@Nullable ClassLoader classLoader) {
// 获取需要被代理的接口集合
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
// 检测是否在被代理接口中声明了 equals 和 hashCode 方法
this.findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 基于 Java 原生代理生成代理对象
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

这里的逻辑也就是 Java 原生代理的模板代码,如果对 Java 代理比较熟悉的话,应该不难理解

基于 CGLib 代理创建增强代理对象

基于 CGLib 代理生成增强代理对象的过程位于 ObjenesisCglibAopProxy 类中,该类继承自 CglibAopProxy 类。获取 CGLib 代理类对象的方法定义在 CglibAopProxy 中,即 CglibAopProxy#getProxy 方法。该方法基于 CGLib 的 Enhancer 类创建代理对象,属于 CGLib 的标准使用模式,因为有多个 callback 实现,所以这里使用了 CallbackFilter 模式,依据场景选择并应用对应的 callback 拦截器。

我们重点关注 callback 的实现,位于 CglibAopProxy#getCallbacks 方法中。受制于 CGLib 在执行时一次只允许应用一个 callback 的约束,所以该方法依据参数配置实现了一组 callback,以覆盖不同的场景。核心的 AOP callback 实现是 DynamicAdvisedInterceptor 类,它实现了 MethodInterceptor 接口,对应的 DynamicAdvisedInterceptor#intercept 方法实现如下:

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

// 获取当前方法的拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 结果值
Object retVal;
// Check whether we only have one InvokerInterceptor:
// that is, no real advice, but just reflective invocation of the target.
// 拦截器链为空,则直接反射调用增强方法
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);
}
// 否则需要创建对应的 MethodInvocation,以链式调用拦截器方法和增强方法
else {
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);
}
}
}

可以看出上述方法在实现流程上与前面介绍的 JdkDynamicAopProxy#invoke 方法是一致的,只是这里是基于 CGLib 实现

参考 https://my.oschina.net/wangzhenchao/blog/4279608

总结

  1. @EnableAspectJAutoProxy 开启AOP功能
  2. @EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
  3. AnnotationAwareAspectJAutoProxyCreator 是一个 InstantiationAwareBeanPostProcessor 类型后置处理器,功能可以概括为:
    1. 从容器中获取所有的切面定义
    2. 筛选适用于当前 bean 的增强器集合
    3. 依据增强器集合基于动态代理机制生成相应的增强代理对象

Spring AOP 的实现本质上是一个动态代理的过程,Spring 引入了 Java 原生代理和 CGLib 代理,并依据场景选择基于哪种代理机制对目标对象进行增强。Spring 容器在完成对 bean 对象的创建之后会执行初始化操作,而 AOP 初始化的过程就发生在 bean 的后置初始化阶段


代理 Proxy 反射 Reflect 与 Spring AOP
https://sugayoiya.github.io/posts/59835.html
作者
Sugayoiya
发布于
2021年8月1日
许可协议