代理模式
代理通常指的通过一个代理类实现对真实类的控制访问。
在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。比如租房子时与中介沟通租房的一切事宜,不直接接触房东。
Java中根据代理的创建时期,代理的类型分为两种。
- 静态代理:程序员创建代理类或特定工具类源码对其编译,在程序运行前就生成了.class文件
- 动态代理:在程序运行时通过反射机制动态创建
静态代理
创建一个RentService
接口
1 2 3 4
| public interface RentService { void pay(); }
|
实现类
1 2 3 4 5 6 7
| public class RentServiceImpl implements RentService{
@Override public void pay() { System.out.println("房客付钱咯..."); } }
|
代理类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class RentServiceProxy implements RentService{ private RentService rentService;
public RentServiceProxy(RentService rentService) { this.rentService = rentService; }
public void see() { System.out.println("房客看房咯..."); }
@Override public void pay() { see(); rentService.pay(); sign(); }
public void sign() { System.out.println("房客签名咯..."); } }
|
测试类
1 2 3 4 5 6
| public class TestProxy { public static void main(String[] args) { RentService rentService = new RentServiceProxy(new RentServiceImpl()); rentService.pay(); } }
|
结果如图
通过RentServiceProxy
实现了对RentService
类的拓展,在测试类中代码量没有增加但是扩展了功能。
但静态代理的缺点在于:
- 当需要代理多个类的时候,由于代理对象要实现与目标对象一致的接口,有两种方式:
- 只维护一个代理类,由这个代理类实现多个接口,但是这样就导致代理类过于庞大。
- 新建多个代理类,每个目标对象对应一个代理类,但是这样会**产生过多的代理类。
- 当接口需要增加、删除、修改方法的时候,目标对象与代理类都要同时修改,不易维护。
动态代理
Java中动态代理有两种实现方法:
涉及两个类 java.lang.reflect.Proxy
和 java.lang.reflect.InvocationHandler
。
Proxy
提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。
InvocationHandler
是由代理实例的调用处理程序实现的接口。
JDK 动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,就可以使用CGLIB实现。JDK 动态代理之所以只能代理接口是因为代理类本身已经 extends 了 Proxy,而java是不允许多重继承的,但是允许实现多个接口。
使用cglib代理的对象则无需实现接口,可以在运行时动态的生成某个类的子类,故需要某个类不能被标记为final
JDK动态代理
使用Proxy.newProxyInstance
方法生成代理对象
1 2 3
| public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
|
loader
为代理类的类加载器
interfaces
为代理类的接口数组
h
为方法调用处理器
使用 InvocationHandler
的 invoke
方法实现方法调用
1
| public Object invoke(Object proxy, Method method, Object[] args)
|
proxy
:触发方法的代理类实例
method
:代理类实现的接口中的方法
args
:方法参数
实现一个Handler,继承 InvocationHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class DynamicProxyHandler implements InvocationHandler { private RentService rentService;
public DynamicProxyHandler(RentService rentService) { this.rentService = rentService; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("房客看房咯..."); Object o = method.invoke(rentService, args); System.out.println("房客签名咯..."); return o; } }
|
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class TestProxy { public static void main(String[] args) { RentService target = new RentServiceImpl(); DynamicProxyHandler handler = new DynamicProxyHandler(target); RentService rentServiceProxy = (RentService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler); rentServiceProxy.pay(); } }
|
结果和静态代理类相同。
JDK中提供的生成动态代理类的机制有个鲜明的特点是: 某个类必须有实现的接口,而生成的代理类也只能代理某个类接口定义的方法。比如上面例子中如果RentServiceImpl
有其他方法live()
,JDK动态代理类中就没有这个方法。
而CGLIB(Code Generation Library)
没有接口也能实现动态代理
示例代码
自定义Interceptor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class RentInterceptor implements MethodInterceptor {
@Override public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("房客看房咯..."); Object result = methodProxy.invokeSuper(object, args); System.out.println("房客签名咯..."); return result; } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class TestProxy { public static void main(String[] args) { RentInterceptor interceptor = new RentInterceptor(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(RentServiceImpl.class); enhancer.setCallback(interceptor); RentServiceImpl proxy = (RentServiceImpl)enhancer.create(); System.out.println("cglib: " + proxy.getClass()); proxy.pay(); proxy.decorate(); } }
|
运行结果