JDK Proxy与Cglib Proxy实现分析

JDK Proxy与Cglib Proxy实现分析

JDK Proxy AOP实现

java.lang.reflect.Proxy,
Proxy
提供用于创建动态代理类和实例的静态方法. 只能针对接口创建代理
newProxyInstance()
返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序
(
详见api文档)

java.lang.reflect.InvocationHandler,
InvocationHandler
是代理实例的调用处理程序 实现的接口。
invoke()
在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。

 

动态代理的使用代码示例如下:
 1  public   static   void  main(String[] args) {
 2          
 3          InvocationHandler ih  =   new  InvocationHandler() {
 4 
 5               public  Object invoke(Object proxy, Method method, Object[] args)
 6                       throws  Throwable {
 7                   //  拦截方法处理
 8                   return   null ;
 9              }
10              
11          };
12          
13          Class <?> [] interfaces  =   new  Class <?> [] {BankAccount. class };
14          
15          BankAccount bankAccount  =  (BankAccount) Proxy.newProxyInstance(ProxyTest  
16                  . class .getClassLoader(), interfaces, ih);  
17    }
18 

下面是动态代理生成的代码对应(通过反编译工具对字节码进行处理)

接口代码:

 1  public   interface  BankAccount {
 2 
 3       boolean  deposit(BigDecimal money);
 4      
 5       boolean  withdraw(BigDecimal money);
 6      
 7      String getName();
 8      
 9      String getId();
10  }
11 

动态代理生成的字节码 ( 反编译后 的Java代码)

 1  public   final   class  BankAccount$ 1   extends  Proxy  implements  BankAccount {
 2       private   static  Method m6;  //  getId
 3       private   static  Method m4;  //  withdraw
 4       private   static  Method m5;  //  getName
 5       private   static  Method m2;  //  toString
 6       private   static  Method m0;  //  hashCode
 7       private   static  Method m3;  //  deposit
 8       private   static  Method m1;  //  equals
 9 
10       public  BankAccount$ 1 (InvocationHandler ih) {
11           super (ih);
12      }
13 
14       public   final  String getId() {
15           try  {
16               return  (String)  this .h.invoke( this , m6,  null );
17          }  catch  (RuntimeException e) {
18               throw  e;
19          }  catch  (Throwable t) {
20               throw   new  UndeclaredThrowableException(t);
21          }
22      }
23 
24       public   final   boolean  withdraw(BigDecimal paramBigDecimal) {
25           try  {
26               return  ((Boolean)  this .h.invoke( this , m4,
27                       new  Object[] { paramBigDecimal })).booleanValue();
28          }  catch  (RuntimeException e) {
29               throw  e;
30          }  catch  (Throwable t) {
31               throw   new  UndeclaredThrowableException(t);
32          }
33      }
34 
35       public   final  String getName() {
36           try  {
37               return  (String)  this .h.invoke( this , m5,  null );
38          }  catch  (RuntimeException e) {
39               throw  e;
40          }  catch  (Throwable t) {
41               throw   new  UndeclaredThrowableException(t);
42          }
43      }
44 
45       public   final  String toString() {
46           try  {
47               return  (String)  this .h.invoke( this , m2,  null );
48          }  catch  (RuntimeException localRuntimeException) {
49               throw  localRuntimeException;
50          }  catch  (Throwable t) {
51               throw   new  UndeclaredThrowableException(t);
52          }
53      }
54 
55       public   final   int  hashCode() {
56           try  {
57               return  ((Integer)  this .h.invoke( this , m0,  null )).intValue();
58          }  catch  (RuntimeException e) {
59               throw  e;
60          }  catch  (Throwable t) {
61               throw   new  UndeclaredThrowableException(t);
62          }
63      }
64 
65       public   final   boolean  deposit(BigDecimal paramBigDecimal) {
66           try  {
67               return  ((Boolean)  this .h.invoke( this , m3,
68                       new  Object[] { paramBigDecimal })).booleanValue();
69          }  catch  (RuntimeException localRuntimeException) {
70               throw  localRuntimeException;
71          }  catch  (Throwable localThrowable) {
72               throw   new  UndeclaredThrowableException(localThrowable);
73          }
74      }
75 
76       static  {
77           try  {
78              m6  =  Class.forName( " BankAccount " ).getMethod( " getId " new  Class[ 0 ]);
79              m4  =  Class.forName( " BankAccount " ).getMethod( " withdraw " ,
80                       new  Class[] { Class.forName( " java.math.BigDecimal " ) });
81              m5  =  Class.forName( " BankAccount " )
82                      .getMethod( " getName " new  Class[ 0 ]);
83              m2  =  Class.forName( " java.lang.Object " ).getMethod( " toString " ,
84                       new  Class[ 0 ]);
85              m0  =  Class.forName( " java.lang.Object " ).getMethod( " hashCode " ,
86                       new  Class[ 0 ]);
87              m3  =  Class.forName( " BankAccount " ).getMethod( " deposit " ,
88                       new  Class[] { Class.forName( " java.math.BigDecimal " ) });
89              m1  =  Class.forName( " java.lang.Object " ).getMethod( " equals " ,
90                       new  Class[] { Class.forName( " java.lang.Object " ) });
91          }  catch  (NoSuchMethodException e) {
92               throw   new  NoSuchMethodError(e.getMessage());
93          }  catch  (ClassNotFoundException e) {
94               throw   new  NoClassDefFoundError(e.getMessage());
95          }
96      }
97  }
98 

