一、静态代理类:
由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。该模式有以下角色:
(1)抽象角色(Subject):负责声明真实对象和代理对象的共同接口;
(2)代理角色(ProxySubject):内部包含真实对象的引用,负责对真实对象进行再封装以提供特定的服务。
(3)真实角色(RealSubject):被代理的真实对象,负责提供实现的具体服务。
/** * 抽象角色 */ public interface Subject { public void say(); } /** * 真实角色 * */ public class RealSubject implements Subject { @Override public void say() { System.out.println("hello world!"); } } /** * 代理角色 */ public class ProxySubject implements Subject{ //真实角色引用 private Subject subject; public ProxySubject(Subject subject) { this.subject = subject; } @Override //对真实对象进行再封装,并在真实对象的前后进行切面处理 public void say() { System.out.println("start saying..."); //相当于回调 subject.say(); System.out.println("stop saying..."); } } /** * 测试类 */ @Test public void test2() { Subject s = new RealSubject(); ProxySubject ps = new ProxySubject(s); ps.say(); }
缺点:(1)当我们在抽象对象中增加一个方法时,那么不仅在真实角色中需要进行修改,代理角色中也要进行修改。
(2)每个代理类只能为一个抽象角色服务(如果我们一个代理类实现多个接口,那么一个代理就可以用到所有的接口的方法而非自己接口的方法),这样会产生过多的同功能代理类,而且各代理类除了调用的方法不一样之外,其它代码都一样,代码重复严重。
二、动态代理类
在程序运行时,运用反射机制动态创建而成。JDK提供了java.lang.reflect.InvocationHandler接口和java.lang.reflect.Proxy类支持动态代理的实现。
Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现。
/** * 抽象角色(同静态代理) */ public interface Subject { public void say(); } /** * 真实角色(同静态代理) * */ public class RealSubject implements Subject { @Override public void say() { System.out.println("hello world!"); } } /** * 动态代理类 * */ //继承自java.lang.reflect.InvocationHandler接口 public class DynamicProxy implements InvocationHandler{ //真实对象引用 private Object subject; public DynamicProxy(Object subject) { super(); this.subject = subject; } @Override public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { System.out.println("welcome "); Object result = method.invoke(subject, args); return result; } } /** * 测试类 */ @Test public void test4(){ Subject s = new RealSubject(); DynamicProxy dp = new DynamicProxy(s); Subject sProxy = (Subject)Proxy.newProxyInstance(s.getClass().getClassLoader(), new Class[]{Subject.class},dp); sProxy.say(); }
缺点:(1)只能代理实现了接口的类,有些类没实现接口的就不能使用JDK代理。
三、应用场合
(1)不允许直接访问某些类;
(2)对访问要做特殊处理等