zoukankan      html  css  js  c++  java
  • 设计模式之代理模式

    第一、代理模式定义

    代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。

    举个例子来说明:假如说我现在想买一辆二手车,虽然我可以自己去找车源,做质量检测等一系列的车辆过户流程,但是这确实太浪费我得时间和精力了。我只是想买一辆车而已为什么我还要额外做这么多事呢?于是我就通过中介公司来买车,他们来给我找车源,帮我办理车辆过户流程,我只是负责选择自己喜欢的车,然后付钱就可以了。用图表示如下:

    第二、使用代理模式的好处

    中介隔离:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。

    开闭原则,增加功能代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,

    符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。

    真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。

    使用动态代理的有2个目的:一、是保护目标对象;二、增强目标对象

    第三、代理的实现原理

    代理模式主要包含三个角色,即抽象主题角色(Subject)、委托类角色(被代理角色,Proxied)以及代理类角色(Proxy),如上图所示:

    抽象主题角色:可以是接口,也可以是抽象类;

    委托类角色:真实主题角色,业务逻辑的具体执行者;

    代理类角色:内部含有对真实对象RealSubject的引用,负责对真实主题角色的调用,并在真实主题角色处理前后做预处理和后处理。

    第三、代理模式的应用场景

    SpringAop、日志收集、权限控制、过滤器、RPC远程调用

    第三、代理模式创建的方式

    静态代理和动态代理

     3.1静态代理

    静态代理是由程序员创建或工具生成代理类的源码,再编译代理类。

    所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。一句话,自己手写代理类就是静态代理。

    代码实现1:

    /**
     * 目标接口
     */
    public interface OrderService {
        public void service();
    }
    /**
     * 目标实现类
     */
    public class OrderServiceImpl implements OrderService {
        @Override
        public void service() {
            System.out.println("实现类");
        }
    }
    /**
     * 静态代理类
     */
    public class OrderServiceProxy  implements OrderService {
        private OrderService orderService;
    
        public OrderServiceProxy(OrderService orderService) {
            this.orderService = orderService;
        }
        public void before(){
            System.out.println("方法执行之前增强");
        }
        public void after(){
            System.out.println("方法执行之后增强");
        }
    
        @Override
        public void service() {
            before();
            this.orderService.service();
            after();
        }
    }
    测试代码
    public class Test001 {
        public static void main(String[] args) {
            OrderServiceProxy orderServiceProxy = new OrderServiceProxy(new OrderServiceImpl());
            orderServiceProxy.service();
        }
    }

     静态代理实现多数据源切换代码实现

    /** 
     * 业务接口
     */
    public interface IOrderService {
    
        public int createOrder(Order order);
    }
    /**
     * 动态数据源切换
     */
    public class DynamicsDasourceEntity {
    
        private final  static String DEFAULT_SOURCE=null;
        private static ThreadLocal<String> threadLocal = new ThreadLocal();
    
        /**
         * 还原当前数据源
         */
        public static void setStore(){
            threadLocal.set(DEFAULT_SOURCE);
        }
        /**
         * 移除数据源
         */
        public static void clear(){
            threadLocal.remove();
        }
        /**
         * 设置默认数据源
         */
        public static void setDefaultSource(){
            threadLocal.set(DEFAULT_SOURCE);
        }
    
        /**
         * 根据已经知道数据源名称设置
         */
        public static void setDB(String dataSource){
            threadLocal.set(dataSource);
        }
    
        /**
         * 根据年份设置数据源
         * @param year
         */
        public static void setDB(int year){
            threadLocal.set("DB_"+year);
        }
        /**
         * 获取数据源
         * @return
         */
        public static String getDB(){
            return threadLocal.get();
    
        }
    }
    
    /**
     * 订单实体
     */
    public class Order {
        private Object orderInfo;
        private Long crateTime;
        private String id;
    
        public Object getOrderInfo() {
            return orderInfo;
        }
    
        public void setOrderInfo(Object orderInfo) {
            this.orderInfo = orderInfo;
        }
    
        public Long getCrateTime() {
            return crateTime;
        }
    
        public void setCrateTime(Long crateTime) {
            this.crateTime = crateTime;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    }
    /**
     * 持久层
     */
    public class OrderDao {
    
        public int insert(Order order){
            System.out.println("OrderDao创建Order成功");
            return 1;
        }
    }
    /**
     * 静态代理类实现数据源切换
     */
    public class OrderProxy implements IOrderService{
    
        private SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
    
        private IOrderService iOrderService;
        public OrderProxy(IOrderService iOrderService){
            this.iOrderService = iOrderService;
        }
    
        public void after(){
            System.out.println("方法之后执行");
        }
        public void before(){
            System.out.println("方法之前执行");
        }
    
        @Override
        public int createOrder(Order order) {
            before();
            Long crateTime = order.getCrateTime();
            String year = this.format.format(new Date(crateTime));
            Integer dbRouter = Integer.valueOf(year);
            System.out.println("静态代理已经将数据库切换到DB_"+dbRouter+"数据源处理数据");
            DynamicsDasourceEntity.setDB(dbRouter);
            iOrderService.createOrder(order);
            after();
            return 0;
        }
    }
    /**
     * 业务实现接类
     */
    public class OrderServiceImpl implements IOrderService {
        private OrderDao orderDao;
        public OrderServiceImpl(){
            orderDao = new OrderDao();
        }
        @Override
        public int createOrder(Order order) {
            return orderDao.insert(order);
        }
    }
    /**
     * 测试类
     */
    public class Test001 {
        public static void main(String[] args) {
            OrderProxy orderProxy = new OrderProxy(new OrderServiceImpl());
            Order order = new Order();
            order.setCrateTime(System.currentTimeMillis());
            orderProxy.createOrder(order);
        }
    }

    3.2JDK动态代理

    JDK动态代理实现的一般步骤:

    1、创建被代理的接口和类;

    2、实现InvoactionHandler接口,对目标接口中声明的方法统一进行处理;

    3、调用Proxy静态方法,创建代理类并生成相应的代理对象

    入门案例:

    /**
     * 目标接口
     */
    public interface OrderService {
        public void service();
    }
    /**
     * 目标实现类
     */
    public class OrderServiceImpl implements OrderService {
        @Override
        public void service() {
            System.out.println("目标实现类,service方法");
        }
    }
    /**
     * 动态代理类
     */
    public class OrderServiceProxy implements InvocationHandler {
        private Object target;
    
        public <T> T getIntance(Object obj){
            this.target = obj;
            Class<?> clazz = obj.getClass();
            return (T) Proxy.newProxyInstance(clazz.getClassLoader(),
                    clazz.getInterfaces(),this);
        }
        @Override
        public Object invoke(Object proxy, Method method,
                             Object[] args) throws Throwable {
            before();
            Object obj = method.invoke(this.target, args);
            after();
            return obj;
        }
        public void before(){
            System.out.println("方法执行之前");
        }
        public void after(){
            System.out.println("方法执行之后");
        }
    }
    /**
     * 测试类
     */
    public class Test001 {
        public static void main(String[] args) {
            OrderService orderService = new OrderServiceProxy()
                    .getIntance(new OrderServiceImpl());
            orderService.service();
        }
    }

    使用动态代理模拟多数据源切换

    /**
     * 业务接口
     */
    public interface IOrderService {
    
        public int createOrder(Order order);
    }
    /**
     * 动态数据源切换
     */
    public class DynamicsDasourceEntity {
    
        private final  static String DEFAULT_SOURCE=null;
        private static ThreadLocal<String> threadLocal = new ThreadLocal();
    
        /**
         * 还原当前数据源
         */
        public static void setStore(){
            threadLocal.set(DEFAULT_SOURCE);
        }
        /**
         * 移除数据源
         */
        public static void clear(){
            threadLocal.remove();
        }
        /**
         * 设置默认数据源
         */
        public static void setDefaultSource(){
            threadLocal.set(DEFAULT_SOURCE);
        }
    
        /**
         * 根据已经知道数据源名称设置
         */
        public static void setDB(String dataSource){
            threadLocal.set(dataSource);
        }
    
        /**
         * 根据年份设置数据源
         * @param year
         */
        public static void setDB(int year){
            threadLocal.set("DB_"+year);
        }
        /**
         * 获取数据源
         * @return
         */
        public static String getDB(){
            return threadLocal.get();
    
        }
    }
    /**
     * 订单实体
     */
    public class Order {
        private Object orderInfo;
        private Long crateTime;
        private String id;
    
        public Object getOrderInfo() {
            return orderInfo;
        }
    
        public void setOrderInfo(Object orderInfo) {
            this.orderInfo = orderInfo;
        }
    
        public Long getCrateTime() {
            return crateTime;
        }
    
        public void setCrateTime(Long crateTime) {
            this.crateTime = crateTime;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    }
    /**
     * 持久层
     */
    public class OrderDao {
    
        public int insert(Order order){
            System.out.println("OrderDao创建Order成功");
            return 1;
        }
    }
    /**
     * 静态代理类实现数据源切换
     */
    public class OrderProxy implements InvocationHandler {
    
        private SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
    
        private Object target;
    
        public <T> T getIntance(Object object){
            this.target = object;
            Class<?> clazz = object.getClass();
            return (T) Proxy.newProxyInstance(clazz.getClassLoader(),
                    clazz.getInterfaces(),this);
        }
    
        public void after(){
            System.out.println("方法之后执行");
            DynamicsDasourceEntity.clear();
            System.out.println("数据源已经被移除了");
        }
        public void before(Object target){
            try {
                System.out.println("方法之前执行");
               Long time = (Long) target.getClass().getMethod("getCrateTime").invoke(target);
                String format = this.format.format(new Date(time));
                DynamicsDasourceEntity.setDB(Integer.parseInt(format));
                System.out.println("动态数据源已经被切换了:"+format);
            } catch (Exception ioe) {
                ioe.printStackTrace();
            } finally {
    
            }
        }
    
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            before(args[0]);
            Object obj = method.invoke(target, args);
            after();
            return obj;
        }
    }
    /**
     * 业务实现接类
     */
    public class OrderServiceImpl implements IOrderService {
        private OrderDao orderDao;
        public OrderServiceImpl(){
            orderDao = new OrderDao();
        }
        @Override
        public int createOrder(Order order) {
            return orderDao.insert(order);
        }
    }
    
    /**
     * 测试类
     */
    public class Test001 {
        public static void main(String[] args) {
            IOrderService orderService =
                    new OrderProxy().getIntance(new OrderServiceImpl());
            Order order = new Order();
            order.setCrateTime(System.currentTimeMillis());
            orderService.createOrder(order);
    
        }
    }

    3.3jdk动态代理原理分析

    JDK Proxy 生成对象的步骤:

       1、拿到被代理对象的引用,并获取他所有的接口,反射获取;

       2、JDK Proxy重新生成一个新的类、同时新的类要实现代理被代理对象的所有实现的所有的接口;

       3、动态生成java代码,把新增的业务逻辑的方法由一定的逻辑代码去调用;

        4、编译新生成的java代码.class

        5、重新加载到JVM中

    public class Test001 {
        public static void main(String[] args) {
    
            try {
                IOrderService orderService =
                        new OrderProxy().getIntance(new OrderServiceImpl());
                Order order = new Order();
                order.setCrateTime(System.currentTimeMillis());
                orderService.createOrder(order);
                //通过反编译查看源代码
                byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{IOrderService.class});
                FileOutputStream out = new FileOutputStream("E://$Proxy0.class");
                out.write(bytes);
                out.close();
            } catch (Exception ioe) {
                ioe.printStackTrace();
            } finally {
    
            }
    
        }
    }

    运行上面的代码之后,生成一个$Proxy.class,用反编译插件打开

    import com.yehui.dynamicproxy01.IOrderService;
    import com.yehui.dynamicproxy01.Order;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class $Proxy0
      extends Proxy
      implements IOrderService
    {
      private static Method m1;
      private static Method m2;
      private static Method m3;
      private static Method m0;
      
      public $Proxy0(InvocationHandler paramInvocationHandler)
      {
        super(paramInvocationHandler);
      }
      
      public final boolean equals(Object paramObject)
      {
        try
        {
          return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      public final String toString()
      {
        try
        {
          return (String)this.h.invoke(this, m2, null);
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      public final int createOrder(Order paramOrder)
      {
        try
        {
          return ((Integer)this.h.invoke(this, m3, new Object[] { paramOrder })).intValue();
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      public final int hashCode()
      {
        try
        {
          return ((Integer)this.h.invoke(this, m0, null)).intValue();
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      static
      {
        try
        {
          m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
          m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
          m3 = Class.forName("com.yehui.dynamicproxy01.IOrderService").getMethod("createOrder", new Class[] 
    { Class.forName("com.yehui.dynamicproxy01.Order") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } } }
    由上面的代码可以看出,新生成了$Proxy类,继承了Proxy类,同时还实现了IOrderService接口,而且还重写了createOrder()
    等方法,而且在静态代码块用反射查找到了目标对象的所有方法,而且保存了所有方法的引用,在重写的的方法用反射调用目标对象的方法

    注意继承了Proxy类,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。

    3.4Cglib动态代理

    3.4.1定义

    Cglib是一个强大的,高性能,高质量的代码生成类库。它可以在运行期扩展JAVA类与实现JAVA接口。其底层实现是通过ASM字节码处理框架来转换字节码并生成新的类。大部分功能实际上是ASM所提供的,Cglib只是封装了ASM,简化了ASM操作,实现了运行期生成新的class。

    3.4.2原理

    运行时动态的生成一个被代理类的子类(通过ASM字节码处理框架实现),子类重写了被代理类中所有非final的方法,在子类中采用方法拦截的技术拦截所有父类方法的调用,不需要被代理类对象实现接口,从而CGLIB动态代理效率比Jdk动态代理反射技术效率要高。

    3.4.3实现步骤

    实现MethodInterceptor接口的intercept方法后,所有生成的代理方法都调用这个方法。

    intercept方法的具体参数有

    obj 目标类的实例

    1. method 目标方法实例(通过反射获取的目标方法实例)

    2. args 目标方法的参数

    3. proxy 代理类的实例

    该方法的返回值就是目标方法的返回值。

    代码实现:

    /**
     * 目标实现类
     */
    public class Person {
        public void findLove(){
            System.out.println("找妹子");
        }
    }
    /**
     * cglib动态代理
     */
    public class OrderService implements MethodInterceptor {
    
        public <T> T getIntance(Object obj){
            //相当于Proxy,代理工具类
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(obj.getClass());
            enhancer.setCallback(this);
            return (T) enhancer.create();
        }
        @Override
        public Object intercept(Object o, Method method, Object[] objects,
                                MethodProxy methodProxy) throws Throwable {
            before();
            Object obj = methodProxy.invokeSuper(o, objects);
            after();
            return obj;
        }
        public void before(){
            System.out.println("方法之前执行");
        }
        public void after(){
            System.out.println("方法之后执行");
        }
    }
    /**
     * 测试类
     */
    public class CglibTest {
    
        public static void main(String[] args) {
            try {
                //打印到磁盘上
                System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"E://cglibproxy");
                Person person = new OrderService().getIntance(new Person());
                person.findLove();
            } catch (Exception ioe) {
                ioe.printStackTrace();
            } finally {
    
            }
    
        }
    }

     maven依赖

    <dependencies>

      <dependency>

          <groupId>cglib</groupId>

          <artifactId>cglib</artifactId>

           <version>3.2.12</version>

       </dependency>

    </dependencies>

     3.5动态代理与静态代理的区别

    1、静态代理只能通过手动完成代理操作,如果被代理类新增方法,代理类需要同步新增,违背开闭原则
    2、动态代理采用在运行时生成代码的方式取消了对代理类的扩展限制,遵循了开闭原则。
    3、若无动态代理要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类变课完成无需修改代理类的代码

    3.6JDK动态代理和Cglib代理的对比

    1、JDK动态代理是实现了被代理对象的接口,CGLIb是继承了被代理对象,CGLIB覆盖父类的方法
    2、JDK和CGLib都是在运行时期生成字节码,JDK是直接写Class字节码,cglib使用ASM框架写Class字节码,Cglib代理实现更复杂,生成代理类效率低
    3、JDK代理调用方法,是通过反射机制调用,CGLib是通过FastClass机制直接调用方法Cglib执行效率更高
    4、Cglib有个坑,CGLIb不能代理final的方法
    5、都是生成一个新的类,去实现增强代码逻辑的功能

     

  • 相关阅读:
    简单查询plan
    EXP AND IMP
    (4.16)sql server迁移DB文件(同一DB内)
    sql server日志传送实践(基于server 2008 R2)
    (1.3)学习笔记之mysql体系结构(C/S整体架构、内存结构、物理存储结构、逻辑结构、SQL查询流程)
    (1.2)学习笔记之mysql体系结构(数据库文件)
    (1.1)学习笔记之mysql体系结构(内存、进程、线程)
    SSAS(SQL Server 分析服务)、***S(SQL Server报表服务)、SSIS(SQL Server集成服务)
    教你使用SQL查询(1-12)
    Sql Server内置函数实现MD5加密
  • 原文地址:https://www.cnblogs.com/cxyyh/p/10888062.html
Copyright © 2011-2022 走看看