从动态代理生成的代码可以分析得到,所有的方法的调用,都会回调 InvokeHanlder 接口的实现类的 invoke 方法,并把实际调用的反射相关信息作为参数传给 invoke 方法。

Cglib Proxy AOP实现

cglib是一个开源项目! 是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Spring很多地方借助该项目实现AOP的功能封装。

CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。通过使用CGLIB来为那些没有接口的类创建代理对象。

 

CglibProxyJDK Proxy还是有一定的相似的,下面的例子,给大家一个基本的演示


1  public   class  SimpleBean {
2 
3       public   void  hello() {
4          System.out.println( " hi matthew! " );
5      }
6  }

Cglib 代理后(只给出了部分核心反编译后的Java代码)


 1  class   SimpleBean$$EnhancerByCGLIB$$4c4a66a  extends  SimpleBean {
 2       private    static    final   Method CGLIB$hello$ 0 $Method ;
 3 
 4       public    final    void   hello( ) {
 5       if ( ! this .CGLIB$CONSTRUCTED)
 6      {
 7         super .hello();
 8         return ;
 9     
10      }
11       if ( this .CGLIB$CALLBACK_0 ==   null )
12      {
13        CGLIB$BIND_CALLBACKS( this );
14     
15      }
16       if ( this .CGLIB$CALLBACK_0 !=    null )
17      {
18         this .CGLIB$CALLBACK_0.intercept( this ,SimpleBean$$EnhancerByCGLIB$$4c4a66a.CGLIB$hello$ 0 $Method,SimpleBean$$EnhancerByCGLIB$$4c4a66a.CGLIB$emptyArgs,SimpleBean$$EnhancerByCGLIB$$4c4a66a.CGLIB$hello$ 0 $Proxy);
19         return ;
20     
21      }
22       super .hello();
23       return ;
24       catch (RuntimeException  aRuntimeException2)
25      {
26         catch (Throwable  aRuntimeException2)
27        {
28          UndeclaredThrowableException JdecGenerated57  =   new  UndeclaredThrowableException(
29   }
30  }
31 
32  final      void  CGLIB$hello$ 0 ( ) 
33   {
34       super .hello();
35       return ;
36   }
37 

注: 从上面的实现代理来看,Cglib对于标识 final 关键字的class无法进行代理操作。

       对于标识 final 的方法,也无法进行代理

Good Luck!
Yours Matthew!

你可能感兴趣的:(JDK Proxy与Cglib Proxy实现分析)