动态代理

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 动态代理
 */
public interface Subject {
    public void rent();
    public void hello(String str);
}

class RealSubject implements Subject {

    @Override
    public void rent() {
        System.out.println("I want to rent my house");
    }

    @Override
    public void hello(String str) {
        System.out.println("hello: " + str);
    }
}

class DynamicProxy implements InvocationHandler {

    private Object subject; //代理的真实对象

    /**
     * 构造方法,给我们要代理的真实对象赋初值
     * @param subject
     */
    public DynamicProxy(Object subject) {
        this.subject = subject;
    }

    /**
     *
     * @param proxy 动态代理类的引用,通常情况下不需要它。但可以使用getClass()方法,得到proxy的Class类从而取得实例的类信息,
     *                  如方法列表,annotation等。
     * @param method 方法对象的引用,代表动态代理类调用的方法。从中可得到方法名,参数,返回类型等等
     * @param args 对象数组,代表被调用方法的参数。注意基本类型(int, long)会被装箱成对象类型(Integer,Long)
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在代理真实对象前我们可以添加一些自己的操作
        System.out.println("before rent house");
        System.out.println("Method: " + method);
        // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法进行调用
        method.invoke(subject, args);
        // 在代理真实对象后也可以添加一些自己的操作
        System.out.println("after rent house");
        return null;
    }
}

class Client {
    public static void main(String[] args) {
        // 我们要代理的真实对象
        Subject realSubject = new RealSubject();
        //我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
        InvocationHandler handler = new DynamicProxy(realSubject);

        /*
         * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
         * 第一个参数:handler.getClass().getClassLoader(),我们这里使用handler这个类的ClassLoader对象
         *      来加载我们的代理对象
         * 第二个参数:realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实现的接口,
         *      表示我们要代理的是该真实对象,这里我就能调用这组接口中的方法了
         * 第三个参数handler,我们这里将这个代理对象关联到了上方的InvocationHandler这个对象上
         *
         * Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader()
         *      , realSubject.getClass().getInterfaces(), handler);
         *  1. 为什么我们这里可以将其转化为Subject类型的对象?原因就是在newProxyInstance这个方法的第二个参数上,
         *          我们给这个代理对象提供了一组什么接口 ,那么我这个代理对象就会实现了这组接口,这个时候我们当然可以
         *          将这个代理对象强制类型转化为这组接口中的任意一个,因为这里的接口是Subject类型,所以就可以将其转化为Subject类型了。
         *     通过Proxy.newProxyInstance 创建的代理对象是在jvm运行是动态生成的一个对象,它并不是我们的InbacationHandler类型,
         *     二是在运行时动态生成的一个对象,并且命名方式都是这样的形式(com.sun.proxy.$Proxy0),以$开头,proxy为中,最后一个数字表示对象的标号。
         */
        Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader()
                , realSubject.getClass().getInterfaces(), handler);
        System.out.println(subject.getClass().getName());
        subject.rent();
        subject.hello("world");
    }
}

 

posted @ 2018-01-15 14:18  菲儿飞飞  Views(128)  Comments(0Edit  收藏  举报