博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式之代理模式(上) 静态代理与JDK动态代理
阅读量:5950 次
发布时间:2019-06-19

本文共 3096 字,大约阅读时间需要 10 分钟。

hot3.png

代理模式

  • 给某一个对象提供一个代理,并由代理对象控制对原对象的引用。

静态代理

静态代理是由我们编写好的类,在程序运行之前就已经编译好的的类,此时就叫静态代理。 说理论还是比较懵逼的,直接上代码:

抽象主题,可以想象成我们的业务接口。

/** * 抽象主题。 * @author wushuaiping * @date 2018/3/13 下午10:13 */public interface ISubject {    /**     *  比如现在有个业务功能,需要开启某项校验。     */    void enableCheck();}

真实主题,可以想象成我们对业务接口的实现类。

/** *  真实主题 * @author wushuaiping * @date 2018/3/13 下午10:21 */public class RealSubject implements ISubject {    public void enableCheck() {        System.out.println("我开启了某项校验~~");    }}

但是有一天,我突然想加个日志记录,但是我不想去改动原有的方法。那么我们就可以使用这种方式:

/** *  代理类 * @author wushuaiping * @date 2018/3/13 下午10:23 */public class ProxySubject implements ISubject{    private ISubject subject;    public ProxySubject(ISubject subject){        super();        this.subject = subject;    }    // 对被代理对象的方法进行增强    public void enableCheck() {        before();        subject.enableCheck();        after();    }    private void before(){        System.out.println("我记录一下启动校验前的相关日志。");    }    private void after(){        System.out.println("我记录一下启动校验后的相关日志。");    }}

我们使用静态代理后,来试试看这种方式能不能行?测试代码:

public class Main{    public static void main(String[] args) throws ApiException {        ProxySubject proxy = new ProxySubject(new RealSubject());        proxy.enableCheck();    }}

运行结果:

我记录一下启动校验前的相关日志我开启了某项校验~~我记录一下启动校验后的相关日志。

静态代理模式相对比较简单,但是缺点肯定也是有的:

  1. 一个代理对象只能服务于一个类。如果有很多类需要记录日志的话,你的一个一个去实现。。累不死你。。

  2. 代理对象必须实现接口,如上。一个字:还是累。

动态代理

这里动态代理使用的是JDK的动态代理实现的,JDK的动态代理必须是目标对象实现接口才可以。也就是相当于我们上面的业务实现类(RealSubject)。使用CGLIB就不用实现接口也可完成动态代理,但是今天时间不多了,明天还得搬砖,所以先把JDK动态代理学了,明天再学学CGLIB的动态代理。 代码如下:

要实现动态代理;需要先去实现InvocationHandler接口,这个接口提供了invoke方法,该方法相信用过反射或者AOP的同学应该都比较熟悉,我这里就不多讲了。实现了这个后我们可以调用目标方法了,但是我们需要代理的对象还不知道从何而来,所以我们还需要使用JDK提供的Proxy.newProxyInstance方法,第一个参数是目标代理类的类加载器,第二个参数是目标代理类实现的接口,第三个参数的话是目标代理类的调用处理程序就是InvokeHandler啦。用该方法可以生产代理对象。

/** *  使用Java的动态代理实现 * @author wushuaiping * @date 2018/3/13 下午10:43 */public class DynamicProxy implements InvocationHandler {    private Object target;    public Object getProxyInstance(Object target){        this.target = target;        // 使用Java的获取代理实例方法来获取代理实例。。好绕啊。。反正就是获取代理实例-_-        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this);    }    // 增强, 调用目标方法    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        before();        // 因为我们需要被增强的方法enableCheck是没有返回参数的,所以不需要返回值。        // 如果有返回值 Object res = method.invoke(proxy, args); return res;就可以了        method.invoke(target, args);        after();        return null;    }    private void before(){        System.out.println("操作之前的日志记录~~");    }    private void after(){        System.out.println("操作之后的日志记录~~");    }}

Test case

public static void main(String[] args) throws ApiException {        DynamicProxy proxy = new DynamicProxy();        ISubject subject = (ISubject)proxy.getProxyInstance(new RealSubject());        subject.enableCheck();    }

运行结果:

操作之前的日志记录~~我开启了某项校验~~操作之后的日志记录~~

今天的设计模式算是学完啦,抽象工厂模式感觉我可能思维不够抽象,所以到现在还没能理解抽象工厂模式到底能干嘛?实际中有何用处?本文用于个人学习记录,有写的不好的地方,还请各位大佬指点一二!

good night!

转载于:https://my.oschina.net/u/3152087/blog/1634283

你可能感兴趣的文章
JMS 实例讲解
查看>>
求教:如何成为一个优秀的项目经理人
查看>>
shell 脚本--备份、还原mysql数据库
查看>>
JS脚本静态变量调用方法
查看>>
linux中cacti和nagios整合
查看>>
Parallels Desktop12推出 新增Parallels Toolbox
查看>>
正则表达式验证身份证格式是否正确
查看>>
Firebird(全功能的,免维护的数据库,能够管理多个独立的数据库) V2.1.3 英文特别版...
查看>>
xml格式文件解析
查看>>
ios百度地图-路径规划
查看>>
Python高效编程技巧
查看>>
配置Eclipse使用maven构建项目默认JDK为1.8
查看>>
jsp内置对象以及jsp动作
查看>>
Struts上路_09-数据类型转换
查看>>
CMake与动态链接库(dll, so, dylib)
查看>>
myeclipse(eclipse)乱码处理
查看>>
SpringBoot 过滤器, 拦截器, 监听器 对比及使用场景
查看>>
数据库索引探索
查看>>
struts2使用json需要注意的问题
查看>>
gitlab runner 优化
查看>>