Spring源码-Aspect-前置知识-Java动态代理

总结摘要
Spring AOP Aspect 前置知识 Java动态代理

Java 动态代理

基于JDK实现动态代理

基于JDK来实现动态代理主要用到了java.lang.reflect.InvocationHandler接口和java.lang.reflect.Proxy类。

 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
{
    public static void main(String[] args) {
        testJdkProxy();
    }

    /**
     * log start time [Tue Oct 07 16:09:48 CST 2025]
     * 查询 selectById
     * log end time [Tue Oct 07 16:09:48 CST 2025]
     * log start time [Tue Oct 07 16:09:48 CST 2025]
     * 更新 update
     * log end time [Tue Oct 07 16:09:48 CST 2025]
     */
    public static void testJdkProxy() {
        UserServiceImpl userServiceImpl = new UserServiceImpl();
        ClassLoader classLoader = userServiceImpl.getClass().getClassLoader();
        Class<?>[] interfaces = userServiceImpl.getClass().getInterfaces();
        java.lang.reflect.InvocationHandler logHandler = new LogHandler(userServiceImpl);
        UserService proxy = (UserService) java.lang.reflect.Proxy.newProxyInstance(classLoader, interfaces, logHandler);
        // 调用代理的方法
        proxy.select();
        proxy.update();

    }
}

interface UserService {
    void select();
    void update();
}

class UserServiceImpl implements UserService {
    public void select() {
        System.out.println("查询 selectById");
    }
    public void update() {
        System.out.println("更新 update");
    }
}

class LogHandler implements java.lang.reflect.InvocationHandler {
    Object target;  // 被代理的对象,实际的方法执行者

    public LogHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(target, args);
        after();
        return result;
    }
    private void before() {
        System.out.println(String.format("log start time [%s] ", new Date()));
    }
    private void after() {
        System.out.println(String.format("log end time [%s] ", new Date()));
    }
}

动态代理类具有哪些方法,只跟接口有关,跟原始类没有任何关系。这也是基于JDK实现的动态代理,要求原始类必须有接口定义才行的原因。

静态代理类的类名是程序员指定的,动态代理类的类名是自动生成的。动态代理类的类名由2部分构成:$Proxy+自增编号。比如,如果项目中使用Proxy类生成了两个动态代理类,那么,它们的名称就分别为:$Proxy0、$Proxy1。

基于CGLIB实现动态代理

基于CGLIB实现动态代理,需要用到一个核心接口MethodInterceptor和一个核心类Enhancer,它们的用法跟JDK中的InvocationHandler接口和Proxy类相似。

实际上,为了优化性能,CGLIB可以不使用Java反射来执行方法,如下代码所示。MethodProxy的invokeSuper()方法底层依赖CGLIB自己实现的反射(即net.sf.cglib.reflect.FastClass)来执行方法。不过,即便如此,两种动态代理实现方式的性能仍然相差无几。

原生 Cglib

 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
{
    public static void main(String[] args) {
        testCglibNative();
    }

    /**
     * log start time [Tue Oct 07 15:36:32 CST 2025]
     * UserDao 更新 update
     * log end time [Tue Oct 07 15:36:32 CST 2025]
     * log start time [Tue Oct 07 15:36:32 CST 2025]
     * UserDao 查询 selectById
     * log end time [Tue Oct 07 15:36:32 CST 2025] 
     */
    public static void testCglibNative() {
        LogInterceptorCglibNative daoProxy = new LogInterceptorCglibNative();
        net.sf.cglib.proxy.Enhancer enhancer = new net.sf.cglib.proxy.Enhancer();
        enhancer.setSuperclass(UserDao.class);  // 设置超类,cglib是通过继承来实现的
        enhancer.setCallback(daoProxy);

        UserDao dao = (UserDao)enhancer.create();   // 创建代理类
        dao.update();
        dao.select();
    }
}

class UserDao {
    public void select() {
        System.out.println("UserDao 查询 selectById");
    }
    public void update() {
        System.out.println("UserDao 更新 update");
    }
}

