当前位置: 首页 > news >正文

1、代理模式

二、结构型模式

    1、代理模式

        (1)、概述

            代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象。这样做的好处是:在不改动原有代码的前提下,在已有代码基础上添加新的功能,从而增强原功能。这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法。

        (2)、分类

            ①、静态代理(静态定义代理类):静态代理实现起来比较简单,需要提前定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。但静态代理需要去实现每一个被代理的类以及方法,如果被代理的方法比较多,会比较繁琐。

            ②、动态代理(动态生成代理类):

                a、JDK动态代理:需要被代理类一定要实现某个接口,而代理类只需要实现InvocationHandler接口。代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)。只能对实现了接口的类生成代理,而不能针对类,对于没有实现接口的类无法实现JDK动态代理。Spring会使用JDK Proxy去创建代理对象,而对于没有实现接口的对象,就无法使用JDK Proxy去进行代理,因为Proxy.newProxyInstance()方法会返回的是一个指定接口的代理类实例,需要用接口接收。

                b、cglib动态代理:提供的动态代理不需要类实现了某个接口,是针对类实现代理。cglib采用继承的方式实现动态代理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。

        (3)、静态代理的代码实现

            ①、定义Automobile接口

public interface Automobile {

    String doSomething(String series);

}

            ②、被代理类实现Automobile接口

public class Benz implements Automobile {

    @Override

    public String doSomething(String series) {

        return String.format("德国奔驰:%s",series);

    }

}

            ③、代理类实现Automobile接口

public class BeijingBenz implements Automobile {

    private Benz benz;

    public BeijingBenz(Benz benz){

        this.benz = benz; 

    }

    @Override

    public String doSomething(String series) {

        System.out.println("我是北京奔驰,我代理德国奔驰");

        String msg =  benz.doSomething(series);

        System.out.println(msg);

        return msg;

    }

}

            ④、实现静态代理

public class Main {

    public static void main(String[] args) {

        Benz benz = new Benz();

        BeijingBenz beijingBenz = new BeijingBenz(benz);

        beijingBenz.doSomething("S600");

    }

}

            ⑤、实际应用

                TokenCallable通过代理Callable实现token的传递,以及日志打印的一些信息。

public class TokenCallable<V> implements Callable<V> {

    private final String accessToken;

    /**

     * 被代理的Callable

     */

    private final Callable<V> delegate;

    private final String taskName;

    public TokenCallable(Callable<V> delegate, String accessToken,String taskName) {

        this.delegate = CallableWrapper.of(delegate);

        this.accessToken = accessToken;

        this.taskName = taskName;

    }

    @Override

    public V call() throws Exception {

       long start = System.currentTimeMillis();

        LogUtil.debug("currentThreadId = " + Thread.currentThread().getId() + ",accessToken=" + accessToken);

        //给当前线程设置token

        AccessTokenUtil.setAccessToken(accessToken);

        V call = delegate.call();

        LogUtil.info("taskName =" + taskName + ",taskTime = " + (System.currentTimeMillis() - start) + " ms");

        return call;

    }

}

        (4)、JDK动态代理的代码实现

            ①、定义Automobile接口

public interface Automobile {

    String doSomething(String series);

}

            ②、被代理类实现Automobile接口

public class BMW implements Automobile {

    @Override

    public String doSomething(String series) {

        return String.format("德国宝马 %s", series);

    }

}

            ③、代理类实现InvocationHandler接口

public class HuachenBMW implements InvocationHandler {

    public Automobile target;

    public HuachenBMW(Automobile target) {

        this.target = target;

    }

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("来中国混,根据指示找代理");

        Object ret = method.invoke(target, args);

        System.out.println("代理车系是:" + ret);

        return ret;

    }

}

            ④、实现JDK动态代理

public class Main {

