JDK动态代理原理分析


代理模式

使用代理模式必须要让代理类和目标类实现相同的接口,客户端通过代理类来调用目标方法,代理类会将所有的方法调用分派到目标对象上反射执行,还可以在分派过程中添加"前置通知"和后置处理(如在调用目标方法前校验权限,在调用完目标方法后打印日志等)等功能。

使用动态代理的五大步骤
1.通过实现InvocationHandler接口来自定义自己的InvocationHandler;
 
2.通过Proxy.getProxyClass获得动态代理类
 
3.通过反射机制获得代理类的构造方法,方法签名为getConstructor(InvocationHandler.class)
 
4.通过构造函数获得代理对象并将自定义的InvocationHandler实例对象传为参数传入
 

5.通过代理对象调用目标方法



动态代理的使用
例1(方式一)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public  class  MyProxy {
     public  interface  IHello{
         void  sayHello();
     }
     static  class  Hello  implements  IHello{
         public  void  sayHello() {
             System.out.println( "Hello world!!" );
         }
     }
     //自定义InvocationHandler
     static   class  HWInvocationHandler  implements  InvocationHandler{
         //目标对象
         private  Object target;
         public  HWInvocationHandler(Object target){
             this .target = target;
         }
         public  Object invoke(Object proxy, Method method, Object[] args)  throws  Throwable {
             System.out.println( "------插入前置通知代码-------------" );
             //执行相应的目标方法
             Object rs = method.invoke(target,args);
             System.out.println( "------插入后置处理代码-------------" );
             return  rs;
         }
     }
     public  static  void  main(String[] args)  throws  NoSuchMethodException, IllegalAccessException, InvocationTargetExc    eption, InstantiationException {
         //生成$Proxy0的class文件
         System.getProperties().put( "sun.misc.ProxyGenerator.saveGeneratedFiles" "true" );
         //获取动态代理类
         Class proxyClazz = Proxy.getProxyClass(IHello. class .getClassLoader(),IHello. class );
         //获得代理类的构造函数,并传入参数类型InvocationHandler.class
         Constructor constructor = proxyClazz.getConstructor(InvocationHandler. class );
         //通过构造函数来创建动态代理对象,将自定义的InvocationHandler实例传入
         IHello iHello = (IHello) constructor.newInstance( new  HWInvocationHandler( new  Hello()));
         //通过代理对象调用目标方法
         iHello.sayHello();
     }
}

代理类Class源码样例

$Proxy0.class
来看看例1(MyProxy)的代理类是怎样的?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public  final  class  $Proxy0  extends  Proxy  implements  IHello {    //继承了Proxy类和实现IHello接口
     //变量,都是private static Method  XXX
     private  static  Method m3;  
     private  static  Method m1;
     private  static  Method m0;
     private  static  Method m2;
     //代理类的构造函数,其参数正是是InvocationHandler实例,Proxy.newInstance方法就是通过通过这个构造函数来创建代理实例的
     public  $Proxy0(InvocationHandler var1)  throws   {
         super (var1);
     }
     //接口代理方法
     public  final  void  sayHello()  throws   {
         try  {
             super .h.invoke( this , m3, (Object[]) null );
         catch  (RuntimeException | Error var2) {
             throw  var2;
         catch  (Throwable var3) {
             throw  new  UndeclaredThrowableException(var3);
         }
     }
     //以下Object中的三个方法
     public  final  boolean  equals(Object var1)  throws   {
         try  {
             return  ((Boolean) super .h.invoke( this , m1,  new  Object[]{var1})).booleanValue();
         catch  (RuntimeException | Error var3) {
             throw  var3;
         catch  (Throwable var4) {
             throw  new  UndeclaredThrowableException(var4);
         }
     }
     public  final  int  hashCode()  throws   {
         try  {
             return  ((Integer) super .h.invoke( this , m0, (Object[]) null )).intValue();
         catch  (RuntimeException | Error var2) {
             throw  var2;
         catch  (Throwable var3) {
             throw  new  UndeclaredThrowableException(var3);
         }
     }
     public  final  String toString()  throws   {
         try  {
             return  (String) super .h.invoke( this , m2, (Object[]) null );
         catch  (RuntimeException | Error var2) {
             throw  var2;
         catch  (Throwable var3) {
             throw  new  UndeclaredThrowableException(var3);
         }
     }
     //对变量进行一些初始化工作
     static  {
         try  {
             m3 = Class.forName( "com.mobin.proxy.IHello" ).getMethod( "sayHello" new  Class[ 0 ]);
             m1 = Class.forName( "java.lang.Object" ).getMethod( "equals" new  Class[]{Class.forName( "java.lang.Object" )});
             m0 = Class.forName( "java.lang.Object" ).getMethod( "hashCode" new  Class[ 0 ]);
             m2 = Class.forName( "java.lang.Object" ).getMethod( "toString" new  Class[ 0 ]);
         catch  (NoSuchMethodException var2) {
             throw  new  NoSuchMethodError(var2.getMessage());
         catch  (ClassNotFoundException var3) {
             throw  new  NoClassDefFoundError(var3.getMessage());
         }
     }
}

由于JDK生成的代理类已经继承了Proxy(Java只支持单一继承),因此目标类必须是接口。代理类也实现了目标接口,因此在

代理类中,实现了目标接口中定义的方法。调用代理类中的代理方法时,都会通过 super.h.invoke(this, m3, (Object[])null);

调用InvocationHandler的invoke()方法,传入代理对象this,Method方法和方法参数,由于在handler中持有了目标类的实例,因此在InvocationHandler 的

invoke()方法中回掉目标对象的方法,并且在目标方法调用前,后,返回后,异常情况下进行处理(如:日志、安全、缓存等操作)

  public  Object invoke(Object proxy, Method method, Object[] args)  throws  Throwable {
             System.out.println( "------插入前置通知代码-------------" );
             //执行相应的目标方法
             Object rs = method.invoke(target,args);
             System.out.println( "------插入后置处理代码-------------" );
             return  rs;
         }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值