动态代理 两种方式

代理类Proxy和RealSubject应该实现了相同的功能接口,在面向对象的编程之中,如果想要两个对象实现相同的功能,有以下两种方式:

1)  定义一个功能接口,然后代理类Proxy和真实类RealSubject都实现这个接口。

2)  代理类Proxy继承RealSubject,这样Proxy则拥有了RealSubject的功能,Proxy还可以通过重写RealSubject中的方法,来实现多态。 

其中JDK中提供的创建动态代理的机制就是以1方式设计的,而cglib则是以2方式设计的。


1、JDK的动态代理机制

Jdk为RealSubject对象创建动态代理对象,主要做了以下工作:

1) 获取RealSubject上的所有接口列表。

2) 确定要生成的动态代理类的类名,默认为com.sun.proxy.$ProxyXXX

3) 根据需要实现接口信息,在代码中动态创建该Proxy的字节码

4) 将对应的字节码转换为对应的class对象

5) 创建InvocationHandler实例,用来处理Proxy所有方法调用

6) Proxy的class对象以创建的handler对象为参,实例化Proxy对象

Jdk通过java.lang.reflect.Proxy来支持动态代理,一般情况下,使用方法newProxyInstanceof来创建Proxy类,而对于InvocationHandler,需要实现它的invoke方法,在调用代理对象中的每一个方法时,在代码内部,都是直接调用了InvocationHandler的invoke方法,而invoke方法根据代理类传递给自己的method参数来区分是什么方法。

Java动态代理技术的两种方式

2、cglib的动态代理机制

JDK中提供的生成动态代理类的机制有个鲜明的特点是: 某个类必须有实现的接口,而生成的代理类也只能代理某个类接口定义的方法果某个类没有实现接口,那么这个类就不能同JDK产生动态代理了!CGLIB(Code Generation Library),是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。

cglib 创建某动态代理类的模式是:

1)  查找类上的所有非final的public类型的方法定义

2)  将这些方法的定义转换成字节码

3)  将组成的字节码转换成相应的代理的class对象

4)  实现MethodInterceptor接口,用来处理对代理类上所有方法的请求(和InvocationHandler的功能和角色是一样的)

Java动态代理技术的两种方式
Java动态代理技术的两种方式
cglib需要的jar包有asm.jar、cglib.jar


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通常被首选使用,因为它更快。

[java] view plain copy
  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. }  


[java] view plain copy
  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++++++


猜你喜欢

转载自blog.csdn.net/lovezhaohaimig/article/details/80287949