1. 前记
上一篇文章中,分析了 Spring 是如何为目标 bean 筛选合适的通知器的
接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 bean 的某些方法前后
2. 背景知识
2.1 proxy-target-class
1
2
3
4
5
6
7
<aop:aspectj-autoproxy proxy-target-class="true"/>
<aop:config proxy-target-class="true">
<aop:aspect id="xxx" ref="xxxx">
<!-- 省略 -->
</aop:aspect>
</aop:config>
默认情况下 proxy-target-class 属性为 false。当目标 bean 实现了接口时,Spring 会基于 JDK 动态代理为目标 bean 创建代理对象。若未实现任何接口,Spring 则会通过 CGLIB 创建代理。而当 proxy-target-class 属性设为 true 时,则会强制 Spring 通过 CGLIB 的方式创建代理对象,即使目标 bean 实现了接口。
2.2 动态代理
2.2.1 基于 JDK 的动态代理
1
2
3
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
简单说一下上面的参数列表:
- loader - 类加载器
- interfaces - 目标类所实现的接口列表
- h - 用于封装代理逻辑
JDK 动态代理只能为实现了接口的目标类生成代理对象
举个例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface UserService {
void save(User user);
void update(User user);
}
public class UserServiceImpl implements UserService {
@Override
public void save(User user) {
System.out.println("save user info");
}
@Override
public void update(User user) {
System.out.println("update user info");
}
}
2.2.2 基于 CGLIB 的动态代理
当我们要为未实现接口的类生成代理时,就无法使用 JDK 动态代理了。那么此类的目标对象生成代理时应该怎么办呢?当然是使用 CGLIB 了。
这里作者举了个很有意思的例子
1
2
3
4
5
6
7
8
9
10
public class Tank59 {
void run() {
System.out.println("极速前行中....");
}
void shoot() {
System.out.println("轰...轰...轰...轰...");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class CglibProxyCreator implements ProxyCreator {
private Object target;
private MethodInterceptor methodInterceptor;
public CglibProxyCreator(Object target, MethodInterceptor methodInterceptor) {
assert (target != null && methodInterceptor != null);
this.target = target;
this.methodInterceptor = methodInterceptor;
}
@Override
public Object getProxy() {
Enhancer enhancer = new Enhancer();
// 设置代理类的父类
enhancer.setSuperclass(target.getClass());
// 设置代理逻辑
enhancer.setCallback(methodInterceptor);
// 创建代理对象
return enhancer.create();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class TankRemanufacture implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if (method.getName().equals("run")) {
System.out.println("正在重造59坦克...");
System.out.println("重造成功,已获取 ✨59改 之 超音速飞行版✨");
System.out.print("已起飞,正在突破音障。");
methodProxy.invokeSuper(o, objects);
System.out.println("已击落黑鸟 SR-71,正在返航...");
return null;
}
return methodProxy.invokeSuper(o, objects);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class CglibProxyCreatorTest {
@Test
public void getProxy() throws Exception {
ProxyCreator proxyCreator = new CglibProxyCreator(new Tank59(), new TankRemanufacture());
Tank59 tank59 = (Tank59) proxyCreator.getProxy();
System.out.println("proxy class = " + tank59.getClass() + "\n");
tank59.run();
System.out.println();
System.out.print("射击测试:");
tank59.shoot();
}
}
3. 总结
我省略了作者的源码分析,看的不是很明白
但核心思想是在advisor中,找到构建proxy的东西,比如 classLoader Interface invoke 或者是 class MehtodInterceptor 来构建最终的proxy类
这篇文章主要了解到java中创建代理的俩种模式: JDK 和 CGLIB 的动态代理