一、相关概念
1、JDK 动态代理原理
- 使用拦截器 (需要实现 InvocationHandler 接口) 加上反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用
invoke()
方法来进行处理
2、CGLIB 动态代理原理
- 使用 ASM 字节码框架 (需要实现 MethodInterceptor 接口),加载代理对象类的 Class 文件,通过修改其字节码生成子类来进行处理
3、什么时候使用 JDK 动态代理、CGLIB 动态代理?
-
如果目标对象实现了接口,默认情况下会使用 JDK 动态代理来实现 AOP,可以强制使用 CGLIB 来实现 AOP
-
如果目标对象没有实现接口,则必须使用 CGLIB 动态代理,Spring 会在 JDK 动态代理和 CGLIB 动态代理之间自动切换
4、如何强制使用 CGLIB 动态代理实现 AOP?
-
XML 文件
<aop:aspectj-autoproxy proxy-target-class="true"/>
-
application.yml 文件
spring: aop: proxy-target-class: true
5、JDK 动态代理和 CGLIB 动态代理的区别
-
JDK 动态代理只能针对实现了接口的类生成代理,而不能针对普通类
-
CGLIB 动态代理针对类 (不能用 final 进行修饰) 生成代理,通过生成目标类的子类,并覆盖目标类的方法来实现增强
6、JDK 动态代理和 CGLIB 动态代理谁更快?
-
在 JDK6 和 JDK7 版本时,JDK 动态代理的速度要比 CGLIB 动态代理慢
-
从 JDK8 开始,JDK 动态代理的速度要比 CGLIB 动态代理快
二、代码示例
-
UserService 接口,供 JDK 动态代理使用
public interface UserService { void addUser(String username, String password); }
-
UserServiceImpl 实现类,实现 UserService 接口,供 CGLIB 动态代理使用
public class UserServiceImpl implements UserService { @Override public void addUser(String username, String password) { System.out.println("调用了 UserServiceImpl 类的 addUser() 方法"); } }
-
CGLIB 动态代理
public class CGLIBProxy implements MethodInterceptor { /** * 需要代理的目标对象 */ private Object targetObj; /** * 获取代理对象 */ public Object newProxy(Object targetObj) { this.targetObj = targetObj; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(targetObj.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { // 过滤方法 if ("addUser".equals(method.getName())) { checkPermissions(); } return method.invoke(targetObj, args); } private void checkPermissions() { System.out.println("检查用户权限 checkPermissions"); } }
-
JDK 动态代理
public class JDKProxy implements InvocationHandler { /** * 需要代理的目标对象 */ private Object targetObj; /** * 获取代理对象 */ public Object newProxy(Object targetObj) { this.targetObj = targetObj; Class<?> clazz = targetObj.getClass(); return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 检查权限 checkPermissions(); return method.invoke(targetObj, args); } private void checkPermissions() { System.out.println("检查用户权限 checkPermissions"); } }
-
进行测试
public class ProxyTest { public static void main(String[] args) { System.out.println("================ CGLIB动态代理 ================"); CGLIBProxy cglibProxy = new CGLIBProxy(); UserServiceImpl cglib = (UserServiceImpl) cglibProxy.newProxy(new UserServiceImpl()); cglib.addUser("tom", "root"); System.out.println("================ JDK动态代理 ================"); JDKProxy jdkProxy = new JDKProxy(); UserService jdk = (UserService) jdkProxy.newProxy(new UserServiceImpl()); jdk.addUser("tom", "root"); } }
-
测试结果
-
去除 UserServiceImpl 类实现 UserService 接口 (即此时 UserServiceImpl 是一个普通类),再进行测试
public class UserServiceImpl { public void addUser(String username, String password) { System.out.println("调用了 UserServiceImpl 类的 addUser() 方法"); } }
-
测试结果