1、定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗来讲就是中介。
2、UML类图
代理模式中的角色分析:
- 抽象对象角色(AbstractObject):声明了目标对象和代理对象的共同接口,这样依赖在任何可以使用目标对象的地方都可以使用代理对象;
- 目标对象角色(RealObject):定义了代理对象所代表的目标对象;
- 代理对象角色(ProxyObject):代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或者之后,执行某个操作,而不是单纯的将调用传递给目标对象。
3、代理模式的场景
- 中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口;
- 开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。
4、代理模式的种类
- 静态代理;
- 动态代理;
- CGLIB代理。
5、静态代理
实现原理:代理对象将客户端的调用委派给目标对象,在调用目标对象之前跟之后都可以执行特定的操作,一个目标对象对应一个代理对象。代理类在编译时期就已经确定。
1 /** 2 * @author it-小林 3 * @desc 抽象对象角色 4 * @date 2021年08月02日 20:35 5 */ 6 public abstract class AbstractObject { 7 8 /** 9 * 定义操作 10 */ 11 public abstract void operation(); 12 }
1 /** 2 * @author it-小林 3 * @desc 目标对象角色 4 * @date 2021年08月02日 20:38 5 */ 6 public class RealObject extends AbstractObject { 7 @Override 8 public void operation() { 9 System.out.println("Do Something!"); 10 } 11 }
1 /** 2 * @author it-小林 3 * @desc 4 * @date 2021年08月02日 20:40 5 */ 6 public class ProxyObject extends AbstractObject{ 7 RealObject realObject = new RealObject(); 8 9 @Override 10 public void operation() { 11 //在调用目标对象之前 12 System.out.println("Before Do Something!"); 13 realObject.operation(); 14 //在调用目标对象之后 15 System.out.println("After Do Something"); 16 } 17 }
1 /** 2 * @author it-小林 3 * @desc 测试类 4 * @date 2021年08月02日 20:42 5 */ 6 public class Client { 7 public static void main(String[] args) { 8 AbstractObject abstractObject = new ProxyObject(); 9 abstractObject.operation(); 10 } 11 }
总结
- 可以做到不修改目标对象的前提下,扩展目标对象的功能;
- 不足之处就是因为代理对象需要同目标对象实现同样的接口,所以会有很多的代理类,造成类过多;并且,一旦接口中增加方法,目标对象同代理对象都需要进行维护。
6、动态代理
动态代理主要有如下特点:
- 代理对象不需要实现目标对象的接口;
- 代理对象的生成,使用的是Java的API,动态的在内存中构件代理对象(这需要我们指定创建代理对象/目标对象的接口的类型);
- 动态代理也叫做JDK代理、接口代理。
JDK中生成代理对象的API
代理类所在的包为:java.lang.reflect.Proxy
。
JDK实现代理只需要使用newProxyInstance
方法,但是该方法需要接收三个参数,源码中的方法定义为:
1 public static Object newProxyInstance(ClassLoader loader, 2 Class<?>[] interfaces, 3 InvocationHandler h) 4 throws IllegalArgumentException 5 { 6 //...... 7 }
注意,该方法在Proxy
类中是静态方法,且接收的三个参数依次为:
ClassLoader loader
:指定当前目标对象使用类加载器,获取加载器的方法是固定的。Class<?>[] interfaces
:目标对象实现的接口类型,使用泛型方式确认类型。InvocationHandler h
:事件处理。执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入。
/** * @author it-小林 * @desc 目标对象接口 * @date 2021年08月03日 8:58 */ public interface IUserDao { void save(); }
1 /** 2 * @author it-小林 3 * @desc 目标对象类 4 * @date 2021年08月03日 8:59 5 */ 6 public class UserDao implements IUserDao { 7 @Override 8 public void save() { 9 System.out.println("---------已经保存数据-------"); 10 } 11 }
1 /** 2 * @author it-小林 3 * @desc 创建动态代理对象 4 * 动态代理对象不需要实现接口,但是需要指定接口类型 5 * @date 2021年08月03日 9:03 6 */ 7 public class ProxyFactory { 8 //维护一个目标对象 9 private Object target; 10 //对象构造时,提供目标对象 11 public ProxyFactory(Object target) { 12 this.target = target; 13 } 14 15 //给目标对象生成代理对象 16 public Object getProxyInstance(){ 17 return Proxy.newProxyInstance( 18 target.getClass().getClassLoader(), 19 target.getClass().getInterfaces(), 20 new InvocationHandler() { 21 @Override 22 public Object invoke( 23 Object proxy, 24 Method method, 25 Object[] args) throws Throwable { 26 System.out.println("Begin Transaction"); 27 //执行目标对象方法 28 Object returnValue = method.invoke(target, args); 29 System.out.println("Commit Transaction"); 30 return returnValue; 31 } 32 } 33 ); 34 } 35 }
1 /** 2 * @author it-小林 3 * @desc 测试类 4 * @date 2021年08月03日 9:10 5 */ 6 public class Client { 7 public static void main(String[] args) { 8 //目标对象 9 IUserDao userDao = new UserDao(); 10 //原始类型 11 System.out.println(userDao.getClass()); 12 13 //给定目标对象。动态创建代理对象 14 IUserDao proxy = (IUserDao) new ProxyFactory(userDao).getProxyInstance(); 15 //代理对象类型 16 System.out.println(proxy.getClass()); 17 proxy.save(); 18 } 19 }