本文共 3418 字,大约阅读时间需要 11 分钟。
代理模式Proxy,就是在访问原始的对象的时候,引入一定的简介手段,附加更多的功能,这样保证不影响原始代理核心功能的基础上可以增加额外功能(AOP思想)。
/** * 定义一个政策接口 */public interface IPolicy { /** * 执行政策方法 */ void executePolicy();}/** * 实现政策接口,进行业务逻辑处理 */public class Policy implements IPolicy { @Override public void executePolicy() { System.out.println("执行政策!"); }}
根据需求,我们在政策执行之前需要进行校验,那么我们一般的做法就是继承Policy,重写父类方法
** * 继承的方式,添加普通类型政策的校验逻辑 */public class CommonPolicy extends Policy { private String policyId; /*省略get,set方法*/ @Override public void executePolicy() { System.out.println("校验普通政策ID, 政策id = " + policyId); System.out.println("执行政策!"); }}
这样做其实是违背了“开闭原则”,虽然拓展,但对修改开放了,为了解决这个问题,我们可以采取代理模式,主要分为静态代理和动态代理
代理者和原始对象继承或者遵从同一个接口,但是原始对象中值操作核心功能,而代理者则将附加功能写入,并在类内新建原始对象,然后调用其核心方法,这样就在核心功能继承上附加了额外功能,外部只需要调取代理。
/** * 改进:与Policy一样遵从同一套接口,同时将Policy实现类传入,调用其方法 * 这样可以保证对原方法的修改关闭,而增加了拓展(切面增强功能,开闭原则) * JDK代理方式 */public class SpecialPolicy implements IPolicy { private String policyId; private Policy policy; /*get\set*/ @Override public void executePolicy() { System.out.println("校验特殊政策ID, 政策id = " + policyId); policy.executePolicy(); }}
当然,我们还可以使用继承
/** * 改进:也可以使用继承来实现同样的功能(CgLib代理方式) */public class SpecialPolicy2 extends Policy { private String policyId; private Policy policy; /*get\set*/ @Override public void executePolicy() { System.out.println("校验特殊政策ID, 政策id = " + policyId); policy.executePolicy(); }}
但是这种方式还有个问题,如果政策量很大,那岂不是我的每个政策都要加一个“执行政策!”
这个业务逻辑?!
本质就是利用Java反射技术将零散的目标类各个属性重组,并改写其中的方法,返回一个与原始类属性一模一样的代理类。
public class SomePolicy implements IPolicy { private String policyId; /*get/set*/ public void executePolicy() { System.out.println("政策校验,policyId = " + policyId); }}/*使用JDK反射包中的代理接口*/public class ProxyHandler implements InvocationHandler { //目标:被代理类 private Object target; public Object getProxy(Object target) { this.target = target; /** * 将目标对象传入,反射获取目标对象的类加载器、所有接口 * this=当前对象,该对象实现了InvocationHandler接口所以有invoke方法,通过invoke方法可以调用被代理对象的方法 */ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } /** * 代理类执行的方法 * @param proxy “被”代理的对象(原始对象) * @param method 需要执行的方法 * @param args 方法执行的参数 * @return * @throws Throwable 异常 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; //AOP-before:业务增强 result = method.invoke(target, args); //AOP-after:业务增强 System.out.println("执行政策!"); return result; }}
我们测试一下:
@Testpublic void testProxyHandler() { ProxyHandler proxyHandler = new ProxyHandler(); SomePolicy somePolicy = new SomePolicy(); somePolicy.setPolicyId(UUID.randomUUID().toString()); //必须强转为接口对象,即后面somePolicy实现类的父对象 IPolicy iPolicy = (IPolicy) proxyHandler.getProxy(somePolicy); iPolicy.executePolicy();}//打印结果政策校验,policyId = 38c90df8-4dde-44ba-bacb-6990fc34bb05执行政策!
这里要注意:
1、当调用“executePolicy()
”方法的时候,其实调用的不是真正的方法,而是将方法名和参数传入到了InvocationHandler
的invoke()
方法,进行代理增强 2、进行对象强转的时候,必须转为接口对象,而不能是实现对象,否则会抛出不能同级转换的异常 java.lang.ClassCastException: com.sun.proxy.$Proxy6 cannot be cast to com.flight.carryprice.rjmodel.impl.SomePolicy
转载地址:http://lpgzi.baihongyu.com/