架构设计:系统间通信(39)——Apache Camel快速入门(下2)

本文深入探讨了Apache Camel中的生命周期策略、CopyOnWriteArrayList、软引用、LRU算法及其在Camel中的应用。重点讲解了CopyOnWriteArrayList的线程安全特性以及其在监听器模式中的作用,同时还介绍了LRU算法在EndpointRegistry中的实现,通过LRUSoftCache利用SoftReference防止内存溢出。最后,展示了如何使用XML形式编排Camel路由并集成Spring。

========================
(接上文:《架构设计:系统间通信(38)——Apache Camel快速入门(下1)》)

4-2-1、LifecycleStrategy

LifecycleStrategy接口按照字面的理解是一个关于Camel中元素生命周期的规则管理器,但实际上LifecycleStrategy接口的定义更确切的应该被描述成一个监听器:

这里写图片描述

当Camel引用程序中发生诸如Route加载、Route移除、Service加载、Serivce移除、Context启动或者Context移除等事件时,DefaultCamelContext中已经被添加到集合“lifecycleStrategies”(java.util.List<LifecycleStrategy>)的LifecycleStrategy对象将会做相应的事件触发。

读者还应该注意到“lifecycleStrategies”集合是一个CopyOnWriteArrayList,我们随后对这个List的实现进行讲解。以下代码展示了在DefaultCamelContext添加Service时,DefaultCamelContext内部是如何触发“lifecycleStrategies”集合中已添加的监听的:

......
private void doAddService(Object object, boolean closeOnShutdown) throws Exception {
    ......

    // 只有以下条件成立,才需要将外部来源的Object作为一个Service处理
    if (object instanceof Service) {
        Service service = (Service) object;

        // 依次连续触发已注册的监听
        for (LifecycleStrategy strategy : lifecycleStrategies) {
            // 如果是一个Endpoint的实现,则触发onEndpointAdd方法
            if (service instanceof Endpoint) {
                // use specialized endpoint add
                strategy.onEndpointAdd((Endpoint) service);
            } 
            // 其它情况下,促发onServiceAdd方法
            else {
               strategy.onServiceAdd(this, service, null);
            }
       }

       // 其它后续处理
       ......
    }
}
......

4-2-2、CopyOnWriteArrayList与监听者模式

正如上一小节讲到的,已在DefaultCamelContext中注册的LifecycleStrategy对象存放于一个名叫“lifecycleStrategies”的集合中,后者是CopyOnWriteArrayList容器的实现,这是一个从JDK 1.5+ 版本开始提供的容器结构。

各位读者可以设想一下这样的操作:某个线程在对容器进行写操作的同时,还有另外的线程对容器进行读取操作。如果上述操作过程是在没有“线程安全”特性的容器中进行的,那么可能出现的情况就是:开发人员原本想读取容器中 i 位置的元素X,可这个元素已经被其它线程删除了,开发人员最后读取的 i 位置的元素变成了Y。但是在具有“写线程安全”特性的容器中进行这样的操作就不会有问题:因为写操作在另一个副本容器中进行,原容器中的数据大小、数据位置都不会受到影响。

如果上述操作过程是在有“线程安全”特性的容器中进行的,那么以上脏读的情况是可以避免的。但是又会出现另外一个问题:由于容器的各种读写操作都会加上锁(无论是悲观锁还是乐观锁),所以容器的读写性能又会收到影响。如果采用的是乐观锁,那么对性能的影响可能还不会太大,但是如果采用的是悲观锁,那么对性能的影响就有点具体了。

CopyOnWriteArrayList为我们提供了另一种线程安全的容器操作方式。CopyOnWriteArrayList的工作效果类似于java.util.ArrayList,但是它通过ReentrantLock实现了容器中写操作的线程安全性。CopyOnWriteArrayList最大的特点是:当进行容器中元素的修改操作时,它会首先将容器中的原有元素克隆到一个副本容器中,然后对副本容器中的元素进行修改操作。待这些操作完成后,再将副本中的元素集合重新会写到原有的容器中完成整个修改操作。这种工作机制称为Copy-On-Write(COW)。这样做的最主要目的是分离容器的读写操作。CopyOnWriteArrayList会对所有的写操作加锁,但是不会对任何容器的读操作加锁(因为写操作在一个副本中进行)。

另外CopyOnWriteArrayList还重新实现了一个新的迭代器:COWIterator。它是做什么的呢?举例说明:在ArrayList中我们如果在进行迭代时同时进行容器的写操作,那么就可能会因为下标超界等原因出现程序异常:

List<?> list = new ArrayList<?>();
// 省略了添加元素部分的代码
......

// ArrayList不支持这样的操作方式,会报错
for(Object item : list){
    list.remove(item);
}

但如果使用CopyOnWriteArrayList中重写的COWIterator迭代器,就不会出现的情况(开发人员还可以使用JDK 1.5+ 提供的另一个线程安全COW容器:CopyOnWriteArraySet):

List<?> list = new CopyOnWriteArrayList<?>();
// 省略了添加元素部分的代码
......

// COWIterator迭代器支持一边迭代一边进行容器的写操作
for(Object item : list){
    list.remove(item);
}

那么CopyOnWriteArrayList和监听器模式有什么关系呢?在书本上我们学到的监听器容器基本上都不是线程安全的,这基本上是出于两方面的考虑。首先对于设计模式的初学者来说最重要的理解模式所代表的设计思想,而非实现细节;另外,在这些示例中,设计模式的实现和操作一般为单一线程,不会出现多其它线程同时操作容器的情况。以下是我们常看到的监听者模式(代码片段):

/**
 * 为事件监听携带的业务对象
 * @author yinwenjie
 */
public class BusinessEventObject extends EventObject {
    
    
    public BusinessEventObject(Object source) {
        super(source);
    }
}

/**
 * 监听器,其中只有一个事件方法
 * @author yinwenjie
 */
public interface BusinessEventListener extends EventListener {
    
    
    public void onBusinessStart(BusinessEventObject eventObject);
}

/**
 * 业务级别的代码
 * @author yinwenjie
 */
public class BusinessOperation {
    
    

    /**
     * 已注册的监听器放在这里
     */
    private List<BusinessEventListener> listeners = new
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值