Spring(十三):设计模式——代理模式
Spring中AOP的底层原理就是动态代理模式,所以我们在这里对代理模式进行学习。
一、代理模式
1.什么是代理
代理,顾名思义,就是一个人代替另一个人去做他需要做的事情。代理是一种设计模式,具体实现就是一个类代替某个类去实现功能。
我们举一个例子:
我要租房子,我可以找房东直接租房子。同样我可以找中介来租房子,这个中介就是代理,它代理房东来做租赁房子的事情。
2.为什么需要代理模式呢?
我们的开发一般都是纵向开发,当有新的需求出现但又不想改变原有的业务逻辑时,就需要用到代理模式了,代理模式属于横向开发,我们只需要代理原来的业物逻辑并在代理类中添加新的功能即可。
二、静态代理
1.定义一个接口;
2.被代理类实现接口;
3.代理类引用被代理类,并且通过被代理类的方法实现接口。
我们以上图为例子,来进行一个静态代理的简单应用:
1.定义一个rental接口
package com.jms.demo01; //租房接口 public interface rental { void doRental(); }
2.被代理类landlord实现接口
package com.jms.demo01; //房东 public class landlord implements rental{ @Override public void doRental() { System.out.println("房东要出租房子"); } }
3.代理类intermediary引用被代理类,并且通过被代理类的方法实现接口。
package com.jms.demo01; //中介 public class intermediary implements rental{ private landlord landlord; public intermediary(landlord landlord) { this.landlord = landlord; } @Override public void doRental() { landlord.doRental(); seeHouse(); writeContract(); } public void seeHouse() { System.out.println("中介带你看房子"); } public void writeContract() { System.out.println("中介和你签合同"); } }
同时代理类可以根据实际需求添加自己的方法。
4.测试一下
package com.jms.demo01; //租客 public class Tenants { public static void main(String[] args) { landlord landlord = new landlord(); intermediary intermediary = new intermediary(landlord); intermediary.doRental(); } }
三、动态代理
上面静态代理的缺陷很明显,一个代理类对应一个被代理类,当我们的被代理类数量相当庞大时,我们也要写出相应的数量的代理类才行,为了解决这个问题,我们就需要用到动态代理。
我们再以上面租房为例用动态代理实现。
1.接口还是上面的rental接口;
2.代理类landlord实现接口与静态代理相同;
3.动态代理没有代理类,而是通过java.lang.reflect.InvocationHandler和java.lang.reflect.Proxy来实现
具体写法如下:
package com.jms.demo3; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyInvocationHandler implements InvocationHandler { //被代理的接口 private Object target; public void setTarget(Object target) { this.target = target; } //生成得到代理类 public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } //处理代理实例并返回结果 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { java.lang.Object result = method.invoke(target, args); seeHouse(); writeContract(); return result; } }
这段代码适用于任何接口的动态代理,即拿即用。
我们在上面类中可以随意添加我们需要的方法,此处我将其修改如下:
package com.jms.demo3; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyInvocationHandler implements InvocationHandler { //被代理的接口 private Object target; public void setTarget(Object target) { this.target = target; } //生成得到代理类 public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } //处理代理实例并返回结果 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { java.lang.Object result = method.invoke(target, args); seeHouse(); writeContract(); return result; } public void seeHouse() { System.out.println("中介带你看房子"); } public void writeContract() { System.out.println("中介和你签合同"); } }
4.具体的使用
public class Tenants { public static void main(String[] args) { //被代理类 landlord landlord = new landlord(); ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(); //设置动态代理的接口 proxyInvocationHandler.setTarget(landlord); //获取接口 rental rental = (rental) proxyInvocationHandler.getProxy(); //执行具体操作 rental.doRental(); } }
(本文仅作个人学习记录用,如有纰漏敬请指正)