代理是基本的设计模式之一,它是你为了提供额外的或不同的操作,而插入用来代替实际对象的对象,这些操作通常涉及与"实际"对象的通讯,因此代理通常充当中间人的角色.
动态代理并非是日常使用的工具,但是它可以非常好的解决某些类型的问题.
下面是一个用来展示代理结构的简单示例:
public interface Interface {
void doSomething();
void somethingElse(String arg);
}
public class RealObject implements Interface{
@Override
public void doSomething() {
System.out.println("doSomething");
}
@Override
public void somethingElse(String arg) {
System.out.println("somethingElse "+arg);
}
}
public class SimpleProxy implements Interface{
private Interface proxied;
public SimpleProxy(Interface proxied) {
this.proxied = proxied;
}
@Override
public void doSomething() {
System.out.println("SimpleProxy doSomething");
proxied.doSomething();
}
@Override
public void somethingElse(String arg) {
System.out.println("SimpleProxy somethingElse");
proxied.somethingElse(arg);
}
}
public class SimpleProxyDemo {
public static void consumer(Interface inter){
inter.doSomething();
inter.somethingElse("boon");
}
public static void main(String[] args) {
consumer(new RealObject());
consumer(new SimpleProxy(new RealObject()));
}
}
输出结果:
doSomething
somethingElse boon
SimpleProxy doSomething
doSomething
SimpleProxy somethingElse
somethingElse boon
在任何时刻,只要你想将额外的操作从"实际"对象中分离到不同的地方,特别是当你希望能够很容易的做出修改,从没有使用额外操作转为使用这些操作,或者反过来时,代理就显得很有用(设计模式的关键就是封装修改,因此你需要修改事务以证明这种模式的正确性)
java的动态代理比代理的思想更迈进了一步,因此它可以动态的创建代理并动态的对所代理方法的调用,在动态代理上所做的调用都会被重定向到单一的 调用处理器上,它的工作是确定调用的类型并确定相应的策略,下面是重写动态代理的SimpleProxyDemo
public class DynamicProxyHandler implements InvocationHandler {
private Object proxied;
public DynamicProxyHandler(Object proxied) {
this.proxied = proxied;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("**** proxy :"+proxy.getClass()+
",method :"+method+",args :"+args);
if (args != null){
for (Object arg : args) {
System.out.println(" "+arg);
}
}
return method.invoke(proxied,args);
}
}
修改SimpleProxyDemo
public static void main(String[] args) {
// consumer(new RealObject());
// consumer(new SimpleProxy(new RealObject()));
RealObject real = new RealObject();
Interface proxy = (Interface)Proxy.newProxyInstance(Interface.class.getClassLoader(),
new Class[]{Interface.class}, new DynamicProxyHandler(real));
consumer(proxy);
}
输出结果:
**** proxy :class com.sun.proxy.$Proxy0,method :public abstract void thinking_java14.proxy.Interface.doSomething(),args :null
doSomething
**** proxy :class com.sun.proxy.$Proxy0,method :public abstract void thinking_java14.proxy.Interface.somethingElse(java.lang.String),args :[Ljava.lang.Object;@50040f0c
boon
somethingElse boon
通过调用静态方法Proxy.newProxyInstance()可以创建动态代理,这个方法需要得到一个类加载器(通常可以自己从已经被加载的对象中获取类加载器,然后传递给它),一个希望该代理实现的接口列表(不是类或抽象类),以及InvocationHandler接口的一个实现类.动态代理可以将所有调用重定向到调用处理器,因此通常会向调用处理器的构造参数传递一个实际对象的引用,从而使得调用处理器在执行其中介任务时,可以将请求转发/
invoke()方法中传递进来了代理对象,以防你需要区分请求的来源,但在多数情况下,你不需要关心这一点,然而,在invoke内部,在代理上调用方法时需要格外小心,因为对接口的调用会被重定向到对代理的调用.
通常,你会执行被代理的操作,然后使用Method.invoke()将请求转发给代理对象,并传入需要的参数.这初看起来有些受限,就像你只能执行范化操作一样,但是可以通过传入其他的参数,来过滤某些方法调用:
public interface SomeMethods {
void boring1();
void boring2();
void boring3();
void interesting(String arg);
}
public class Implementation implements SomeMethods{
@Override
public void boring1() {
System.out.println("boring1");
}
@Override
public void boring2() {
System.out.println("boring2");
}
@Override
public void boring3() {
System.out.println("boring3");
}
@Override
public void interesting(String arg) {
System.out.println("interesting :"+arg);
}
}
public class MethodSelector implements InvocationHandler {
private Object proxied;
public MethodSelector(Object proxied) {
this.proxied = proxied;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("interesting")){
System.out.println("Proxy detected the interesting method");
}
return method.invoke(proxied,args);
}
}
public class SelectingMethods {
public static void main(String[] args) {
SomeMethods proxy= (SomeMethods)Proxy.newProxyInstance(SomeMethods.class.getClassLoader(),
new Class[]{SomeMethods.class}, new MethodSelector(new Implementation()));
proxy.boring1();
proxy.boring2();
proxy.boring3();
proxy.interesting("boon");
}
}
输出结果:
boring1
boring2
boring3
Proxy detected the interesting method
interesting :boon
这里只查看了方法名,你还可以查看方法签名的其他方面,甚至可以搜索特定的参数值.