动态代理(JDK实现)

代理是基本的设计模式之一,代理通常充当着中间人的角色。


一个代理的简单示例:

/**
 * 代理结构的简单示例
 *
 */

interface Interface {
    void doSomething();
    void somethingElse(String arg);
}

class RealObject implements Interface {
    public void doSomething() {
        System.out.println("doSomething");
    }
    
    public void somethingElse(String arg) {
        System.out.println("somethingElse " + arg);
    }
}

class SimpleProxy implements Interface {
    private Interface proxied;
    
    public SimpleProxy(Interface proxied) {
        this.proxied = proxied;
    }
    
    public void doSomething() {
        System.out.println("SimpleProxy doSomething");
        proxied.doSomething();
    }
    
    public void somethingElse(String arg) {
        System.out.println("SimpleProxy somethingElse " + arg);
        proxied.somethingElse(arg);
    }
    
}

public class SimpleProxyDemo {
    
    public static void consumer(Interface iface) {
        iface.doSomething();
        iface.somethingElse("bonobo");
    }
    
    public static void main(String[] args) {
        consumer(new RealObject());
        consumer(new SimpleProxy(new RealObject()));
    }

}

    因为consumer()接受的是Interface,所以它无法知道正在获得的到底是RealObject还是SimpleProxy,因为这二者都实现了Interface。但是SimpleProxy已经被插入到了客户端和RealObject之间,因此它会执行操作,然后调用RealObject上相同的方法。

    如果你希望跟踪对RealObject中的方法调用,或者希望度量这些调用的开销,这些代码肯定不希望将其合并到应用中的代码,因此代理使得很容易地添加或移除它们(降低耦合度,业务逻辑与日志、事务、异常、开销等逻辑区分开)。

    Java的动态代理比代理的思想更向前迈进了一步,因为他可以动态地创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上。

    这样代理类不用因为新增一个接口就得加一个,动态代理实现了多个接口及多个方法都能用一个调用处理器来处理代理。

    可以通过调用静态方法 Proxy.newProxyInstance()创建动态代理。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 通过调用 Proxy.newProxyInstance()方法可以实现动态代理
 * @author cmdsm
 * 
 *
 */
// 实现调用处理器
class DynamicProxyHandler implements InvocationHandler {
	private Object proxied;
	
	public DynamicProxyHandler(Object proxied) {
		this.proxied = proxied;
	}
	
	/**
	 * 动态代理可以将所有调用重定向到调用处理器
	 * 
	 * invoke()方法传递进来了代理对象proxy,以防需要区分请求的来源,
	 * 但是许多情况下并不需要关心这一点。
	 * 在invoke()内部,在代理上调用方法时需要格外当心,因为对接口的调用将被重定向为对代理的调用
	 */
	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);
	}
}

public class SimpleDynamicProxy {
	
	public static void consumer(Interface iface) {
		iface.doSomething();
		iface.somethingElse("bonobo");
	}
	
	public static void main(String[] args) {
		RealObject real = new RealObject();
		consumer(real);
		// Insert a proxy and call again
		Interface proxy = (Interface) Proxy.newProxyInstance(
				// 需要一个类加载器,从哪个类获取都可以,一般从已加载的类获取
				Interface.class.getClassLoader(), 
				// 需要希望该代理实现的接口列表(不是类或抽象类)
				new Class[]{Interface.class}, 
				// 需要一个InvocationHandler(调用处理)接口的实现
				new DynamicProxyHandler(real));
		
		consumer(proxy);
	}

}


可以通过传递其他参数,来过滤某些方法调用

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 动态代理 过滤某些方法的调用
 * @author cmdsm
 *
 */
class MethodSelector implements InvocationHandler {
	private Object proxied;
	public MethodSelector(Object proxied) {
		this.proxied = proxied;
	}
	
	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);
	}

}

interface SomeMethods {
	void boring1();
	void boring2();
	void interesting(String arg);
	void boring3();
}


class Implementation implements SomeMethods {
	
	public void boring1() {System.out.println("boring1"); }
	public void boring2() {System.out.println("boring1"); }
	public void interesting(String arg) {
		System.out.println("interesting " + arg);
	}
	public void boring3() {System.out.println("boring1"); }
}

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.interesting("bonobo");
		proxy.boring3();
	}
}



输出:



摘自Java编程思想


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值