proxy动态代理机制分析

时间:2021-08-03 15:18:34

1       模拟Proxy模式

   代理模式支持将某些操作从实际的对象中分离出来,通过它的代理类提供处理。这样便于修改和管理这些特定的操作。

下面示例一个代理模式的实现。

 

1.1  接口定义

package com.zj.proxy;

public interface Subject

{    void operation1();       

     void operation2(String arg);

}

1.2  接口实现

RealSubject.java

package com.zj.proxy;

 public class RealSubject implements Subject

{     public void operation1()

{       System.out.println("Realer do operation1");    }   

 public void operation2(String arg)

 {       System.out.println("Realer do operation2 with " + arg);    }

}

1.3  实现代理

package com.zj.proxy;

public class ProxySubject implements Subject

{    private Subject proxied;//被代理对象   

 public ProxySubject(Subject proxied) {       this.proxied = proxied;    }     public void operation1() {      

System.out.println("Proxyer do operation1");       proxied.operation1();    }   

 public void operation2(String arg)

{       System.out.println("Proxyer do operation2 with " + arg);       proxied.operation2(arg);    }

}

 

1.4  代理调用

package com.zj.proxy.client;

 import com.zj.proxy.Subject;

import com.zj.proxy.RealSubject;

import com.zj.proxy.ProxySubject;

 public class SimpleProxyDemo

 {    public static void consumer(Subject subject)

{       subject.operation1();       

subject.operation2("ZJ");    }   

 public static void main(String[] args)

{       RealSubject real = new RealSubject();       System.out.println("===Without Proxy===");      

consumer(real);      

System.out.println("===Use Proxy===");      

consumer(new ProxySubject(real));    }}

2       动态代理机制设计

 一个类用于实现InvocationHandle接口,InvocationHandler是代理实例的调用处理程序实现的接口。每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke方法。

2.1  动态接口InvocationHandle.java

package java.lang.reflect;

 public interface InvocationHandler

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

}

对应invoke参数:

[1]proxy - 在其上调用方法的代理实例;

[2]method - 对应于在代理实例上调用的接口方法的 Method实例;

[3]args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null

2.2  实现动态接口的类

现在设计一个类实现该接口,并提供代理实例。

package com.zj.proxy.dynamic;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

public class DynamicProxyHandler implements InvocationHandler

{    private Object proxied;    

public DynamicProxyHandler(Object proxied)

 {       this.proxied = proxied;    }    

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

{     

 System.out.println("**** proxy: ****\n" + proxy.getClass()              + "\nmethod: " + method + "\nargs: " + args);     

 if (args != null)          

for (Object arg : args)              System.out.println("  " + arg);      

return method.invoke(proxied, args);    }

}

   这里的private Object proxied;即代理实例,也即上文代理模式中介绍的RealSubject对象。在invoke()方法中,我们会打印它的所有参数,并调用当前代理的方法。

2.3  代理测试类

package com.zj.proxy.client;

import java.lang.reflect.Proxy;import com.zj.proxy.Subject;

import com.zj.proxy.RealSubject;

import com.zj.proxy.dynamic.DynamicProxyHandler;

public class DynamicProxyDemo {   

public static void consumer(Subject subject)

{      

subject.operation1();      

subject.operation2("ZJ");   

}       

public static void main(String[] args)

{       

RealSubject real = new RealSubject();      

System.out.println("===Without Proxy===");      

consumer(real);     

 System.out.println("===Use Proxy===");     

 Subject proxy = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[] { Subject.class }, new DynamicProxyHandler(real));      

consumer(proxy);   

}

}

   这里通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)生成代理类,并传递与其关联的调用处理程序new DynamicProxyHandler(real)

对于newProxyInstance()的参数:

[1]loader - 定义代理类的类加载器;

[2]interfaces - 代理类要实现的接口列表;

[3]h - 指派方法调用的调用处理程序。

从结果可以发现,通过代理可以得到当前被调用的方法,及其参数。代理过程可以基于此进行逻辑处理,测试程序只是简单的打印这些相关信息。

 

3       动态代理机制的分析

3.1  传统基于接口实现扩展

调用端代理不变,通过参数改变,实现功能的改变

3.1.1       接口定义

public interface Car

{

    public void description();

}

3.1.2       接口实现

