• java动态代理模式


    java动态代理机制详解

    Spring的核心AOP的原理就是java的动态代理机制。

    在java的动态代理机制中,有两个重要的类或接口:

    1.InvocationHandler(Interface):

      每一个动态代理类都必须要实现InvocatonHandler这个接口,并且每个代理类的实例都关联到一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由

    InvocatonHandler这个接口的invoke方法来进行调用。

    public Object invoke(Object proxy,Method method,Object[] args )throws Throwable
      { 
     }

    proxy:代表我们所代理的那个真实对象;

    method:只带我们所要调用真实对象的某个方法的Method对象;

    args:指代的是调用真实对象某个方法时接受的参数。

    2.Proxy(Class)

      这个类的作用就是用来动态的创建一个代理对象的类,它提供了许多方法,但是我们用的最多的就是newProxyInstance这个方法:

     1 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interface,InvocationHandler h)throws IllegalArgumentException 

    loader:一个ClassLoder对象,定义了由那个ClassLoader对象来对生成的代理对象进行加载;

    interface:一个Interface对象的数组,表示的是我将要给我的需要代理的对象提供一组什么借口,如果我提供了一组借口给他,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了;

    h:一个InvocationHandler对象,表示的是当我这个代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上。

      

    【代码清单--1】抽象对象角色:

     1 package com.huawei.subject;
     2 /**
     3  * 抽象对象角色
     4  * @author Administrator
     5  *
     6  */
     7 public interface Subject 
     8 {
     9     void rent();
    10     void hello();
    11 }

    【代码清单--2】真实对象角色

     1 package com.huawei.subject.Impl;
     2 
     3 import com.huawei.subject.Subject;
     4 /**
     5  * 真实对象角色
     6  * @author Administrator
     7  *
     8  */
     9 public class RealSubject implements Subject 
    10 {
    11 
    12     @Override
    13     public void rent()
    14     {
    15         System.out.println("我想要出租my building");
    16     }
    17 
    18     @Override
    19     public void hello() 
    20     {
    21         System.out.println("租客你好");
    22     }
    23 
    24 }

    【代码清单--3】代理类

     1 package com.huawei.proxy;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Method;
     5 
     6 /**
     7  * 动态代理角色
     8  * @author Administrator
     9  *
    10  */
    11 public class DynamicProxy implements InvocationHandler 
    12 {
    13     //这个是我们要代理的真实对象
    14     private Object subject;
    15     //构造方法,给我们要代理的真实对象赋初值
    16     public DynamicProxy(Object obj)
    17     {
    18         this.subject = obj;
    19     }
    20     
    21 
    22     @Override
    23     public Object invoke(Object object, Method method, Object[] args)
    24             throws Throwable 
    25     {
    26         //可以在代理真实对象之前进行一些自己的操作
    27         System.out.println("Mrthod :"+method);
    28         //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象的handler对象的invoke方法来进行调用
    29         method.invoke(subject, args);
    30         
    31         //可以在代理真实对象之后进行一些自己的操作
    32         
    33         return null;
    34     }
    35 
    36 }

    【客户端】--测试类

     1 package com.huawei;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Proxy;
     5 
     6 import com.huawei.proxy.DynamicProxy;
     7 import com.huawei.subject.Subject;
     8 import com.huawei.subject.Impl.RealSubject;
     9 
    10 public class Main {
    11 
    12     public static void main(String[] args) 
    13     {
    14         //我们要代理的真实对象
    15         Subject realSubject = new RealSubject();
    16         //我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
    17         InvocationHandler handler = new DynamicProxy(realSubject);
    18         /**
    19          * 通过Proxy的newInstance方法来创建我们的代理对象
    20          * 第一个参数handler.getClass().getClassLoader(),我们这里使用这个
    21          * handler这个类的ClassLoader对象来加载我们的代理对象;
    22          * 第二个参数realSubject.getClass().getInterface(),我们这里为代理对象提供的接口
    23          * 是真实对象所实现的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了;
    24          * 第三个参数handler,这里讲这个代理对象关联到上方的InvocationHandler这个对象上
    25          */
    26         
    27         Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), 
    28                                                     realSubject.getClass().getInterfaces(), 
    29                                                     handler);
    30         
    31         System.out.println(subject.getClass().getName());
    32         
    33         subject.rent();
    34         subject.hello();
    35 
    36     }
    37 
    38 }

    【运行结果】

    com.sun.proxy.$Proxy0
    Mrthod :public abstract void com.huawei.subject.Subject.rent()
    我想要出租my building
    Mrthod :public abstract void com.huawei.subject.Subject.hello()
    租客你好

      通过Proxy.newInstance创建的代理对象是在JVM运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行时动态生成的一个对象,

    并且明明方式都是这样的形式,以$开头,proxy为重,最后一个数字表示对象的标号。

    subject.rent();
    subject.hello();

      这里是通过代理对象来调用实现的那种接口中的方法,这个时候程序就会跳转到由这个代理对象关联到的handler中的invoke方法去执行,而我们

    的这个handler对象又接受一个RealSubject类型的参数,表示我要代理的就是这个真实对象,所以此时就会调用handler中invoke方法去执行。

      由结果可知,也证明了当我们通过代理对象来调用方法的时候,实际就是委托有其关联到的handler对象的invoke方法中来调用,并不是自己真实调用,而是通过代理的方法来调用的。

  • 相关阅读:
    oracle新建用户赋权限
    Linux配置tomcat自动启动
    java白皮书关键术语
    sql中exists和not exists的用法
    db2用户、权限相关命令
    面试问题
    能ping通,但是打不开网页
    kali linux的错误
    virtualbox display size
    Jetson tk1 安装 CUDA,ROS,OpenCV和kinect2以及刷机以及ssh远程控制
  • 原文地址:https://www.cnblogs.com/lthIU/p/5837737.html
Copyright © 2020-2023  润新知