IT培训-高端面授IT培训机构
云和教育:云和数据集团高端IT职业教育品牌 全国咨询热线:0371-67988003
课程 请选择课程
    校区 请选择校区
      • 华为
        授权培训中心
      • 腾讯云
        一级认证培训中心
      • 百度营销大学
        豫陕深授权运营中心
      • Oracle甲骨文
        OAEP中心
      • Microsoft Azure
        微软云合作伙伴
      • Unity公司
        战略合作伙伴
      • 普华基础软件
        战略合作伙伴
      • 新开普(股票代码300248)
        旗下丹诚开普投资
      • 中国互联网百强企业锐之旗
        旗下锐旗资本投资
      当前位置:
      首页IT问答正文

      Spring对JDK和CgLib动态代理该怎么选?

      • 发布时间:
        2023-03-21
      • 版权所有:
        云和教育
      • 分享:

      Spring框架在实现动态代理时,提供了两种选择:基于JDK的动态代理和基于CgLib的动态代理。

      JDK动态代理只能代理实现了接口的类,而CgLib动态代理可以代理没有实现接口的类。因此,如果需要代理的类实现了接口,建议使用JDK动态代理;如果需要代理的类没有实现接口,或者需要对类的方法进行代理而不是接口的方法,建议使用CgLib动态代理。

      另外,由于JDK动态代理是基于接口的,因此它的代理效率比CgLib动态代理要高。在大多数情况下,建议首选JDK动态代理,只有在必要的情况下才考虑使用CgLib动态代理。

      需要注意的是,如果需要代理的类已经是final类,则无法使用CgLib动态代理代理该类。此外,CgLib动态代理也可能会影响应用程序的性能,因此在使用CgLib动态代理时,需要谨慎评估其对性能的影响。

      下面是使用Spring基于JDK和CgLib动态代理的示例代码。

      假设我们有一个接口UserService和一个实现类UserServiceImpl,代码如下:

      public interface UserService {
          void addUser();
      }
      
      public class UserServiceImpl implements UserService {
          @Override
          public void addUser() {
              System.out.println("Add user.");
          }
      }

      现在我们想要在调用UserServiceImpl的addUser()方法之前和之后执行一些额外的逻辑。我们可以使用Spring的动态代理功能来实现这一点。

      基于JDK的动态代理示例代码如下:

      import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Method;
      import java.lang.reflect.Proxy;
      
      public class UserServiceProxy implements InvocationHandler {
      
          private UserService userService;
      
          public UserServiceProxy(UserService userService) {
              this.userService = userService;
          }
      
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              System.out.println("Before addUser.");
              Object result = method.invoke(userService, args);
              System.out.println("After addUser.");
              return result;
          }
      
          public static void main(String[] args) {
              UserService userService = new UserServiceImpl();
              InvocationHandler handler = new UserServiceProxy(userService);
              UserService userServiceProxy = (UserService) Proxy.newProxyInstance(
                      userService.getClass().getClassLoader(),
                      userService.getClass().getInterfaces(),
                      handler
              );
              userServiceProxy.addUser();
          }
      }

      基于CgLib的动态代理示例代码如下:

      import net.sf.cglib.proxy.MethodInterceptor;
      import net.sf.cglib.proxy.MethodProxy;
      import net.sf.cglib.proxy.Enhancer;
      
      public class UserServiceCgLibProxy implements MethodInterceptor {
      
          private UserService userService;
      
          public UserServiceCgLibProxy(UserService userService) {
              this.userService = userService;
          }
      
          @Override
          public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
              System.out.println("Before addUser.");
              Object result = proxy.invoke(userService, args);
              System.out.println("After addUser.");
              return result;
          }
      
          public static void main(String[] args) {
              UserService userService = new UserServiceImpl();
              Enhancer enhancer = new Enhancer();
              enhancer.setSuperclass(userService.getClass());
              enhancer.setCallback(new UserServiceCgLibProxy(userService));
              UserService userServiceProxy = (UserService) enhancer.create();
              userServiceProxy.addUser();
          }
      }

      以上两个示例代码中,我们都定义了一个代理类,并实现了InvocationHandler或MethodInterceptor接口来处理方法调用。在main方法中,我们通过Proxy.newProxyInstance()或Enhancer.create()方法来创建代理对象,并调用其方法,此时代理对象会自动调用我们定义的invoke()或intercept()方法来执行相应的逻辑。