public class BigCar implements Car

{

public void description()

{

        System.out.println("BigCar");

    }

}

3.1.3       接口调用

Car car = new BigCar();  

car.description(); 

3.2  基于代理的调用扩展

3.2.1       实现代理接口

如果我们要用Proxy来做,首先需要一个实现了InvocationHandler的代理类:

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

public class CarProxy implements InvocationHandler

{

    private Object delegate;

public Object newInstance(Object delegate)

{

        this.delegate = delegate;

        return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),

                delegate.getClass().getInterfaces(), this);

    }

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

            throws Throwable

{

        return method.invoke(delegate, args);

    }

}

3.2.2       接口调用

CarProxy cp = new CarProxy();  

Car car = (Car) cp.newInstance(BigCar.class.newInstance());  

car.description(); 

3.2.3       作用分析

使用Proxy一般目的有两个:

(1)    一是为了在程序逻辑执行时插入其它逻辑(比如添加日志或是改写参数传递);

(2)    二是为了改变程序逻辑。

3.3  基于代理的插入逻辑

3.3.1       实现代理接口

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

public class CarProxy implements InvocationHandler

{

 

    private Object delegate;

public Object newInstance(Object delegate)

{

        this.delegate = delegate;

        return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),

                delegate.getClass().getInterfaces(), this);

    }

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

{

        System.out.println("before method: " + method.getName());

        Object returnObj = null;

        try

        {

            returnObj = method.invoke(delegate, args);

        } catch (IllegalAccessException e)

        {

            e.printStackTrace();

        } catch (InvocationTargetException e)

        {

            e.printStackTrace();

        } finally

        {

            System.out.println("after method: " + method.getName());

        }

        return returnObj;

    }

}

3.3.2       接口调用

CarProxy cp = new CarProxy();  

Car car = (Car) cp.newInstance(BigCar.class.newInstance());  

car.description();

3.4  基于代理的改变逻辑

3.4.1       实现代理接口

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

public class CarProxy implements InvocationHandler

{

    private Object delegate;

public Object newInstance(Object delegate)

 {

        this.delegate = delegate;

        return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),

                delegate.getClass().getInterfaces(), this);

    }

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

{

        if (method.getName().equals("description"))

{

            System.out.println("Caught by proxy.");

        }

        return null;

    }

}

3.4.2       接口调用

CarProxy cp = new CarProxy();  

Car car = (Car) cp.newInstance(BigCar.class.newInstance());  

car.description();

 

4       一个代理可以代理多个类

4.1  接口定义

4.1.1       接口一

public interface Flavor

{

    public void taste();

}

 

public class Spicy implements Flavor

{

public void taste()

{

        System.out.println("Spicy");

    }

}

4.1.2       接口二

public interface Color

{

    public void show();

}

public class Red implements Color

{

public void show()

{

        System.out.println("Red");

    }

}

4.2  代理多个类实现

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

public class MultipleProxy implements InvocationHandler

{

   private Class[] interfaces;

   private Object[] delegates;

public MultipleProxy(Class[] interfaces, Object[] delegates)

{

        this.interfaces = (Class[]) interfaces.clone();

        this.delegates = (Object[]) delegates.clone();

    }

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

{

        Class declaringClass = m.getDeclaringClass();

        for (int i = 0; i < interfaces.length; i++) {

            if (declaringClass.isAssignableFrom(interfaces[i]))

            {

                try

                {

                    return m.invoke(delegates[i], args);

                } catch (InvocationTargetException e)

                {

                    throw e.getTargetException();

                }

            }

        }

        return methodNotFound(proxy, m, args);

    }

    protected Object methodNotFound(Object proxy, Method m,

                                    Object[] args)

            throws Throwable

    {

        throw new InternalError("unexpected method dispatched: " + m);

    }

 

}

4.3  代理调用

Class[] proxyInterfaces = new Class[]{Color.class, Flavor.class};

Object obj = Proxy.newProxyInstance(Color.class.getClassLoader(),

        proxyInterfaces,

        new MultipleProxy(proxyInterfaces, new Object[]{new Red(), new Spicy()}));

//3个参数:装载工具、接口类集、实现类(接口类集、接口实现类)

Color color = (Color) obj;

color.show();

Flavor flavor = (Flavor) obj;

flavor.taste();