一、什么是动态代理
动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实。代理一般会实现它所表示的实际对象的接口。代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际功能,代理对象对客户隐藏了实际对象。客户不知道它是与代理打交道还是与实际对象打交道。
目的:主要用来做方法的增强,让你可以在不修改源码(不用改变这个方法的签名,原来调用这个方法的类依然能正常工作)的情况下,增强一些方法。在方法执行前后做任何你想做的事情(甚至根本不去执行这个方法),因为在InvocationHandler的invoke方法中,你可以直接获取正在调用方法对应的Method对象,具体应用的话,比如可以添加调用日志,做事务控制等。
还有一个有趣的作用是可以用作远程调用,比如现在有Java接口,这个接口的实现部署在其它服务器上,在编写客户端代码的时候,没办法直接调用接口方法,因为接口是不能直接生成对象的,这个时候就可以考虑代理模式(动态代理)了,通过Proxy.newProxyInstance代理一个该接口对应的InvocationHandler对象,然后在InvocationHandler的invoke方法内封装通讯细节就可以了。具体的应用,最经典的当然是Java标准库的RMI,其它比如hessian,各种webservice框架中的远程调用,大致都是这么实现的。
而像 AspectJ 这种 AOP 刚不同,它直接把人家的 class 代码修改了,它就不需要使用代理。
这些在新的 JDK 6 中都可以通过 Instrument 来做到,不过也是个通用的方法,还得通过规则来定制什么情况下处理,什么时候不处理。
二、jdk的动态代理
目前Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。 其实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。
Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现。
动态代理是很多框架和技术的基础, spring 的AOP实现就是基于动态代理实现的。了解动态代理的机制对于理解AOP的底层实现是很有帮助的。
平常写的代码,一般是一个对象直接持有另外一个对象的引用,称为
静态代理:
public class StaticProxyMain {
//这里传入的是接口类型的对象,方便向上转型,实现多态
public static void consumer(ProxyInterface pi){
pi.say();
}
public static void main(String[] args) {
StaticProxyMain.consumer(new ProxyObject());
}
}
//代理接口
interface ProxyInterface{
void say();
}
//被代理者
class RealObject implements ProxyInterface{
//实现接口方法
@Override
public void say() {
System.out.println("say");
}
}
//代理者
class ProxyObject implements ProxyInterface{
@Override
public void say() {
System.out.println("hello proxy");
new RealObject().say();
System.out.println("this is method end");
}
}
动态代理:
例子1:
public class DProxyMain {
public static void main(String[] args) {
ArrayList<String> content = new ArrayList<>();
MyInvocationHandler handler = new MyInvocationHandler(content);
Object proxy = Proxy.newProxyInstance(null, new Class[]{List.class}, handler);
if (proxy instanceof List) {
System.out.println("proxy is list");
List<String> mlist = (List<String>) proxy;
mlist.add("one");
mlist.add("two");
mlist.add("three");
mlist.add("apple");
}
System.out.println("proxy:"+proxy.toString());
System.out.println("content:"+content.toString());
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method name:"+method.getName());
if (method.getName().equals("add")) {
if (args[0].equals("apple")) {
return false;
}
}
return method.invoke(this.target, args);
}
}
例子2:
public class DynamicProxyMain {
public static void main(String[] args) {
RealObject realObject = new RealObject();
ProxyInterface proxyInterface = (ProxyInterface) Proxy.newProxyInstance(ProxyInterface.class.getClassLoader(), new Class[]{ProxyInterface.class}, new ProxyObject(realObject));
proxyInterface.say();
}
}
//代理接口
interface ProxyInterface{
void say();
}
//被代理类
class RealObject implements ProxyInterface {
@Override
public void say() {
System.out.println("I'm talking...");
}
}
//代理类,实现InvocationHandler 接口
class ProxyObject implements InvocationHandler {
private Object target = null;
public ProxyObject(Object proxied){
this.target = proxied;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method name:"+method.getName());
return method.invoke(this.target, args);
}
}
1. 利用动态代理实现设计模式,修饰器和适配器
2. AOP编程(Spring AOP)