当前位置: > Linux教程 > Linux学习 >

proxy动态代理机制分析

时间:2016-03-11 23:21来源:linux.it.net.cn 作者:IT
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();
顶 (责任编辑:IT)
------分隔线----------------------------