Ehcache在集群时, 测试是否集群间能正常通讯
以下内容,个人总结, 只是项目中用到, 并且知识范围内做的修改, 不妥之处请打脸. 脸放这(
)
项目中使用的Ehcache做的缓存处理, 但是ehcache集群时, 判断是否能正常通讯只通过操作缓存后, 查询其他机器缓存是否正常清除或者添加有点黑盒的感觉, 看不见具体的缓存添加移除过程.
另外由于@Cacheable不支持的key不支持正则表达式, 有些缓存时单项缓存,但是修改时 ,通过@CacheEvict来清除不知道具体的key, 只知道key的前半部分或者后半部分, ehcache的key又不支持正则, 无法模糊清除.
针对上面的两个情况, 对ehache的源码部分做了一丁点的修改, 支持正则表达式, 并且集群环境下能打印一下缓存添加移除的日志.
对于集群时, 集群机器间的地址查找, 可以通过增加log4j的debug日志看见, 但是仅是机器查找的日志 lookup ipxxx....的日志字样.
log4j.logger.net.sf.ehcache.distribution.RMICacheManagerPeerListener=DEBUG,Console
缓存变化异步通知类是:
log4j.logger.net.sf.ehcache.distribution.RMIAsynchronousCacheReplicator=DEBUG,Console
真正处理接收到缓存变化异步通知处理类是:
log4j.logger.net.sf.ehcache.distribution.RMICachePeer=DEBUG,Console
RMICachePeer是缓存处理的最终类, 正则表达式的支持也是放到这个类上做的处理.
/*** Copyright Terracotta, Inc.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package net.sf.ehcache.distribution;import net.sf.ehcache.CacheException;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;import java.io.Serializable;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;
import net.sf.ehcache.distribution.RmiEventMessage.RmiEventType;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import com.thinkgem.jeesite.common.utils.Collections3;/*** An RMI based implementation of CachePeer.* * This class features a customised RMIClientSocketFactory which enables socket timeouts to be configured.** @author Greg Luck* @version $Id: RMICachePeer.java 5631 2012-05-10 08:31:33Z teck $*/
//remove方法增加正则表达式支持 mod by tom
public class RMICachePeer extends UnicastRemoteObject implements CachePeer, Remote {private static final Logger LOG = LoggerFactory.getLogger(RMICachePeer.class.getName());private final String hostname;private final Integer rmiRegistryPort;private Integer remoteObjectPort;private final Ehcache cache;/*** Construct a new remote peer.** @param cache The cache attached to the peer* @param hostName The host name the peer is running on.* @param rmiRegistryPort The port number on which the RMI Registry listens. Should be an unused port in* the range 1025 - 65536* @param remoteObjectPort the port number on which the remote objects bound in the registry receive calls.* This defaults to a free port if not specified.* Should be an unused port in the range 1025 - 65536* @param socketTimeoutMillis* @throws RemoteException*/public RMICachePeer(Ehcache cache, String hostName, Integer rmiRegistryPort, Integer remoteObjectPort,Integer socketTimeoutMillis)throws RemoteException {super(remoteObjectPort.intValue(), new ConfigurableRMIClientSocketFactory(socketTimeoutMillis),ConfigurableRMIClientSocketFactory.getConfiguredRMISocketFactory());this.remoteObjectPort = remoteObjectPort;this.hostname = hostName;this.rmiRegistryPort = rmiRegistryPort;this.cache = cache;}/*** {@inheritDoc}* * This implementation gives an URL which has meaning to the RMI remoting system.** @return the URL, without the scheme, as a string e.g. //hostname:port/cacheName*/public final String getUrl() {return new StringBuilder().append("//").append(hostname).append(":").append(rmiRegistryPort).append("/").append(cache.getName()).toString();}/*** {@inheritDoc}* * This implementation gives an URL which has meaning to the RMI remoting system.** @return the URL, without the scheme, as a string e.g. //hostname:port*/public final String getUrlBase() {return new StringBuilder().append("//").append(hostname).append(":").append(rmiRegistryPort).toString();}/*** Returns a list of all elements in the cache, whether or not they are expired.* * The returned keys are unique and can be considered a set.* * The List returned is not live. It is a copy.* * The time taken is O(n). On a single cpu 1.8Ghz P4, approximately 8ms is required* for each 1000 entries.** @return a list of {@link Object} keys*/public List getKeys() throws RemoteException {List keys = cache.getKeys();if (keys instanceof Serializable) {return keys;}return new ArrayList(keys);}/*** Gets an element from the cache, without updating Element statistics. Cache statistics are* still updated.** @param key a serializable value* @return the element, or null, if it does not exist.*/public Element getQuiet(Serializable key) throws RemoteException {return cache.getQuiet(key);}/*** Gets a list of elements from the cache, for a list of keys, without updating Element statistics. Time to* idle lifetimes are therefore not affected.* * Cache statistics are still updated.* * Callers should ideally first call this method with a small list of keys to gauge the size of a typical Element.* Then a calculation can be made of the right number to request each time so as to optimise network performance and* not cause an OutOfMemory error on this Cache.** @param keys a list of serializable values which represent keys* @return a list of Elements. If an element was not found or null, it will not be in the list.*/public List getElements(List keys) throws RemoteException {if (keys == null) {return new ArrayList();}List elements = new ArrayList();for (int i = 0; i < keys.size(); i++) {Serializable key = (Serializable) keys.get(i);Element element = cache.getQuiet(key);if (element != null) {elements.add(element);}}return elements;}/*** Puts an Element into the underlying cache without notifying listeners or updating statistics.** @param element* @throws java.rmi.RemoteException* @throws IllegalArgumentException* @throws IllegalStateException*/public void put(Element element) throws RemoteException, IllegalArgumentException, IllegalStateException {cache.put(element, true);if (LOG.isDebugEnabled()) {
// LOG.debug("RMICachePeer for cache " + cache.getName() + ": remote put received. Element is: " + element);LOG.debug("RMICachePeer for cache " + cache.getName() + ": remote put received. Element is: " + element.getObjectKey());}}/*** Removes an Element from the underlying cache without notifying listeners or updating statistics.** @param key* @return true if the element was removed, false if it was not found in the cache* @throws RemoteException* @throws IllegalStateException*/public boolean remove(Serializable key) throws RemoteException, IllegalStateException {if (LOG.isDebugEnabled()) {LOG.debug("RMICachePeer for cache " + cache.getName() + ": remote remove received for key: " + key);}//add by tom 2017年11月8日 ,移除符合自定义正则表达式的缓存removeRegex(key);return cache.remove(key, true);}/*** remove regex pattern cache key. add by tom* @param key*/private void removeRegex(Serializable key) {try {String strKey = key.toString();if (strKey.matches("<\\[.+\\]>")) {String regex = strKey.substring(2,strKey.length()-2);LOG.debug("RMICachePeer for cache " + cache.getName() + ": remote regex: " + regex);@SuppressWarnings("unchecked")List kList = cache.getKeys();if (kList == null || kList.isEmpty()) {LOG.debug("keys is empty for cache " + cache.getName() + ": remote regex: " + regex);return;}LOG.debug("cache " + cache.getName() + " exists keys: " + kList.size());for (String k : kList) {
// LOG.debug("RMICachePeer for cache " + cache.getName() + ": remote remove regex key : " + k);if (k.matches(regex)) {if (LOG.isDebugEnabled()) {LOG.debug("RMICachePeer for cache " + cache.getName() + ": remote remove regex matcher key: " + k);}cache.remove(k, true);}}}} catch (IllegalStateException e) {LOG.error(e.getMessage(), e);} catch (CacheException e) {LOG.error(e.getMessage(), e);} }/*** Removes all cached items.** @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}*/public void removeAll() throws RemoteException, IllegalStateException {if (LOG.isDebugEnabled()) {LOG.debug("RMICachePeer for cache " + cache.getName() + ": remote removeAll received");}cache.removeAll(true);}/*** Send the cache peer with an ordered list of {@link EventMessage}s* * This enables multiple messages to be delivered in one network invocation.*/public void send(List eventMessages) throws RemoteException {for (int i = 0; i < eventMessages.size(); i++) {RmiEventMessage eventMessage = (RmiEventMessage) eventMessages.get(i);if (eventMessage.getType() == RmiEventType.PUT) {put(eventMessage.getElement());} else if (eventMessage.getType() == RmiEventType.REMOVE) {remove(eventMessage.getSerializableKey());} else if (eventMessage.getType() == RmiEventType.REMOVE_ALL) {removeAll();} else {LOG.error("Unknown event: " + eventMessage);}}}/*** Gets the cache name*/public final String getName() throws RemoteException {return cache.getName();}/*** {@inheritDoc}*/public final String getGuid() throws RemoteException {return cache.getGuid();}/*** Gets the cache instance that this listener is bound to*/final Ehcache getBoundCacheInstance() {return cache;}/*** Returns a String that represents the value of this object.*/public String toString() {StringBuilder buffer = new StringBuilder("URL: ");buffer.append(getUrl());buffer.append(" Remote Object Port: ");buffer.append(remoteObjectPort);return buffer.toString();}}
上面的类增加了一个方法:
removeRegex在使用@CacheEvict时, key值如果作为正则表达式, 需要 key = '<[正则表达式]>', 用<[]>包含的内容作为正则表达式处理, 通过将ehcache中的缓存key取出并做正则匹配, 匹配上时, 调用cache.remove方法将缓存移除.
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
