JDK Proxy与Cglib Proxy实现分析

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来为那些没有接口的类创建代理对象。

 

Cglib的 Proxy与 JDK 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 的方法,也无法进行代理
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值