class LogInterceptorCglibNative implements net.sf.cglib.proxy.MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, net.sf.cglib.proxy.MethodProxy methodProxy) throws Throwable {
        before();
        Object result = methodProxy.invokeSuper(o, objects);
        after();
        return result;
    }
    private void before() {
        System.out.println(String.format("log start time [%s] ", new Date()));
    }
    private void after() {
        System.out.println(String.format("log end time [%s] ", new Date()));
    }
}

使用CGLIB需要先在项目中引入CGLIB包,Maven配置如下所示。

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>3.3.0</version>
</dependency>

Spring Cglib

 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
{

    public static void main(String[] args) {
        testCglibSpring();
    }

    /**
     * log start time [Tue Oct 07 15:39:04 CST 2025]
     * UserDao 更新 update
     * log end time [Tue Oct 07 15:39:04 CST 2025]
     * log start time [Tue Oct 07 15:39:04 CST 2025]
     * UserDao 查询 selectById
     * log end time [Tue Oct 07 15:39:04 CST 2025]
     */
    public static void testCglibSpring() {
        LogInterceptorCglibSpring daoProxy = new LogInterceptorCglibSpring();
        org.springframework.cglib.proxy.Enhancer enhancer = new org.springframework.cglib.proxy.Enhancer();
        enhancer.setSuperclass(UserDao.class);  // 设置超类,cglib是通过继承来实现的
        enhancer.setCallback(daoProxy);

        UserDao dao = (UserDao)enhancer.create();   // 创建代理类
        dao.update();
        dao.select();
    }
}

class UserDao {
    public void select() {
        System.out.println("UserDao 查询 selectById");
    }
    public void update() {
        System.out.println("UserDao 更新 update");
    }
}

class LogInterceptorCglibSpring implements org.springframework.cglib.proxy.MethodInterceptor {
    @Override
    public Object intercept(Object object, java.lang.reflect.Method method, Object[] objects, org.springframework.cglib.proxy.MethodProxy methodProxy) throws Throwable {
        before();
        // 注意这里是调用 invokeSuper 而不是 invoke,否则死循环,methodProxy.invokesuper执行的是原始类的方法,method.invoke执行的是子类的方法
        Object result = methodProxy.invokeSuper(object, objects);
        after();
        return result;
    }
    private void before() {
        System.out.println(String.format("log start time [%s] ", new Date()));
    }
    private void after() {
        System.out.println(String.format("log end time [%s] ", new Date()));
    }
}

需引入 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
{
    public static void main(String[] args) {
        testCglibReflect();
    }

    /**
     * log start time [Tue Oct 07 15:58:34 CST 2025] 
     * UserDao 查询 selectById
     * log end time [Tue Oct 07 15:58:34 CST 2025] 
     * log start time [Tue Oct 07 15:58:34 CST 2025] 
     * UserDao 更新 update
     * log end time [Tue Oct 07 15:58:34 CST 2025] 
     */
    public static void testCglibReflect() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserDao.class);
        enhancer.setCallback(new ProxyFactory(new UserDao()));
        
        UserDao userDaoProxy = (UserDao) enhancer.create();
        userDaoProxy.select();
        userDaoProxy.update();
    }
}

class UserDao {
    public void select() {
        System.out.println("UserDao 查询 selectById");
    }
    public void update() {
        System.out.println("UserDao 更新 update");
    }
}

class ProxyFactory implements MethodInterceptor {
    private Object origBean;

    public ProxyFactory(Object origBean) {
        this.origBean = origBean;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)
            throws Throwable {
        before();
        Object result = method.invoke(origBean, objects);
        after();
        return result;
    }
    private void before() {
        System.out.println(String.format("log start time [%s] ", new Date()));
    }
    private void after() {
        System.out.println(String.format("log end time [%s] ", new Date()));
    }
}

参考文章

Java 动态代理详解

http://juejin.cn/post/6844903744954433544

Java | JDK 动态代理的原理其实很简单

http://juejin.cn/post/6974018412158664734

深入理解 Java 反射和动态代理

https://juejin.cn/post/6844903807755747342

END