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动态代理效率较高。

猜你喜欢

转载自blog.csdn.net/qq_41641296/article/details/80999111