    public static void main(String[] args) {

        BMW BMW = new BMW();

        HuachenBMW huachenBMW = new HuachenBMW(BMW);

        //通过Proxy.newProxyInstance()方法返回一个指定接口的代理类实例

        Automobile automobile = (Automobile)Proxy.newProxyInstance(BMW.getClass().getClassLoader(),

                BMW.getClass().getInterfaces(),

                huachenBMW);

        String series = automobile.doSomething("X6");

        System.out.println("抢到一辆:"+ series);

    }

}

        (5)、cglib动态代理的代码实现

            ①、引入cglib的jar包

<dependency>

    <groupId>cglib</groupId>

    <artifactId>cglib</artifactId>

    <version>3.2.10</version>

</dependency>

            ②、定义被代理类

public class Audi {

    public String doSomething(String series){

        System.out.println("原产于德国的奥迪汽车");

        return String.format("德国奥迪,车系是:%s", series);

    }

}

            ③、代理类实现MethodInterceptor接口

public class FirstAudi implements MethodInterceptor {

    @Override

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        System.out.println("代理德国奥迪汽车");

        Object series =  methodProxy.invokeSuper(o, objects);

        System.out.println(series);

        return series;

    }

}

            ④、实现cglib动态代理

public class Main {

    public static void main(String[] args) {

        Enhancer enhancer = new Enhancer();

        enhancer.setSuperclass(Audi.class);

        enhancer.setCallback(new  FirstAudi());

        Audi audi = (Audi) enhancer.create();

        audi.doSomething("A8");

    }

}

        注:JDK内置动态代码采用Java反射机制实现,cglib库实现的动态代理,采用的是ASM直接操作字节码方式实现。由于反射操作的效率要低于直接操作字节码的效率,所以,cglib实现动态代理效率上比JDK内置的动态代理要好。

相关文章:

  • python-json校验-jsonpath
  • 解密Kerberos流量
  • [网鼎杯 2018]Comment
  • Java基础JDK命令行工具(jpd,jstat,jstack,jinfo)
  • 【构建并发程序】8-并发队列之阻塞队列
  • Mysql之用户管理
  • 内网边界代理
  • 【CSS】笔试题精讲
  • Java并发技术基础
  • (附源码)ssm本科教学合格评估管理系统 毕业设计 180916
  • python打包exe
  • ros rviz显示orb-slam2保存的轨迹
  • Part 10:Pandas的axis参数【详解】--Pandas和Numpy的结合
  • 【Linux集群教程】02 高可用集群
  • 吴恩达对话刘慈欣:让科幻更有勇气,让人工智能更有想象力
  • hexo+github搭建个人博客
  • 《深入 React 技术栈》
  • 【跃迁之路】【477天】刻意练习系列236(2018.05.28)
  • Codepen 每日精选(2018-3-25)
  • codis proxy处理流程
  • create-react-app做的留言板
  • css属性的继承、初识值、计算值、当前值、应用值
  • Docker: 容器互访的三种方式
  • Electron入门介绍
  • Hexo+码云+git快速搭建免费的静态Blog
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • Java应用性能调优
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • PHP 7 修改了什么呢 -- 2
  • ReactNative开发常用的三方模块
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • Yeoman_Bower_Grunt
  • 测试如何在敏捷团队中工作?
  • 当SetTimeout遇到了字符串
  • 分类模型——Logistics Regression
  • 高程读书笔记 第六章 面向对象程序设计
  • 前端代码风格自动化系列(二)之Commitlint
  • 嵌入式文件系统
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • ionic入门之数据绑定显示-1
  • 从如何停掉 Promise 链说起
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • ​批处理文件中的errorlevel用法
  • # 透过事物看本质的能力怎么培养?
  • (env: Windows,mp,1.06.2308310; lib: 3.2.4) uniapp微信小程序
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (笔试题)合法字符串
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (附源码)springboot掌上博客系统 毕业设计063131
  • (附源码)ssm教材管理系统 毕业设计 011229
  • (附源码)计算机毕业设计SSM疫情居家隔离服务系统
  • (三) diretfbrc详解
  • (十六)Flask之蓝图
  • (数位dp) 算法竞赛入门到进阶 书本题集
  • (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)