代理模式应用场景十分普遍,随便一个
框架
都会用到,所以学好代理模式对后续框架学习是最基本的要素!!今天咱们就来说讲代理模式
!java
代理模式
的定位,它是
结构性模式
Proxy patternweb
经过代理,控制对对象的访问
设计模式
能够详细的访问某个(某类)对象的实现,在调用这个方法前作前置处理,调用这个方法后作后置处理(AOP的微观实现)安全
代理模式是SpringAOP
的核心实现机制!框架
抽象角色svg
公共对外方法
,通常会使用接口或者抽象类来解决真实角色学习
业务
,供代理角色调用代理角色测试
客户this
安全代理:屏蔽对真实角色的直接访问。
远程代理:经过代理类处理远程方法调用(RMI)
延迟加载:先加载轻量级的代理对象,真正须要再加载真实对象。spa
static proxy
接下来以房东租房这件实例,来说讲代理模式
房东
要租房
,若是房东
懒得管太多,这时候就须要一个中介
,来帮助房东
租房并打理一切事情,这时候租房者
就不须要直接和房东
打交道了,而是经过中介
间接和房东打交道,中介
就是中间者,代理了房东
,且能够在租房先后附加其余操做,好比:签合同,看房子等
这时候对象上述的四个角色就有四个对象:
抽象角色
:租房业务真实角色
:房东代理角色
:中介,可能还有带客户看房子等业务客户
:租房者接下来,咱们经过代码还原上述四个角色
抽象角色:表示租房
这个业务,用接口实现
//租房 public interface Rent { public void rent(); }
真实角色:表明房东
,实现租房业务接口
//房东 public class Host implements Rent{ public void rent() { System.out.println("房东要出租房子了"); } }
代理角色:中介
,实现租房业务接口
由于代理了房东
,因此私有属性是房东对象,除了租房子业务外,可能还有看房、签合同、收中介费等业务
public class Proxy implements Rent { private Host host; public Proxy() { } public Proxy(Host host) { this.host = host; } //代理租房子 public void rent() { seeHouse(); host.rent(); contract(); fare(); } //看房 public void seeHouse() { System.out.println("中介带你看房"); } //签合同 public void contract() { System.out.println("租赁合同"); } //收中介费 public void fare() { System.out.println("收中介费"); } }
客户:租房者
,访问中介
public class Client { public static void main(String[] args) { //房东租房子 Host host = new Host(); //代理,中介帮房东租房子,而且有一些附属操做 Proxy proxy = new Proxy(host); //不须要找房东,直接找中介租房便可 proxy.rent(); } }
好处:
职责清晰
使真实角色
更加的简单专注,无论具体的业务
智能化
客户只需访问代理角色,减小了直接访问真实角色带来的问题
高拓展性
业务发展拓展的时候,方便集中管理
缺点:
可能上述例子过于简单,不能直观的感觉到代理模式的好处,咱们再举个例子加深理解
首先建立一个业务实现接口
npublic interface UserService { public void add(); public void delete(); public void update(); public void query(); }
而后再来一个业务实现类
public class UserServiceImpl implements UserService { public void add() { System.out.println("增长一个用户"); } public void delete() { System.out.println("删除一个用户"); } public void update() { System.out.println("修改了一个用户"); } public void query() { System.out.println("查询了一个用户"); } }
再来个测试类
public class Client { public static void main(String[] args) { UserServiceImpl userService = new UserServiceImpl(); userService.add(); userService.delete(); userService.update(); userService.query(); } }
若是此时,咱们须要增长一个日志业务,须要打印每一个方法的执行
业务实现类
中的每一个方法中都要修改public class UserServiceImpl implements UserService { public void add() { System.out.println("使用了add方法"); System.out.println("增长一个用户"); } public void delete() { System.out.println("使用了delete方法"); System.out.println("删除一个用户"); } public void update() { System.out.println("使用了update方法"); System.out.println("修改了一个用户"); } public void query() { System.out.println("使用了query方法"); System.out.println("查询了一个用户"); } }
业务不少的状况下,修改量十分大,这时候用代理模式
就能很好的解决咱们的问题
咱们新建一个业务代理类
,在业务实现类里只需增长一个方法就能够实现上述新增业务
public class UserServiceProxy implements UserService { private UserServiceImpl userService; public void setUserService(UserServiceImpl userService) { this.userService = userService; } public void add() { log("使用了add方法"); userService.add(); } public void delete() { log("使用了delete方法"); userService.delete(); } public void update() { log("使用了update方法"); userService.update(); } public void query() { log("使用了query方法"); userService.query(); } public void log(String msg) { System.out.println("使用了" + msg + "方法"); } }
而后修改测试类,进行测试
package demo2; public class Client { public static void main(String[] args) { UserServiceImpl userService = new UserServiceImpl(); UserServiceProxy proxy = new UserServiceProxy(); proxy.setUserService(userService); proxy.add(); proxy.delete(); proxy.update(); proxy.query(); } }
因而可知:
高拓展性
dynamic proxy
动态生成
的,不是咱们直接写好的接下来咱们讲述
JDK自带的动态代理
须要了解:
Proxy
(代理)、InvocationHandler
(调用处理程序)
代理
全部方法:
建立动态类的方法:【重要】
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
每次经过Proxy生成的代理类对象都要指定对应的处理器对象,就是第三个参数
三个参数:
处理器接口
惟一的一个方法:
三个参数:
这里仍是以上述租房子为实例,咱们用动态代理的方式实现
Rent接口
(抽象角色) 和 Host类
(真实角色)不变
定义一个处理器接口实现类,继承InvocationHandler
其中的invoke方法实现对真实角色方法的调用,所以该类中有真实角色私有属性,为传参使用
package demo3; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyInvocationHandler implements InvocationHandler { //定义真实角色 private Rent host; //真实角色set方法 public void setHost(Rent host) { this.host = host; } /** 生成代理类方法 1. 类加载器,为当前类便可 2. 代理类实现的接口 3. 处理器接口对象 **/ public Object getProxy() { return Proxy.newProxyInstance(this.getClass().getClassLoader(), host.getClass().getInterfaces(), this); } //处理代理实例,并返回结果 //方法在此调用 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //调用真实角色方法 Object result = method.invoke(host, args); //附加方法 seeHouse(); contract(); fare(); return result; } //看房 public void seeHouse() { System.out.println("中介带你看房"); } //签合同 public void contract() { System.out.println("租赁合同"); } //收中介费 public void fare() { System.out.println("收中介费"); } }
测试类
package demo3; public class Client { public static void main(String[] args) { //真实角色:房东 Host host = new Host(); //处理器接口对象 ProxyInvocationHandler handler = new ProxyInvocationHandler(); //设置要代理的真实角色 handler.setHost(host); //动态生成代理类 Rent proxy = (Rent) handler.getProxy(); //调用方法 proxy.rent(); } }
结果
其余好处同静态代理