java 动态代理 proxy InvocationHandler

一篇杂文,写到哪就说到哪。在一些框架中有所谓的截面(aop),这些应用主要就是使用了JAVA的动态代理机制。截面或者说是拦截器所做的事情就是把一些共同的功能代码进行了抽取,简化开发以及维护。比如说,某些业务需要记录日志,需要进行功能验证。

先把用到的代码做一些简单的说明:

Ø  ImasterBusiness:主业务接口

Ø  MasterBusiness:主业务接口的一个实现类

Ø  MasterBusinessIntercepter:你叫拦截器也好,叫截面也好的一个类

Ø  MasterBusinessHander:处理器

Ø  MasterBusinessProxy:静态代理类

1.    静态代理

代理模式主要就是为了隐藏真实的业务主体,来达到一种封装的效果。静态代理模式是最简单的一种,说白了就是为每一个真实的业务主体都手动创建一个代理类。先看下面的代码

l   业务接口:

public interface IMasterBusiness {

    public void moreMoney();

}

l   真实业务主体

public class MasterBusiness implements IMasterBusiness {

    /* (non-Javadoc)

     * @see test.IMasterBusiness#moreMoney()

     */

    @Override

    public void moreMoney() {

        System.out.println("股票飘红!");

    }

}

l  代理类

public class MasterBusinessProxy implements IMasterBusiness{

    private IMasterBusiness imb;

   

    public MasterBusinessProxy(IMasterBusiness imb){

        this.imb = imb;

    }

   

    @Override

    public void moreMoney() {

        buy();

        imb.moreMoney();

        sale();

    }

    //buy,sale就是一些共同的功能代码,例如记录日志,功能验证等

    private void buy(){

        System.out.println("抄底");

    }

   

    private void sale(){

        System.out.println("高抛");

    }  

}

l  使用代理:

    public static void main(String[] args) {

        IMasterBusiness imb = new MasterBusiness();

        IMasterBusiness imbp = new MasterBusinessProxy(imb);

        imbp.moreMoney();

    }

l  运行结果:

抄底

股票飘红!

高抛

静态代理有一个问题就是需要我们手动创建代理类,如果业务方法不止一个,那么就要在每个业务方法中都加入buy()以及sale()方法。如果业务类不止一个,我们就要分别创建代理类。代码量增大,也为之后的维护增加了难度。解决的办法就是动态代理模式

动态代理模式

动态代理需要引用java中的Proxy类以及InvocationHandler接口。先把实现代码贴上

l  处理器

public class MasterBusinessHander implements InvocationHandler {

    //被代理的对象

    private Object masterBusinee;

    //拦截器

    private MasterBusinessIntercepter intercepter = new MasterBusinessIntercepter();

   

    public MasterBusinessHander(Object masterBusinee){

        this.masterBusinee = masterBusinee;

    }

 

    /* (non-Javadoc)

     * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])

     * proxy:代理类

     * method:要调用的业务方法

     * args:也无方法的参数

     */

    @Override

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

        Object result;

        if(method.getName().equals("moreMoney")){

            intercepter.buy();

            result = method.invoke(masterBusinee, args);

            intercepter.sale();

        }else{

            result = method.invoke(masterBusinee, args);

        }

        return result;

    }

}

l  调用:

public static void main(String[] args) throws Exception {

        //创建一个调用器

        MasterBusinessHander hander = new MasterBusinessHander(new MasterBusiness());

        //拆分生成代理的步骤,方便后面的介绍

        Class<?> mbClass = Proxy.getProxyClass(MasterBusiness.class.getClassLoader(), MasterBusiness.class.getInterfaces());

        Constructor<?> constructor =  mbClass.getConstructor(new Class[]{InvocationHandler.class});

        Object obj =  constructor.newInstance(hander);

        if(obj instanceof IMasterBusiness){

            IMasterBusiness mb = (IMasterBusiness)obj;

            mb.moreMoney();

        }else{

            System.out.println("代理失败");

        }

    }

Proxy

Java 动态代理机制的主类,提供了2个静态方法来生成指定接口的代理类或者对象

//获取指定接口的动态代理类的类对象

static Class getProxyClass(ClassLoader loader, Class[] interfaces)

//生成动态代理类实例

static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

InvocationHandler

调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象,第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行

Object invoke(Object proxy, Method method, Object[] args)

拆分动态代理对象创建过程

1.          首先是new 一个InvocationHandler的实现类对象

new MasterBusinessHander(new MasterBusiness())

需要为调用处理器指定一个真实的业务对象,我们调用代理类的方法最终还是要调用到真实业务对象的方法,就是我们在这里提供的业务对象。

2.          根据指定的接口生成一个代理类对象

Proxy.getProxyClass(MasterBusiness.class.getClassLoader(), MasterBusiness.class.getInterfaces());

getProxyClass这个方法里会对接口数组进行一些验证,而且会把创建的代理对象类缓存到一个map(暂称为proxymap)中,类加载器作为proxymapkeyproxymapvalue又是一个map(暂称为valuemap)valuemapkey是接口数组生产的一个对象,value就是我们创建的代理类对象。这些可以看看Proxy的代码。

3.          获取代理类的构造器

mbClass.getConstructor(new Class[]{InvocationHandler.class})

 我之前一直没有弄明白这个mbClass到底是一个什么样的类,看到下面这张图就可以看得很明白了。$ProxyN就是我们生产的代理类($以及NProxy定义的一个明白规则),这个类实现业务接口A,B,X,同时继承了Proxy类。在Proxy类中定义了一个protect访问权限的构造器

protected Proxy(InvocationHandler h) {

    this.h = h;

}

4.          通过构造函数对象创建动态代理类实例

constructor.newInstance(hander);

在创建代理对象的过程中用到了很多反射方面的知识。

待解决的问题

查看Proxy的源码,生成代理类的代码如下:

byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces);

try {

    // 动态地定义新生成的代理类

    proxyClass = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);

} catch (ClassFormatError e) {

    throw new IllegalArgumentException(e.toString());

}

sun.misc.ProxyGenerator没有公开代码,proxy到底如何调用处理器InvocationHandler我们就无法得知了,一个牛人给出了一个推演

// 假设代理类为 SimulatorProxy, 其类声明将如下

final public class SimulatorProxy implements businessInterface {    

    // 调用处理器对象的引用

    protected InvocationHandler handler;    

    // 以调用处理器为参数的构造函数

    public SimulatorProxy(InvocationHandler handler){

        this.handler = handler;

    }

    // 实现接口方法

    public void businessMethod(int arg1, long arg2, String arg3) throws ExceptionA, ExceptionB {

        // 第一步是获取方法的 Method 对象

        java.lang.reflect.Method method = null;

        try{

            method = businessInterface.class.getMethod(

                " businessMethod ", new Class[] {int.class, long.class, String.class} );

        } catch(Exception e) {

        }        

        // 第二步是调用 handler invoke 方法分派转发方法调用

        Object r = null;

        try {

// 对于原始类型参数需要进行装箱操作,高级别版本的JDK可以自动装箱

            r = handler.invoke(this, method,          

                new Object[] { arg1, arg2, arg3});

        }catch(Throwable e) {

        }

    }

}

这个推演的思路个人认为是正确的,也解释了我的疑惑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值