JDK和Cglib實現動態代理

Spring AOP使用的核心技術是動態代理,說到動態代理就不得不和設計模式中的代理模式聯繫起來,通過代理模式我們可以對目標類進行功能增強,在某個方法的執行前後增加一些操作,例如計算方法執行效率、打印日誌等。

看下面的例子,我們有一個目標類Target,我們需要在目標類的test方法中增加日誌打印功能,這時候我們就可以通過代理模式來實現:

  1. package com.proxy.test;
  2. import org.apache.commons.logging.Log;
  3. import org.apache.commons.logging.LogFactory;
  4. class Target {
  5. public void test(){
  6. System.out.println("Target test");
  7. }
  8. }
  9. class TargetProxy
  10. {
  11. private Target target;
  12. private Log logger = LogFactory.getLog(TargetProxy.class);
  13. public TargetProxy(Target target) {
  14. this.target = target;
  15. }
  16. public void test()
  17. {
  18. logger.info("*****方法執行前**********");
  19. target.test();
  20. logger.info("*****方法執行後**********");
  21. }
  22. }
  23. public class ProxyTest{
  24. public static void main(String[] args) {
  25. Target target = new Target();
  26. TargetProxy proxy = new TargetProxy(target);
  27. proxy.test();
  28. }
  29. }
在上面的例子中我們通過代理類TargetProxy對目標類進行的功能增強,所謂的動態代理就是指在程序運行期間,在內存中動態的生成代理類的字節碼並實例化代理對象。

實現方式有兩種,一種是通過JDK自帶的動態代理,另外一種則是使用Cglib實現。

1.使用JDk實現動態代理

例如在Service層,我們有兩個業務邏輯類LoginServiceImpl和UserServiceImpl:

  1. interface LoginService{
  2. public boolean checkUser();
  3. }
  4. class LoginServiceImpl implements LoginService{
  5. @Override
  6. public boolean checkUser() {
  7. System.out.println("LoginServiceImpl checkUser");
  8. return false;
  9. }
  10. }
  11. interface UserService{
  12. public String getUserName();
  13. }
  14. class UserServiceImpl implements UserService{
  15. @Override
  16. public String getUserName() {
  17. System.out.println("UserServiceImpl getUserName");
  18. return null;
  19. }
  20. }
我們要對LoginServiceImpl和UserServiceImpl中的方法增加日誌打印功能,可以通過Jdk動態代理實現,案例代碼如下:

  1. package com.proxy.test.jdk;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. import org.apache.commons.logging.Log;
  6. import org.apache.commons.logging.LogFactory;
  7. interface LoginService{
  8. public boolean checkUser();
  9. }
  10. class LoginServiceImpl implements LoginService{
  11. @Override
  12. public boolean checkUser() {
  13. System.out.println("LoginServiceImpl checkUser");
  14. return false;
  15. }
  16. }
  17. interface UserService{
  18. public String getUserName();
  19. }
  20. class UserServiceImpl implements UserService{
  21. @Override
  22. public String getUserName() {
  23. System.out.println("UserServiceImpl getUserName");
  24. return null;
  25. }
  26. }
  27. class ProxyHandler implements InvocationHandler{
  28. private Object target;
  29. private Log logger = LogFactory.getLog(ProxyHandler.class);
  30. public void setTarget(Object target) {
  31. this.target = target;
  32. }
  33. @Override
  34. public Object invoke(Object proxy, Method method, Object[] param)
  35. throws Throwable {
  36. logger.info("*********代理方法執行前************");
  37. Object retObj = method.invoke(target, param);
  38. logger.info("*********代理方法執行後************");
  39. return retObj;
  40. }
  41. }
  42. public class ProxyTestJDK {
  43. public static void main(String[] args) {
  44. //創建目標對象
  45. LoginService loninService = new LoginServiceImpl();
  46. UserService userService = new UserServiceImpl();
  47. ProxyHandler proxyHandler = new ProxyHandler();
  48. //創建LoginService代理對象
  49. proxyHandler.setTarget(loninService);
  50. LoginService loninService$Proxy = (LoginService) Proxy.newProxyInstance(loninService.getClass().getClassLoader(),
  51. loninService.getClass().getInterfaces(), proxyHandler);
  52. loninService$Proxy.checkUser();
  53. //創建UserService代理對象
  54. proxyHandler.setTarget(userService);
  55. UserService userService$Proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),
  56. userService.getClass().getInterfaces(), proxyHandler);
  57. userService$Proxy.getUserName();
  58. }
  59. }
運行程序輸出:

  1. 十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept
  2. 信息: *********代理方法執行前************
  3. LoginServiceImpl checkUser
  4. 十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept
  5. 信息: *********代理方法執行後************
  6. 十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept
  7. 信息: *********代理方法執行前************
  8. UserServiceImpl getUserName
  9. 十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept
  10. 信息: *********代理方法執行後************



2.使用Cglib動態代理實現

對於上面的需求我們也可以通過Cglib實現,具體代碼如下:

  1. package com.proxy.test.cglib;
  2. import java.lang.reflect.Method;
  3. import net.sf.cglib.proxy.Enhancer;
  4. import net.sf.cglib.proxy.MethodInterceptor;
  5. import net.sf.cglib.proxy.MethodProxy;
  6. import org.apache.commons.logging.Log;
  7. import org.apache.commons.logging.LogFactory;
  8. interface LoginService{
  9. public boolean checkUser();
  10. }
  11. class LoginServiceImpl implements LoginService{
  12. @Override
  13. public boolean checkUser() {
  14. System.out.println("LoginServiceImpl checkUser");
  15. return false;
  16. }
  17. }
  18. interface UserService{
  19. public String getUserName();
  20. }
  21. class UserServiceImpl implements UserService{
  22. @Override
  23. public String getUserName() {
  24. System.out.println("UserServiceImpl getUserName");
  25. return null;
  26. }
  27. }
  28. class CglibProxy implements MethodInterceptor
  29. {
  30. private Log logger = LogFactory.getLog(CglibProxy.class);
  31. @Override
  32. public Object intercept(Object proxy, Method method, Object[] params,
  33. MethodProxy methodProxy) throws Throwable {
  34. logger.info("*********代理方法執行前************");
  35. Object retObj = methodProxy.invokeSuper(proxy, params);
  36. logger.info("*********代理方法執行後************");
  37. return retObj;
  38. }
  39. //返回目標對象的代理對象
  40. public Object newProxy(Object target)
  41. {
  42. Enhancer enhancer = new Enhancer();
  43. enhancer.setSuperclass(target.getClass());
  44. enhancer.setCallback(this);
  45. enhancer.setClassLoader(target.getClass().getClassLoader());
  46. return enhancer.create();
  47. }
  48. }
  49. public class ProxyTestCglib {
  50. public static void main(String[] args) {
  51. //創建目標對象
  52. LoginService loninService = new LoginServiceImpl();
  53. UserService userService = new UserServiceImpl();
  54. CglibProxy proxy = new CglibProxy();
  55. //創建代理對象
  56. LoginService loninService$Proxy = (LoginService)proxy.newProxy(loninService);
  57. UserService userService$Proxy = (UserService)proxy.newProxy(userService);
  58. loninService$Proxy.checkUser();
  59. userService$Proxy.getUserName();
  60. }
  61. }

3.二者優缺點分析
使用JDK動態代理,目標類必須實現的某個接口,如果某個類沒有實現接口則不能生成代理對象。

Cglib原理是針對目標類生成一個子類,覆蓋其中的所有方法,所以目標類和方法不能聲明爲final類型。

從執行效率上看,Cglib動態代理效率較高。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章