Spring AOP源码分析(二)创建代理对象

Posted by YiBo on November 12, 2020

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

image-20201112160313588

image-20201112160611889

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 的动态代理