Java中的代理机制

来源:互联网 发布:网络教学英语作文优点 编辑:程序博客网 时间:2024/06/01 19:05

说起代理,类比于生活中的例子,就是中介。对于目标类,有一个代理对象去代替目标类执行方法,但实际上还是调用了目标类的方法。
至于Java中的静态代理实现,代理类和目标类都需要实现同一个接口。写个小Demo

静态代理这个模式本身有个大问题,如果类方法数量越来越多的时候,代理类的代码量是十分庞大的。所以引入动态代理来解决此类问题。
动态代理原理见Java帝国之动态原理,讲解的通俗易懂
写个Demo
接口:

public interface Subject1 {    public void rent();    public void sayHello(String name);}

目标类:

public class RealSubject1 implements Subject1{    public void rent(){        System.out.println("I want to rent my house.");    }    public void sayHello(String name){        System.out.println("Hello,"+name);    }}

代理类:

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;/** * 动态代理类 * Created by Dream on 2017/12/12. */public class DynamicProxy implements InvocationHandler {    //代理的真实对象    private Object tar;    //给代理的真实对象赋值    public DynamicProxy(Object tar){        this.tar = tar;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        Object o = null;        //在代理真实对象前,我们可以添加自己的操作        System.out.println("代理真实对象之前...");        System.out.println("Method:"+method);        //当代理对象去调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用        o = method.invoke(tar,args);        //在代理真实对象后,我们也可以添加自己的操作        System.out.println("代理真实对象结束...");        return o;    }}

动态代理类的使用:

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;/** * Created by Dream on 2017/12/12. */public class Client {    public static void main(String[] args){        //代理的真实对象        Subject1 real = new RealSubject1();        // 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的        InvocationHandler handler = new DynamicProxy(real);        /*         * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数         * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象         * 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了         * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上         */        Subject1 sub = (Subject1) Proxy.newProxyInstance(real.getClass().getClassLoader(),real.getClass().getInterfaces(),handler);        System.out.println(sub.getClass().getName());        sub.rent();        sub.sayHello("Dream");    }}

运行结果:

com.sun.proxy.$Proxy0代理真实对象之前...Method:public abstract void com.itdream.Dynamic.Subject1.rent()I want to rent my house.代理真实对象结束...代理真实对象之前...Method:public abstract void com.itdream.Dynamic.Subject1.sayHello(java.lang.String)Hello,Dream代理真实对象结束...

通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号。
起初认为返回的这个代理对象会是Subject类型的对象,或者是InvocationHandler的对象,结果却不是,首先我们解释一下为什么我们这里可以将其转化为Subject类型的对象?原因就是在newProxyInstance这个方法的第二个参数上,我们给这个代理对象提供了一组什么接口,那么我这个代理对象就会实现了这组接口,这个时候我们当然可以将这个代理对象强制类型转化为这组接口中的任意一个,因为这里的接口是Subject类型,所以就可以将其转化为Subject类型了。
更详细的Java动态代理讲解

原创粉丝点击