术语
- 连接点
Join Point
java 运行过程中的位置,对于Spring
来说,表示允许使用切面的位置,它一般是指方法运行的过程,比如运行前,运行后,抛出异常等。 - 通知
Advice
在某连接点上执行的特殊操作 - 切入点
PointCut
切入点通过表达式来连接通知和连接点,确定连接点是否符合切入点表达式 - 目标类
Target
被切面切入的类 - 代理类
AOP proxy
实现切面的方式即实现目标类的代理类对象,对于Spring
来说,通过JDK
动态代理和CGLIB
字节码代理 - 织入
Weaving
把切面应用到目标对象来创建新的代理对象的过程
JDK
动态代理
JDK
动态代理仅支持代理接口(因为代理类继承Proxy
,而java
不支持多继承)。 由JDK
动态生成继承接口的子类,子类的所有方法调用都由创建代理类时使用的参数java.lang.reflect.InvocationHandler
的invoke
方法去完成。
1 | package com.li.springboot.aop; |
下面是自动生成的代理类反编译的源码
1 | // |
我们可以看到实际所有方法的调用都由InvocationHandler
去调用,我们查看下Proxy.newProxyInstance
的细节
1 | public static Object newProxyInstance(ClassLoader loader, |
1 | private static final WeakCache<ClassLoader, Class<?>[], Class<?>> |
1 | public V get(K key, P parameter) { |
通过断点debug
,我们可以得出supplier
的类为class java.lang.reflect.WeakCache$Factory
,查看其get
方法,
1 | public synchronized V get() { // serialize access |
查看ProxyClassFactory
的apply
方法,
1 |
|
1 | private final static boolean saveGeneratedFiles =java.security.AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles")).booleanValue(); |
1 | private byte[] generateClassFile() { |
1 | /** |
为接口实现一个默认类
1 | static <T> T beanInstance(Class<T> _interface, Object ... args) { |
InvocationHandler 针对 void 方法,可以直接返回 null
CGLIB
字节码代理
示例
1 | import org.springframework.cglib.proxy.Enhancer; |
反编译生成的字节码
1 | // |
具体实现细节类似JDK
动态代理,通过某种方式生成字节码文件。
Spring
使用AOP
通过BeanPostProcessor
返回动态代理的bean
,
1 |
|
1 |
|