大话设计模式之代理模式
代理模式
可以理解为一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
通过代码分析理解
//买房动作 public interface BuyHouse { void buyHouse(); } //客户直接买房 public class BuyHouseImpl implements BuyHouse { @Override public void buyHouse() { System.out.println("我要买房子"); } } //通过代理(中介)买房 public class BuyHouseProxy implements BuyHouse { BuyHouse buyHouse; public BuyHouseProxy(BuyHouse buyHouse){ this.buyHouse=buyHouse; } @Override public void buyHouse() { System.out.println("买房前准备"); buyHouse.buyHouse(); System.out.println("买房后装修"); } }
main测试
public class MianTest { public static void main(String[] args){ BuyHouse buyHouse = new BuyHouseImpl(); BuyHouseProxy buyHouseProxy = new BuyHouseProxy(buyHouse); buyHouseProxy.buyHouse(); } } //执行结果 买房前准备 我要买房子 买房后装修
代理模式的应用场景:
1、远程代理,也就是为一个对象在不同的地址空间提供局部代表。
2、虚拟代理,是根据需要创建开销很大的对象。通过他来存放实例化需要很长时间的真是对象。
3、安全代理,用来控制真实对象访问时的权限。
4、智能引用,是指当调用真实对象时,代理处理另外一些事。
2018/9/10修改
上述代理模式是基于静态代理的一种实现,那么下面来讲解基于jdk的动态代理
动态代理实现之jdk动态代理
在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。
实现原理:采用反射技术
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。
代码实现(还是基于买房示例,现在我们只需创建一个动态代理类即可)
package com.chenpt.designModel.proxyFactory; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @Author: chen * @Description: jdk的动态代理 * @Date: created in 2018/9/10 * @Modified By: */ public class MyProxy implements InvocationHandler { public Object target; MyProxy(Object target){ this.target = target; } /** * @param proxy 需要代理的真实类 * @param method 真实类的方法 * @param args 方法所需参数 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("++++++before " + method.getName() + "++++++"); Object result = method.invoke(target,args); System.out.println("++++++after " + method.getName() + "++++++"); return result; } }
客户端
package com.chenpt.designModel.proxyFactory; import java.lang.reflect.Proxy; /** * @Author: chenpengtao * @Description: * @Date: created in 2018/7/24 * @Modified By: */ public class MianTest { public static void main(String[] args){ BuyHouse buyHouse2 = new BuyHouseImpl2(); MyProxy myProxy = new MyProxy(buyHouse2); try { BuyHouse subject = (BuyHouse) Proxy.newProxyInstance(myProxy.getClass().getClassLoader(),buyHouse2.getClass().getInterfaces(),myProxy); subject.buyHouse(); } catch (Throwable throwable) { throwable.printStackTrace(); } } } //执行结果 ++++++before buyHouse++++++ 我要买房子2 ++++++after buyHouse++++++
动态代理实现之cglib代理
cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。不能对final修饰的类进行代理。
实现原理:采用字节码(asm)技术
还以买房为例,现在只需实现cglib代理类即可
package com.chenpt.designModel.proxyFactory; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import org.springframework.context.annotation.Primary; import java.lang.reflect.Method; /** * @Author: chen * @Description: 基于cglib的动态代理 * @Date: created in 2018/9/10 * @Modified By: */ public class MyCglib implements MethodInterceptor{ private Object target; //相当于JDK动态代理中的绑定 public Object getInstance(Object target) { this.target = target; //给业务对象赋值 Enhancer enhancer = new Enhancer(); //创建加强器,用来创建动态代理类 enhancer.setSuperclass(this.target.getClass()); //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类) //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦 enhancer.setCallback(this); // 创建动态代理类对象并返回 return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("预处理——————"); methodProxy.invokeSuper(obj, args); //调用业务类(父类中)的方法 System.out.println("调用后操作——————"); return null; } }
客户端
package com.chenpt.designModel.proxyFactory; import java.lang.reflect.Proxy; /** * @Author: chenpengtao * @Description: * @Date: created in 2018/7/24 * @Modified By: */ public class MianTest { public static void main(String[] args){ BuyHouse buyHouse2 = new BuyHouseImpl2(); MyCglib myCglib = new MyCglib(); buyHouse2 = (BuyHouse) myCglib.getInstance(buyHouse2); buyHouse2.buyHouse(); } } //执行结果 预处理—————— 我要买房子2 调用后操作——————
作者:
不二尘
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。