代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能 *** 作,即扩展目标对象的功能.
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法。下面借用卖房子例子进行说明。
在某种情况下,客户类不能直接引用目标对象,需要通过代理对象去引用。一般的代理模式都会有一个接口,代理对象和目标对象共同实现这个接口。静态代理(继承,实现接口)和动态代理(基于接口的jdk动态代理,不基于接口的cglib动态代理)。
2.静态代理 2.1 手机销售案例,手机买卖都需要记录日志。业务接口类
public interface PhoneService { void buyPhone(int num); void salePhone(int num); }
业务实现类
public class PhoneServiceImpl implements PhoneService { public void buyPhone(int num) { System.out.println("手机进货"+num+"部"); } public void salePhone(int num) { System.out.println("手机销售"+num+"部"); } }
日志工具类
public class MyLogUtil { public void log(String method){ System.out.println(method+"被执行了"+new Date()); } }2.2基于接口的静态代理
public class ProxyStaticInterface implements PhoneService { MyLogUtil logUtil= new MyLogUtil(); public void buyPhone(int num) { System.out.println("手机进货"+num+"部"); logUtil.log("buyPhone"); } public void salePhone(int num) { System.out.println("手机销售"+num+"部"); logUtil.log("salePhone"); } }2.3基于继承的静态代理
public class ProxyStaticExtents extends PhoneServiceImpl { MyLogUtil logUtil= new MyLogUtil(); @Override public void buyPhone(int num) { super.buyPhone(num); logUtil.log("buyPhone"); } @Override public void salePhone(int num) { super.salePhone(num); logUtil.log("salePhone"); } }
测试类
public class TestProxy { public static void main(String[] args) { ProxyStaticInterface proxyStaticInterface = new ProxyStaticInterface(); proxyStaticInterface.buyPhone(200); ProxyStaticExtents proxyStaticExtents= new ProxyStaticExtents(); proxyStaticExtents.buyPhone(200); } }
测试结果
2.4静态代理总结
缺点:每一个目标对象,都需要匹配一个代理类,并且目标对象方法变更,代理类必须同步更新。
目标对象:具体的业务
代理对象:执行的过程中真正运行的对象
3.动态代理 3.1基于接口的jdk动态代理必须实现接口InvocationHandler(调用处理器)
public class ProxyDynamicInterfaceimplements InvocationHandler { //声明一个目标对象 private T obj; private LogUtil myLogUtil = new LogUtil(); //获取代理对象 public T getProxyObj(T target) { obj = target; T proxyInstance = (T)Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this); return proxyInstance; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("目标对象方法开始执行"); //方法执行之前增强处理 Object o = method.invoke(obj, args); //方法执行后增强处理 myLogUtil.log(method.getName()); return o; } }
测试代码
public class FactoryTest { public static void main(String[] args) { //创建目标对象,只能是接口类型,不然会报错 PhoneService phoneService = new PhoneServiceImpl(); //返回代理对象 ProxyDynamicInterfaceproxyDynamicInterface = new ProxyDynamicInterface(); PhoneService proxyObj = proxyDynamicInterface.getProxyObj(phoneService); //具体执行通过代理对象执行 proxyObj.buyPhone(200); proxyObj.salePhone(5); } }
测试结果
3.2不基于接口的cglib代理CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。spring框架自带cglib。对于没有实现接口的目标对象需要使用cglib动态代理。
引入cglib的依赖jar
cglib cglib3.3.0
创建动态代理工具类
//没有接口,只有一个类 public class ComputerServiceImpl { public void saleComputer(int num){ System.out.println("卖了"+num+"台电脑"); } } //代理工具类 public class ProxyDynamicCGlib { LogUtil logUtil = new LogUtil(); //获取代理对象 public Object getProxyObj(Class> clazz){ //定义一个字节码增强器 Enhancer enhancer = new Enhancer(); //设置增强对象,目标对象 enhancer.setSuperclass(clazz); //给增强器设置回调函数 //Interceptor是拦截器的意思,拦截目标对象的方法 enhancer.setCallback(new MethodInterceptor() { public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { //执行目标对象的方法 Object invokeSuper = methodProxy.invokeSuper(o, objects); //增强处理 logUtil.log(method.getName()); return invokeSuper; } }); //返回代理对象 return enhancer.create(); } }
测试类
public class Test1 { public static void main(String[] args) { ProxyDynamicCGlib proxyDynamicCGlib = new ProxyDynamicCGlib(); ComputerServiceImpl proxyObj1 = (ComputerServiceImpl) proxyDynamicCGlib.getProxyObj(ComputerServiceImpl.class); proxyObj1.saleComputer(250); } }
测试结果
以上就是java的三种代理模式的简单使用,这里还有上面三种模式的泛型改写源码 ,放到了我的资源里,需要的自取。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)