当前位置:首页 > CN2资讯 > 正文内容

代理模式的应用代理模式的应用场景

1天前CN2资讯


静态代理

很多小伙伴去大城市打拼。来大城市第一件事就是租房,免不了和中介打交道,因为很多房东很忙,你根本找不到他。从这个场景中就可以抽象出来代理模式

ISubject:被访问者资源的抽象
SubjectImpl:被访问者具体实现类(房东)
SubjectProxy:被访问者的代理实现类(中介)

UML图如下


举个例子来理解一下这个设计模式

老板让记录一下用户服务的响应时间,用代理模式来实现这个功能。

public interface IUserService {
public void request();
}public class UserServiceImpl implements IUserService {
@Override
public void request() {
System.out.println("this is userService");
}
}public class UserServiceProxy implements IUserService {

private IUserService userService;

public UserServiceProxy(IUserService userService) {
this.userService = userService;
}

@Override
public void request() {
long startTime = System.currentTimeMillis();
userService.request();
System.out.println("reques cost :" + (System.currentTimeMillis() - startTime));
}

public static void main(String[] args) {
IUserService userService = new UserServiceImpl();
UserServiceProxy userServiceProxy = new UserServiceProxy(userService);
// this is userService
// reques cost :0
userServiceProxy.request();
}
}

代理模式不只有让代理类和原始类实现同一个接口,然后将原始类注入到代理类中这一种写法。如果原始类没有定义接口,并且原始类并不是我们维护的,我们此时就可以用继承的方式类实现代理模式,让代理类继承原始类,然后扩展功能。

public class UserService {

public void request() {
System.out.println("this is userService");
}
}public class UserServiceProxy extends UserService {

@Override
public void request() {
long startTime = System.currentTimeMillis();
super.request();
System.out.println("reques cost :" + (System.currentTimeMillis() - startTime));
}

public static void main(String[] args) {
UserService userService = new UserServiceProxy();
// this is userService
// reques cost :1
userService.request();
}
}

一切看起来都非常的美好,老板又发话了,把产品服务的响应时间也记录一下吧。又得写如下3个类

IProductService
ProductServiceImpl
ProductServiceProxy

UserServiceProxy和ProductServiceProxy这两个代理类的逻辑都差不多,却还得写2次。其实这个还好,如果老板说,把现有系统的几十个服务的响应时间都记录一下吧,你是不是要疯了?这得写多少代理类啊?这就得用到我们后续提到的动态代理了。

