读书人

Guava源码分析Proxy形式(TimeLim

发布时间: 2013-09-30 09:50:49 作者: rapoo

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

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();

}

}

运行结果:

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

与装饰模式的区别:

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

//蓝莓冰淇淋
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集合为:

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

在调用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(); }

运行结果:

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

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源码分析——Proxy形式(TimeLimiter)

读书人网 >软件架构设计

热点推荐