zoukankan      html  css  js  c++  java
  • Java动态代理的实现方法

    AOP的拦截功能是由java中的动态代理来实现的。说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常时候执行。不同的切入时机对应不同的Interceptor的种类,如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)。

    那么动态代理是如何实现将切面逻辑(advise)织入到目标类方法中去的呢?下面我们就来详细介绍并实现AOP中用到的两种动态代理。

    AOP的源码中用到了两种动态代理来实现拦截切入功能:jdk动态代理和cglib动态代理。两种方法同时存在,各有优劣。jdk动态代理是由Java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。。

    1、定义接口和实现


     

    1. package com.meituan.hyt.test3.service;  
    2.   
    3.   
    4. public interface UserService {  
    5.     public String getName(int id);  
    6.   
    7.     public Integer getAge(int id);  
    8. }  

     
    1. package com.meituan.hyt.test3.service.impl;  
    2.   
    3. import com.meituan.hyt.test3.service.UserService;  
    4.   
    5.   
    6. public class UserServiceImpl implements UserService {  
    7.     @Override  
    8.     public String getName(int id) {  
    9.         System.out.println("------getName------");  
    10.         return "Tom";  
    11.     }  
    12.   
    13.     @Override  
    14.     public Integer getAge(int id) {  
    15.         System.out.println("------getAge------");  
    16.         return 10;  
    17.     }  
    18. }  

    2、jdk动态代理实现

     
    1. package com.meituan.hyt.test3.jdk;  
    2.   
    3. import java.lang.reflect.InvocationHandler;  
    4. import java.lang.reflect.Method;  
    5.   
    6.   
    7. public class MyInvocationHandler implements InvocationHandler {  
    8.     private Object target;  
    9.   
    10.     MyInvocationHandler() {  
    11.         super();  
    12.     }  
    13.   
    14.     MyInvocationHandler(Object target) {  
    15.         super();  
    16.         this.target = target;  
    17.     }  
    18.   
    19.     @Override  
    20.     public Object invoke(Object o, Method method, Object[] args) throws Throwable {  
    21.         if("getName".equals(method.getName())){  
    22.             System.out.println("++++++before " + method.getName() + "++++++");  
    23.             Object result = method.invoke(target, args);  
    24.             System.out.println("++++++after " + method.getName() + "++++++");  
    25.             return result;  
    26.         }else{  
    27.             Object result = method.invoke(target, args);  
    28.             return result;  
    29.         }  
    30.   
    31.     }  
    32. }  
     
    1. package com.meituan.hyt.test3.jdk;  
    2.   
    3. import com.meituan.hyt.test3.service.UserService;  
    4. import com.meituan.hyt.test3.service.impl.UserServiceImpl;  
    5.   
    6. import java.lang.reflect.InvocationHandler;  
    7. import java.lang.reflect.Proxy;  
    8.   
    9.   
    10. public class Main1 {  
    11.     public static void main(String[] args) {  
    12.         UserService userService = new UserServiceImpl();  
    13.         InvocationHandler invocationHandler = new MyInvocationHandler(userService);  
    14.         UserService userServiceProxy = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(),  
    15.                 userService.getClass().getInterfaces(), invocationHandler);  
    16.         System.out.println(userServiceProxy.getName(1));  
    17.         System.out.println(userServiceProxy.getAge(1));  
    18.     }  
    19. }  


    运行结果

    ++++++before getName++++++
    ------getName------
    ++++++after getName++++++
    Tom
    ------getAge------
    10

    3、cglib动态代理实现

    Cglib是一个优秀的动态代理框架,它的底层使用ASM在内存中动态的生成被代理类的子类,使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能。CGLIB具有简单易用,它的运行速度要远远快于JDK的Proxy动态代理:

    CGLIB的核心类:
        net.sf.cglib.proxy.Enhancer – 主要的增强类
        net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现
        net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:
        Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。

    net.sf.cglib.proxy.MethodInterceptor接口是最通用的回调(callback)类型,它经常被基于代理的AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法
    public Object intercept(Object object, java.lang.reflect.Method method,
    Object[] args, MethodProxy proxy) throws Throwable;

    第一个参数是代理对像,第二和第三个参数分别是拦截的方法和方法的参数。原来的方法可能通过使用java.lang.reflect.Method对象的一般反射调用,或者使用 net.sf.cglib.proxy.MethodProxy对象调用。net.sf.cglib.proxy.MethodProxy通常被首选使用,因为它更快。

     
    1. package com.meituan.hyt.test3.cglib;  
    2.   
    3.   
    4. import net.sf.cglib.proxy.MethodInterceptor;  
    5. import net.sf.cglib.proxy.MethodProxy;  
    6.   
    7. import java.lang.reflect.Method;  
    8.   
    9.   
    10. public class CglibProxy implements MethodInterceptor {  
    11.     @Override  
    12.     public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {  
    13.         System.out.println("++++++before " + methodProxy.getSuperName() + "++++++");  
    14.         System.out.println(method.getName());  
    15.         Object o1 = methodProxy.invokeSuper(o, args);  
    16.         System.out.println("++++++before " + methodProxy.getSuperName() + "++++++");  
    17.         return o1;  
    18.     }  
    19. }  



     
    1. package com.meituan.hyt.test3.cglib;  
    2.   
    3. import com.meituan.hyt.test3.service.UserService;  
    4. import com.meituan.hyt.test3.service.impl.UserServiceImpl;  
    5. import net.sf.cglib.proxy.Enhancer;  
    6.   
    7.   
    8.   
    9. public class Main2 {  
    10.     public static void main(String[] args) {  
    11.         CglibProxy cglibProxy = new CglibProxy();  
    12.   
    13.         Enhancer enhancer = new Enhancer();  
    14.         enhancer.setSuperclass(UserServiceImpl.class);  
    15.         enhancer.setCallback(cglibProxy);  
    16.   
    17.         UserService o = (UserService)enhancer.create();  
    18.         o.getName(1);  
    19.         o.getAge(1);  
    20.     }  
    21. }  


    运行结果:

    ++++++before CGLIB$getName$0++++++
    getName
    ------getName------
    ++++++before CGLIB$getName$0++++++
    ++++++before CGLIB$getAge$1++++++
    getAge
    ------getAge------
    ++++++before CGLIB$getAge$1++++++

  • 相关阅读:
    2019-8-31-dotnet-方法名-To-和-As-有什么不同
    2019-8-31-dotnet-方法名-To-和-As-有什么不同
    2018-11-30-WPF-解决-ListView-的滚动条不显示
    2018-11-30-WPF-解决-ListView-的滚动条不显示
    2019-4-29-dotnet-core-通过-frp-发布自己的网站
    2019-4-29-dotnet-core-通过-frp-发布自己的网站
    2019-1-29-jekyll-如何加密博客-防止抓取
    2019-1-29-jekyll-如何加密博客-防止抓取
    2019-8-31-msbuild-项目文件常用判断条件
    XenServer Tools安装
  • 原文地址:https://www.cnblogs.com/jtlgb/p/6085034.html
Copyright © 2011-2022 走看看