Guava源码分析——Proxy模式(TimeLimiter)

代理模式:给某一对象提供代理对象,并由代理对象控制具体对象的引用。主要解决的问题是:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

interface Image {

    public void displayImage();

}


class RealImage implements Image {

    private String filename;

    public RealImage(String filename) {

        this.filename = filename;

        loadImageFromDisk();

    }


    private void loadImageFromDisk() {

        System.out.println("Loading   " + filename);

    }


    public void displayImage() {

        System.out.println("Displaying " + filename);

    }

}


class ProxyImage implements Image {

    private String filename;

    private Image image;


    public ProxyImage(String filename) {

        this.filename = filename;

    }

    public void displayImage() {

        if(image == null)

            image = new RealImage(filename);

        image.displayImage();

    }

}


class ProxyExample {

    public static void main(String[] args) {

        Image image = new ProxyImage("MyPhoto");

        image.displayImage();

    }

}

运行结果:


与装饰模式的区别:

装饰模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。换句话 说,用代理模式,代理类可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们通常在一个代理类中创建一个对象的实例。当我们使用装饰器模式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。使用代理模式,代理和真实对象之间的的关系通常在编译时就已经确定了,而装饰者能够在运行时递归地被构造,例如:

//蓝莓冰淇淋 
AbstractIceCream blueberryIceCream = new BlueberryAdapter(new IceCream()); 

//蓝莓巧克力冰淇淋
AbstractIceCream bb_ch_iceCream = new BlueberryAdapter(new ChocolateAdapter(new IceCream())); 

//加3层巧克力
AbstractIceCream lot_of_chocolate_iceCream = new ChocolateAdapter(new ChocolateAdapter(new ChocolateAdapter(new IceCream())));

 

 

在Guava的TimeLimiter类中就应用到了代理模式:

   TimeLimiter:用于对某一类对象的所有方法运行时间进行限制,即在给定时限内方法正常执行,否则抛出异常。该类生成一个代理,当调用被代理的对象的方法时,会强制加一个时间限制。定义了 newProxy(T target, Class<T> interfaceType, long timeoutDuration, TimeUnit timeoutUnit) callWithTimeOut(Callable<T> callable, long timeoutDuration, TimeUnit timeoutUnit, boolean interruptible)。

 

1、 newProxy()方法生成 target的一个代理

注意:参数interfaceType必须为接口类型。

在该方法中,首先会找出接口的interruptible方法:

 
Set<Method> set = Sets.newHashSet();
    for (Method m : interfaceType.getMethods()) {
      if (declaresInterruptedEx(m)) {
        set.add(m);
      }
    }

这里会判断接口的每一个方法是否抛出InterruptedException异常,如果没有抛出,则不会加到interruptible方法集合里。

例如上面得到的Method集合为:

在调用callWithTimeout时, 该集合用来判断,调用的方法是否amInterruptible。

以判断应该调用future.get(timeoutDuration, timeoutUnit); 或 Uninterruptibles.getUninterruptibly(future, timeoutDuration, timeoutUnit);来获取执行结果。

 

下面例子中,将直接使用上面代理模式中定义的类:

  TimeLimiter limiter = new SimpleTimeLimiter();
        Image image = new ProxyImage("MyPhoto");
        Image proxy = limiter.newProxy(image, Image.class, 1000, TimeUnit.MILLISECONDS);
        try {
            proxy.displayImage();
        } catch (Exception e) {
            e.printStackTrace();
        }

运行结果:

 

2、 callWithTimeout() 方法:如果 callable执行完毕时还没有到达限定时间则将结果或异常传给调用者,否则抛出 UncheckedTimeoutException。用法如下:

public class TimeLimiterTest {
        public static void main(String[] args){
            SimpleTimeLimiter simpleTimeLimiter = new SimpleTimeLimiter();
            String hello = null;
            try {
                hello = simpleTimeLimiter.callWithTimeout(new Callable<String>(){
                    @Override
                    public String call() throws Exception {
                        return "Hello";
                    }
}, 100, TimeUnit.MILLISECONDS, true);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(hello);
 
            String word = null;
            try {
                word = simpleTimeLimiter.callWithTimeout(new Callable<String>(){
                    @Override
                    public String call() throws Exception {
                        Thread.sleep(100);
                        return "Word";
                    }
}, 99, TimeUnit.MILLISECONDS, true);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(word);
        }
}

结果:运行超时

### Guava Cache 源码解析教程 #### 一、概述 Guava Cache 是 Google 开发的一个高性能本地缓存库,适用于 Java 应用程序。该库提供了一种线程安全的方式管理内存中的键值对集合[^2]。 #### 二、核心组件介绍 ##### 1. 数据结构设计 Guava Cache 的内部实现了多种优化的数据结构用于高效存储和访问缓存项。这些数据结构的设计旨在平衡时间和空间复杂度,确保良好的性能表现[^1]。 ##### 2. 自动回收机制 不同于 `ConcurrentMap` 需要手动删除过期条目,Guava Cache 支持设置最大容量、存活时间等参数来自动生成淘汰策略,从而有效控制资源消耗。 #### 三、主要功能模块详解 ##### 1. CacheLoader 类的作用 `CacheLoader` 定义了一个抽象类,允许开发者自定义当缓存未命中时如何获取新值的方法。这使得应用程序可以根据具体需求灵活地决定加载逻辑[^3]。 ```java public class MyCustomCacheLoader extends CacheLoader<String, String> { @Override public String load(String key) throws Exception { // 实现具体的加载逻辑 return "Value for " + key; } } ``` ##### 2. LoadingCache 接口及其子类 `LoadingCache<K,V>` 继承自 `Cache<K,V>` 并增加了自动装载能力。通过实现特定的加载器(`CacheLoader`)可以构建具有懒加载特性的实例对象[^4]。 ```java LoadingCache<Object, Object> cache = CacheBuilder.newBuilder() .maximumSize(100) .expireAfterWrite(10, TimeUnit.MINUTES) .build( new CacheLoader<Object, Object>() { @Override public Object load(Object key) throws Exception { return computeExpensiveValue(key); } }); ``` #### 四、初始化方式举例 除了上述提到的 loader 方式外,还可以采用预填充的方式来创建已含有初始映射关系的缓存实例[^5]。 ```java // 使用ImmutableMap作为输入快速建立带有默认值的缓存 Cache<Integer, Integer> prepopulatedCache = CacheBuilder.<Integer, Integer>newBuilder().build(CacheLoader.from(Map.of(1, 1))); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值