JDK|JDK 动态代理与 CGLIB 动态代理,它俩真的不一样

摘要:一文带你搞懂JDK 动态代理与 CGLIB 动态代理
本文分享自华为云社区《一文带你搞懂JDK 动态代理与 CGLIB 动态代理》,作者: Code皮皮虾 。
两者有何区别 1、Jdk动态代理:利用拦截器(必须实现InvocationHandler接口)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理
2、 Cglib动态代理:利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来进行代理
所以:
  • 如果想要实现JDK动态代理那么代理类必须实现接口,否则不能使用;
  • 如果想要使用CGlib动态代理,那么代理类不能使用final修饰类和方法;
还有: 在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点,但是到jdk8的时候,jdk代理效率高于CGLIB代理。
如何实现 JDK动态代理
JDK|JDK 动态代理与 CGLIB 动态代理,它俩真的不一样
文章图片

UserService接口
public interface UserService {void addUser(); void updateUser(String str); }

UserServiceImpl实现类
public class UserServiceImpl implements UserService { @Override public void addUser() { System.out.println("添加用户"); }@Override public void updateUser(String str) { System.out.println("更新用户信息" + str); } }

UserProxy代理类,实现InvocationHandler接口重写invoke方法
public class UserProxy implements InvocationHandler { private Object target; public UserProxy(Object target) { this.target = target; }@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object res = method.invoke(target, args); System.out.println("记录日志"); return res; } }

test测试类
public class test { public static void main(String[] args) {UserServiceImpl impl = new UserServiceImpl(); UserProxy userProxy = new UserProxy(impl); UserService userService = (UserService) Proxy.newProxyInstance(impl.getClass().getClassLoader(),impl.getClass().getInterfaces(),userProxy); userService.addUser(); userService.updateUser(":我是皮皮虾"); }}

可见实现了增强,打印出记录日志
JDK|JDK 动态代理与 CGLIB 动态代理,它俩真的不一样
文章图片

CGlib动态代理
CGlib不像是JDK动态代理,CGlib需要导入Jar包,那么我用SpringBoot直接导入依赖
cglib cglib 3.3.0

UserServiceImpl被代理类
public class UserServiceImpl {public void addUser() { System.out.println("添加了一个用户"); }public void deleteUser() { System.out.println("删除了一个用户"); }}

UserServiceCGlib代理
public class UserServiceCGlib implements MethodInterceptor { private Object target; public UserServiceCGlib() { }public UserServiceCGlib(Object target) { this.target = target; }//返回一个代理对象:是 target对象的代理对象 public Object getProxyInstance() { //1. 创建一个工具类 Enhancer enhancer = new Enhancer(); //2. 设置父类 enhancer.setSuperclass(target.getClass()); //3. 设置回调函数 enhancer.setCallback(this); //4. 创建子类对象,即代理对象 return enhancer.create(); }@Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("增强开始~~~"); Object result = methodProxy.invokeSuper(o, objects); System.out.println("增强结束~~~"); return result; }}

test测试类
public class test {public static void main(String[] args) { UserServiceCGlib serviceCGlib = new UserServiceCGlib(new UserServiceImpl()); UserServiceImpl userService = (UserServiceImpl)serviceCGlib.getProxyInstance(); userService.addUser(); System.out.println(); userService.deleteUser(); }}

可见实现了增强,打印出记录日志
JDK|JDK 动态代理与 CGLIB 动态代理,它俩真的不一样
文章图片

使用场景 到这里相信各位小伙伴们已经基本掌握了JDK动态代理和CGlib动态代理的区别和实现
但是,如果是在面试过程中,除了要答出以上要点,你还要回答出它们的使用场景,这其实就是面试的加分项
那么,这两个动态代理的使用场景是什么呢???
答案:Spring AOP
以下是Spring AOP创建代理的方法
@Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } //如果 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理
2、如果目标对象实现了接口,也可以强制使用CGLIB
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
如果需要强制使用CGLIB来实现AOP,需要配置spring.aop.proxy-target-class=true或@EnableAspectJAutoProxy(proxyTargetClass = true

【JDK|JDK 动态代理与 CGLIB 动态代理,它俩真的不一样】点击关注,第一时间了解华为云新鲜技术~

    推荐阅读