IT培訓-高端面授IT培訓機構
          云和教育:云和數據集團高端IT職業教育品牌
          • 國家級
            全民數字素養與技能培訓基地
          • 河南省
            第一批產教融合型企業建設培育單位
          • 鄭州市
            數字技能人才(碼農)培養評價聯盟
          當前位置:
          首頁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()方法來執行相應的邏輯。