java 动态代理

来源:互联网 发布:张靓颖 冯轲 知乎 编辑:程序博客网 时间:2024/05/22 10:57

之前写过静态代理 代理模式 ,现在来说说动态代理,传统的静态代理模式需要为每一个需要代理的类写一个代理类,如果需要代理的类有几百个就需要写几百个代理类,为了更优雅地实现代理模式,JDK提供了动态代理方式,可以简单理解为JVM可以在运行时帮我们动态生成一系列的代理类,这样我们就不需要手写每一个静态的代理类了。

同样,我们需要先定义一个接口

public interface IBuyHouse {    abstract void seeHouse();    abstract void contract();    abstract void pay();}

在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。

首先看下 InvocationHandler, 每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。

public class AgencyProxy implements InvocationHandler {    private static final String TAG = "AgencyProxy";    private Object agency;    public AgencyProxy(Object agency) {        this.agency = agency;    }    // proxy:  代理对象    // method:  调用方法    // args:  方法的参数    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        String methodName = method.getName();        if ("seeHouse".equals(methodName)) {            Log.d(TAG, "proxy seeHouse");        } else if ("contract".equals(methodName)) {            Log.d(TAG, "proxy contract");        } else if ("pay".equals(methodName)) {            Log.d(TAG, "proxy pay");        }        return method.invoke(agency, args);    }}

委托类还是和静态类一样的写法

public class Customer implements IBuyHouse {    private static final String TAG = "Customer";    @Override    public void seeHouse() {        Log.d(TAG, "看房");    }    @Override    public void contract() {        Log.d(TAG, "签合同");    }    @Override    public void pay() {        Log.d(TAG, "付款");    }}

现在来看下 main 函数, 用 Proxy.newProxyInstance 动态创建一个代理类,
newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h);

loader: 要求,传递的是被代理类的类加载器ClassLoader 类加载器怎样获取: 得到其Class对象,在Class类中提供一个方法getClassLoader();

interfaces: 要求:得到被代理对象所实现的接口的所有Class对象。 怎样获取所有实现接口的Class对象?
得到其Class对象,在Class类中提供一个方法 getInterfaces();它返回的是Class[],就代表所实现接口的所有Class对象。

h: 它的类型是InvocationHandler,这是一个接口。
InvocationHandler 是代理实例的调用处理程序 实现的接口。

    IBuyHouse c = new Customer();        InvocationHandler handler = new AgencyProxy(c);        IBuyHouse proxyCoustomer = (IBuyHouse) Proxy.newProxyInstance(                c.getClass().getClassLoader(),                c.getClass().getInterfaces(),                handler);        proxyCoustomer.contract();        proxyCoustomer.pay();        proxyCoustomer.seeHouse();

为什么我们这里可以将其转化为IBuyHouse类型的对象?原因就是在newProxyInstance这个方法的第二个参数上,我们给这个代理对象提供了一组什么接口,那么我这个代理对象就会实现了这组接口,这个时候我们当然可以将这个代理对象强制类型转化为这组接口中的任意一个,因为这里的接口是IBuyHouse类型,所以就可以将其转化为IBuyHouse类型了。

运行结果如下:

D/AgencyProxy: proxy contract
D/Customer: 签合同
D/AgencyProxy: proxy pay
D/Customer: 付
D/AgencyProxy: proxy seeHouse
D/Customer: 看房

原创粉丝点击