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)
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) |