RMI方式Ehcache集群的源码分析

本文详细介绍了Ehcache使用RMI进行集群配置的方式,包括自动和手动发现配置,并深入剖析了RMICacheManagerPeerProviderFactory的源码。同时,讨论了服务Listener的配置以及事件Listener在配置文件中的设置,强调了如何实现缓存的同步复制。
摘要由CSDN通过智能技术生成

Ehcache不仅支持基本的内存缓存,还支持多种方式将本地内存中的缓存同步到其他使用Ehcache的服务器中,形成集群。如下图所示:


Ehcache支持多种集群方式,下面以RMI通信方式为例,来具体分析一下Ehcache集群的源码。

1服务Provider

Ehcache支持两种服务发现方式:一种是通过广播的方式,服务间自动发现,动态更新存活服务的列表;另一种就是在配置文件中配置好静态服务列表。

1.1自动发现配置

Server12的配置都一样,广播地址为230.0.0.1:

<cacheManagerPeerProviderFactory 
     class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" 
     properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,
          multicastGroupPort=4446, timeToLive=32"/>


1.2手动发现配置

Server1的配置,rmiUrls为server2上的两个cache:

<cacheManagerPeerProviderFactory 
     class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" 
     properties="peerDiscovery=manual,rmiUrls=//server2:40001/sampleCache11|//server2:40001/sampleCache12"/>


Server2的配置,rmiUrls为server1上的两个cache:

<cacheManagerPeerProviderFactory 
     class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" 
     properties="peerDiscovery=manual,rmiUrls=//server1:40001/sampleCache11|//server1:40001/sampleCache12"/>


1.3源码分析-RMICacheManagerPeerProviderFactory

对应上面两种配置方式,根据peerDiscovery属性的值,创建自动或手动两种Provider。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
     public  CacheManagerPeerProvider createCachePeerProvider(CacheManager cacheManager, Properties properties)
             throws  CacheException {
         String peerDiscovery = PropertyUtil.extractAndLogProperty(PEER_DISCOVERY, properties);
         if  (peerDiscovery ==  null  || peerDiscovery.equalsIgnoreCase(AUTOMATIC_PEER_DISCOVERY)) {
             try  {
                 return  createAutomaticallyConfiguredCachePeerProvider(cacheManager, properties);
             catch  (IOException e) {
                 throw  new  CacheException( "Could not create CacheManagerPeerProvider. Initial cause was "  + e.getMessage(), e);
             }
         else  if  (peerDiscovery.equalsIgnoreCase(MANUALLY_CONFIGURED_PEER_DISCOVERY)) {
             return  createManuallyConfiguredCachePeerProvider(properties);
         else  {
             return  null ;
         }
     }
 
     protected  CacheManagerPeerProvider createManuallyConfiguredCachePeerProvider(Properties properties) {
         String rmiUrls = PropertyUtil.extractAndLogProperty(RMI_URLS, properties);
         if  (rmiUrls ==  null  || rmiUrls.length() ==  0 ) {
             LOG.info( "Starting manual peer provider with empty list of peers. "  +
                     "No replication will occur unless peers are added." );
             rmiUrls =  new  String();
         }
         rmiUrls = rmiUrls.trim();
         StringTokenizer stringTokenizer =  new  StringTokenizer(rmiUrls, PayloadUtil.URL_DELIMITER);
         RMICacheManagerPeerProvider rmiPeerProvider =  new  ManualRMICacheManagerPeerProvider();
         while  (stringTokenizer.hasMoreTokens()) {
             String rmiUrl = stringTokenizer.nextToken();
             rmiUrl = rmiUrl.trim();
             rmiPeerProvider.registerPeer(rmiUrl);
 
                 LOG.debug( "Registering peer {}" , rmiUrl);
         }
         return  rmiPeerProvider;
     }

以创建手动发现服务的Provider为例,新建ManualRMICacheManagerPeerProvider实例后,会调用其registerPeer方法将配置文件中配置的集群服务都注册上。
例如rmiUrls=//server2:40001/sampleCache11|//server2:40001/sampleCache12。

注册代码如下。注册方法仅仅将服务器地址保存到Map中,当后面要讲到的Replicator想要与集群中其他结点通信时,会调用Provider的listRemoteCachePeers()方法,
通过RMI的Naming.lookup()方法找到远程结点并返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
     public  final  synchronized  void  registerPeer(String rmiUrl) {
         peerUrls.put(rmiUrl,  new  Date());
     }
 
     public  final  synchronized  List listRemoteCachePeers(Ehcache cache)  throws  CacheException {
         List remoteCachePeers =  new  ArrayList();
         List staleList =  new  ArrayList();
         for  (Iterator iterator = peerUrls.keySet().iterator(); iterator.hasNext();) {
             String rmiUrl = (String) iterator.next();
             String rmiUrlCacheName = extractCacheName(rmiUrl);
 
             if  (!rmiUrlCacheName.equals(cache.getName())) {
                 continue ;
             }
             Date date = (Date) peerUrls.get(rmiUrl);
             if  (!stale(date)) {
                 CachePeer cachePeer =  null ;
                 try  {
                     cachePeer = lookupRemoteCachePeer(rmiUrl);
                     remoteCachePeers.add(cachePeer);
                 catch  (Exception e) {
                     if  (LOG.isDebugEnabled()) {
                         LOG.debug( "Looking up rmiUrl "  + rmiUrl +  " through exception "  + e.getMessage()
                                 ". This may be normal if a node has gone offline. Or it may indicate network connectivity"
                                 " difficulties" , e);
                     }
                 }
             else  {
                     LOG.debug( "rmiUrl {} should never be stale for a manually configured cluster." , rmiUrl);
                 staleList.add(rmiUrl);
             }
 
         }
 
         //Remove any stale remote peers. Must be done here to avoid concurrent modification exception.
         for  ( int 
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值