• 代理模式


    前言

    代理模式是一种常见的设计模式,它使用代理对象完成用户请求,屏蔽了用户对真实对象的访问。

    在软件设计中,使用代理模式的意图也很多。比如因为安全原因,屏蔽客户端直接访问真实对象。或者在远程调用中,使用代理类来屏蔽远程方法调用的技术细节。或为了提升系统性能,将真实对象封装,达到延迟加载的目的。比如hibernate就使用了cglib来实现延迟加载。
    这里使用代理模式实现延迟加载,提升系统性能和速度。

    不使用代理模式的直接调用

    这里定义一个IUserService接口类,提供一个request方法;UserService实现IUserService接口。Main为测试类。

    1
    2
    3
    4
    5
    6

    * Created by j.tommy on 2017/9/10.
    */
    public interface {
    String request();
    }

    1
    2
    3
    4
    5
    6
    7
    8
    9

    * Created by j.tommy on 2017/9/10.
    */
    public class UserService implements {

    public String request() {
    return "hello";
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    * Created by j.tommy on 2017/9/10.
    */
    public class Main {
    public static void main(String[] args) {
    IUserService ius = new UserService();
    String result = ius.request();
    System.out.println("result:" + result);
    }
    }

    静态代理

    下面定义一个UserServiceProxy来代理UserService,对外提供服务。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    * Created by j.tommy on 2017/9/10.
    */
    public class UserServiceProxy implements {
    private UserService us = null;

    public String request() {
    // 延迟加载us的实例,在实际使用时初始化
    if (null == us) {
    us = new UserService();
    System.out.println("Created UserService.");
    }
    return us.request();
    }
    }

    测试类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    * Created by j.tommy on 2017/9/10.
    */
    public class Main {
    public static void main(String[] args) {
    // 通过代理类调用
    IUserService ius = new UserServiceProxy();
    System.out.println("Created proxy.");
    String result = ius.request();
    System.out.println("result:" + result);
    }
    }

    输出:

    可以看到,在实际调用request()方法时才初始化UserService.
    静态代理很大的一个问题:所有的代理类必须实现接口,现在是一个UserService,如果还有其他的XXService,每个XXServiceProxy都需要实现XXService接口,这是很麻烦的。

    JDK动态代理

    上面看到了使用静态代理的一个大问题,我们可以通过JDK动态代理来实现。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17< 大专栏  代理模式/span>
    18
    19
    20
    21
    22
    23
    24

    * jdk动态代理。
    * Created by j.tommy on 2017/9/10.
    */
    public class JdkDynamicProxy implements InvocationHandler {
    // 真实对象
    private Object target;
    public JdkDynamicProxy(Object target) {
    this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 调用真实对象的方法
    Object result = method.invoke(target,args);
    return result;
    }

    * 获取目标对象的代理对象
    * @return
    */
    public Object getProxy() {
    return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),target.getClass().getInterfaces(),this);
    }
    }

    测试类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    * Created by j.tommy on 2017/9/10.
    */
    public class Main {
    public static void main(String[] args) {
    // JDK动态代理
    // 真实对象
    IUserService ius = new UserService();
    // 代理对象
    IUserService us = (IUserService) new JdkDynamicProxy(ius).getProxy();
    String result = us.request();
    System.out.println("result:" + result);
    }
    }

    如上代码,可以代理任何接口。但它也有个问题,要代理的类必须实现接口。。如果不想实现接口,还要能够代理,可以使用cglib.

    cglib动态代理

    cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    * Created by j.tommy on 2017/9/10.
    */
    public class CglibProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();

    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    // 通过代理类调用父类中的方法
    return methodProxy.invokeSuper(o,args);
    }
    public Object getProxy(Class clazz) {
    // 设置需要创建之类的类
    enhancer.setSuperclass(clazz);
    enhancer.setCallback(this);

    // 通过字节码结束创建之类实例
    return enhancer.create();
    }
    }

    测试类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    * Created by j.tommy on 2017/9/10.
    */
    public class Main {
    public static void main(String[] args) {
    CglibProxy cp = new CglibProxy();
    UserService ius = (UserService) cp.getProxy(UserService.class);
    String result = ius.request();
    System.out.println("result:" + result);
    }
    }

    更多代理模式参考:http://blog.csdn.net/yakoo5/article/details/9099133/
    http://www.importnew.com/22015.html

  • 相关阅读:
    vue如何将单页面改造成多页面应用
    css3动画基础详解(@keyframes和animation)
    《css揭秘》下(伪元素,文字背景,垂直居中技巧,文字环绕)
    Wavesurfer.js音频播放器插件的使用教程
    《CSS3揭秘》上(边框,投影,渐变,条纹效果,蚂蚁行军)
    复活hexo静态博客的方法
    基于svg.js实现对图形的拖拽、选择和编辑操作
    js 常用的工具函数
    linux 新机器的配置(git + nodejs+ mongodb)
    vue 不常见操作
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12251174.html
Copyright © 2020-2023  润新知