房东租房的例子
有一个房东要出租房屋:
public class Host implements Rent {
public void rent() {
System.out.println("房东出租房屋");
}
}
public interface Rent {
void rent();
}
之前在静态代理的例子中,代理类是编译前写好的,并且对于每一个被代理的角色,都需要手动写一个代理类,非常麻烦。在动态代理中,我们可以根据被代理的角色动态生成需要的代理类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
private Object object;
public void setObject(Object object) {
this.object = object;
}
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(object, args);
return result;
}
}
这里采用set方法注入被代理的类,需要实现InvocationHandler接口的方法invoke(),底层用到了反射机制。这段代码对于任何一个被代理的类都可以使用,大大减少了代码量。
有一个打工人前来租房,他需要new一个房东,再new一个代理生成类,然后将房东注入代理生成类并通过getProxy()拿到代理类,然后就可以租房了:
public class Client {
public static void main(String[] args) {
Host host = new Host();
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setObject(host);
Rent proxy = (Rent) pih.getProxy();
proxy.rent();
}
}
分析
- 首先与静态代理相比,生成代理类的操作明显变复杂了,但是具备通用性,减少了代码量。
- 这里的动态代理是基于接口的JDK原生动态代理,此外还有CGLIB动态代理可以了解一下。
- 对于租客来说操作是不是略复杂?Spring的AOP好像可以解决这个问题?
总结
静态代理和动态代理都解决了不改动被代理类的情况下,对被代理类的功能进行扩展的问题。以后有时间可以研究一下动态代理的InvocationHandler接口和Proxy类的原理。