JDK和CGLIB动态代理

AOP是spring的一个重要组成部分,而AOP通过代理实现。这儿写下JDK代理和CGLIB代理两种动态代理,为接下来的Spring AOP做准备。

JDK代理:

1)项目整体结构如下:

JDK和CGLIB动态代理

 

2)创建maven项目,pom.xml如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zby</groupId>
    <artifactId>aop</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/cglib/cglib -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.5</version>
        </dependency>
    </dependencies>
</project>

这个依赖主要是给CGLIB用的,JDK代理并不需要。

3)创建UserService接口:

1
2
3
4
5
6
package com.zby.service;
 
public interface UserService {
 
    void saveUser(String username, String password);
}

4)创建UserService接口实现类UserServiceImpl:

1
2
3
4
5
6
7
8
9
10
11
package com.zby.service.impl;
 
import com.zby.service.UserService;
 
public class UserServiceImpl implements UserService {
 
    public void saveUser(String username, String password) {
        System.out.println("save user[username=" + username + ",password=" + password + "]");
    }
 
}

5)创建CustomAspect切面类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.zby.aspect;
 
public class CustomAspect {
 
    public void startTransaction() {
        System.out.println("I get datasource here and start transaction");
    }
 
 
 
    public void endTrasaction() {
        System.out.println("I get datasource here and end transaction");
    }
}

6)创建JDKProxy代理工厂:

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
package com.zby.factory;
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
 
import com.zby.aspect.CustomAspect;
 
public class JDKProxy {
 
    public static Object createProxy(final Object targetObj, final CustomAspect customAspect) {
        // 使用JDK的Proxy类为目标类创建代理对象
        return Proxy.newProxyInstance(
                // 目标类使用的类加载器
                targetObj.getClass().getClassLoader(),
                // 目标类实现的接口
                targetObj.getClass().getInterfaces(),
                // 执行处理器,代理我们的业务逻辑
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 执行切面方法
                        customAspect.startTransaction();
                        // 具体逻辑代码执行,返回值为方法执行结果
                        Object result = method.invoke(targetObj, args);
                        // 执行切面方法
                        customAspect.endTrasaction();
                        // 返回方法执行结果
                        return result;
                    }
                });
    }
}

  

7)编写测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.zby.test;
 
import org.junit.Test;
 
import com.zby.aspect.CustomAspect;
import com.zby.factory.JDKProxy;
import com.zby.service.UserService;
import com.zby.service.impl.UserServiceImpl;
 
public class JDKProxyTest {
    @Test
    public void testJDKProxy() {
        System.out.println("before Proxy......");
        UserService userService = new UserServiceImpl();
        userService.saveUser("zby""1234567890");
        System.out.println("After Proxy......");
        UserService proxyUserService = (UserService)JDKProxy.createProxy(userService, new CustomAspect());
        proxyUserService.saveUser("zby""1234567890");
    }
}

8)控制台打印结果:

1
2
3
4
5
6
before Proxy......
save user[username=zby,password=1234567890]
After Proxy......
I get datasource here and start transaction
save user[username=zby,password=1234567890]
I get datasource here and end transaction

CGLIB代理:

1)使用JDK代理创建的UserService接口,UserServiceImpl实现类和CustomAspect切面类。

2)创建CGLIB的代理类CGLIBProxy:

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
package com.zby.factory;
 
import java.lang.reflect.Method;
 
import com.zby.aspect.CustomAspect;
 
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
 
public class CGLIBProxy {
 
    public static Object createProxy(final Object targetObj, final CustomAspect customAspect) {
        Enhancer enhancer = new Enhancer();
        // 设置需要代理的父类
        enhancer.setSuperclass(targetObj.getClass());
        // 设置回调
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)
                    throws Throwable {
                // 执行切面方法
                customAspect.startTransaction();
                // 具体逻辑代码执行,返回值为方法执行结果
                Object result = methodProxy.invokeSuper(proxy, args);
                // 执行切面方法
                customAspect.endTrasaction();
                // 返回方法执行结果
                return result;
            }
        });
        // 3.4 创建代理
        return enhancer.create();
    }
}

3)编写测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.zby.test;
 
import org.junit.Test;
 
import com.zby.aspect.CustomAspect;
import com.zby.factory.CGLIBProxy;
import com.zby.service.UserService;
import com.zby.service.impl.UserServiceImpl;
 
public class CGLIBProxyTest {
    @Test
    public void testJDKProxy() {
        System.out.println("before Proxy......");
        UserService userService = new UserServiceImpl();
        userService.saveUser("zby""1234567890");
        System.out.println("After Proxy......");
        UserService proxyUserService = (UserService) CGLIBProxy.createProxy(userService, new CustomAspect());
        proxyUserService.saveUser("zby""1234567890");
    }
}

4)控制台打印结果:

1
2
3
4
5
6
before Proxy......
save user[username=zby,password=1234567890]
After Proxy......
I get datasource here and start transaction
save user[username=zby,password=1234567890]
I get datasource here and end transaction

 5)CGLIB代理和JDK代理最大的区别就是:CGLIB代理的对象不需要实现任何接口,它使用的字节码技术创建子类实例,但是JDK代理的对象必须实现接口。这儿使用CGLIB代理的时候,可以将UserService删除,使用UserServiceImpl接收代理结果,效果完全一样。

  CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。