总结一下,代理模式的实现方式有两种

  • 代理类和原始类实现同一个接口,原始类注入到代理类
  • 代理类继承原始类
  • 动态代理

    黑暗总是暂时的,终究会迎来黎明,在JDK1.3之后引入了一种称之为动态代理(Dynamic Proxy)的机制。使用该机制,我们可以为指定的接口在系统运行期间动态地生成代理对象,从而帮助我们走出最初使用静态代理实现AOP的窘境

    动态代理的实现有两种方式

  • 利用JDK实现动态代理,即调用Proxy.newProxyInstance()方法
  • 使用CGLIB来实现动态代理
  • 使用JDK实现动态代理,原始类必须实现某个接口,因为它是基于实现同一个接口的方式来实现的。而用CGLIB来实现动态代理,原始类有无实现接口都可以,因为它是基于继承的方式实现的

    JDK动态代理

    动态代理的实现主要由一个类和一个接口组成,即java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。

    让我们用动态代理来改造一下上面记录系统响应时间的功能。虽然要为IUserService和IProductService两种服务提供代理对象,但因为代理对象中要添加的横切逻辑是一样的。所以我们只需要实现一个InvocationHandler就可以了。代码如下

    public class RequestCostInvocationHandler implements InvocationHandler {

    private Object target;

    public RequestCostInvocationHandler(Object target) {
    this.target = target;
    }

    /** 被代理对象的任何方法被执行时,都会先进入这个方法 */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (method.getName().equals("request")) {
    long startTime = System.currentTimeMillis();
    // 执行目标对象的方法
    method.invoke(target, args);
    System.out.println("reques cost :" + (System.currentTimeMillis() - startTime));
    }
    return null;
    }

    public static void main(String[] args) {

    // 3个参数解释如下
    // classloader,生成代理类
    // 代理类应该实现的接口
    // 实现InvocationHandler的切面类
    IUserService userService = (IUserService) Proxy.newProxyInstance(
    IUserService.class.getClassLoader(),
    new Class[]{IUserService.class},
    new RequestCostInvocationHandler(new UserServiceImpl()));

    IProductService productService = (IProductService) Proxy.newProxyInstance(
    IProductService.class.getClassLoader(),
    new Class[]{IProductService.class},
    new RequestCostInvocationHandler(new ProductServiceImpl()));

    // this is userService
    // reques cost :0
    userService.request();

    // this is productService
    // reques cost :0
    productService.request();
    }

    }

    生成动态代理也很简单,调用Proxy.newProxyInstance()方法即可

    public static Object newProxyInstance(ClassLoader loader,
    Class<?>[] interfaces,
    InvocationHandler h)

    三个参数如下:

    loader:类加载器
    interfaces: 代理类应该实现的接口
    h:实现InvocationHandler接口的类,在里面增加代理逻辑

    这个方法以及3个参数在面试中偶尔会被问到,动态代理在各大框架中用的确实很多了

    UML图如下。Spring AOP就是用动态代理来实现的

    CGLIB动态代理

    CGLIB基于字节码技术为我们生成子类,不用我们自己去生成。用法如下

    public class UserService {

    public void request() {
    System.out.println("welcome sir");
    }
    }public class RequestCtrlCallback implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    long startTime = System.currentTimeMillis();
    Object object = methodProxy.invokeSuper(o, objects);
    System.out.println("reques cost :" + (System.currentTimeMillis() - startTime));
    return object;
    }

    public static void main(String[] args) {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(UserService.class);
    enhancer.setCallback(new RequestCtrlCallback());

    UserService proxy = (UserService)enhancer.create();
    // welcome sir
    // reques cost :25
    proxy.request();
    }
    }

    代理模式和装饰者模式的区别

    装饰者模式主要是为被装饰的对象提供增强功能,而代理模式主要是对被代理对象的使用增加控制,并不提供增强功能

    参考博客


    [2]http://www.importnew.com/27772.html
    [4]http://layznet.iteye.com/blog/1182924
    好文
    代理模式和装饰者模式的区别
    [8]https://www.zhihu.com/question/41988550


      你可能想看:

      扫描二维码推送至手机访问。

      版权声明:本文由皇冠云发布,如需转载请注明出处。

      本文链接:https://www.idchg.com/info/24993.html

      分享给朋友:

      “代理模式的应用代理模式的应用场景” 的相关文章

      境外VPS搭建服务指南:如何选择最适合的VPS提升网站与业务性能

      网站建设与个人博客 境外VPS是搭建网站和个人博客的理想选择。对于初学者来说,选择价格实惠的VPS主机可以作为一个很好的练手机会。像RackNerd、EthernetServers、CloudCone和HostEONS这样的提供商,提供年付低至9美元的VPS服务,非常适合预算有限但又想尝试网站搭建的...

      Vultr充值优惠活动:享受高性价比云服务的最佳选择

      Vultr概述 当提到云服务,Vultr总是一个热点话题。它从2014年开始运营,迅速在行业内崭露头角。Vultr的目标是为用户提供迅速而灵活的云计算解决方案。在短短几年内,它已经覆盖了全球的多个数据中心,为用户的业务发展提供了强有力的支持。 Vultr注重用户体验,致力于让每一位客户感受到便捷与可...

      云服务器推荐:选择最适合您业务的云计算解决方案

      什么是云服务器? 云服务器是一种通过网络提供计算资源的虚拟服务器。与传统的物理服务器不同,云服务器依托于云计算技术,将庞大的计算和存储需求分散在多个数据中心,利用虚拟化技术将这些资源整合提供给用户。你可以把它想象成一种“租赁”模式,不用像之前那样一次性投入大量资金购置硬件,通过按需付费的方式,灵活获...

      全面解析VPS测评:如何选择适合您的便宜VPS

      VPS测评概述 当我第一次接触VPS时,我也许和很多人一样,产生了不少疑问。VPS,或者说虚拟私人服务器,实际上是一种将一台物理服务器划分成多个虚拟服务器的技术。每个虚拟服务器都能拥有独立的操作系统和资源,允许用户以更低的成本享受类似于专用服务器的服务。这样的设置不仅提供了灵活性,还使得资源的利用更...

      全面了解中国电信测速工具及其使用方法

      在数字化生活中,稳定的网络速度与流畅的使用体验息息相关。中国电信测速工具正是帮助我们了解网络速度状况的重要工具。通过这些工具,用户可以清楚地知道自己当前的网络状况,以便及时调整和优化网络设置。 中国电信测速工具,顾名思义,是用于测试电信网络连接速度的应用或网站。这些工具通常具备多种功能,包括测量下载...

      使用ping.pe提升网络性能和优化用户体验的完整指南

      在互联网不断发展的今天,ping.pe作为一个专业的网络测试工具,逐渐成为了许多用户的首选。我最早接触这个网站时,是因为我需要一个简便的方法来检测网络连接的稳定性。从那时起,我便对这个网站的背景和发展历史产生了浓厚的兴趣。 ping.pe成立于互联网发展的初期,随着技术的进步,它不断完善自身的功能,...