All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.base4j.j2cache.JGroupsCacheChannel Maven / Gradle / Ivy

The newest version!
package com.base4j.j2cache;

import java.net.URL;
import java.util.List;

import org.jgroups.Address;
import org.jgroups.JChannel;
import org.jgroups.Message;
import org.jgroups.ReceiverAdapter;
import org.jgroups.View;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 使用 JGroups 进行组播
 * @author winterlau
 */
public class JGroupsCacheChannel extends ReceiverAdapter implements CacheExpiredListener, CacheChannel {

	private final static Logger log = LoggerFactory.getLogger(JGroupsCacheChannel.class);
	private final static String CONFIG_XML = "/network.xml";
	
	private String name;
	private JChannel channel;
	private final static JGroupsCacheChannel instance = new JGroupsCacheChannel("default");
	
	/**
	 * 单例方法
	 * @return 返回 CacheChannel 单实例
	 */
	public final static JGroupsCacheChannel getInstance(){
		return instance;
	}
	
	/**
	 * 初始化缓存通道并连接
	 * @param name: 缓存实例名称
	 */
	private JGroupsCacheChannel(String name) throws CacheException {
		this.name = name;
		try{
			CacheManager.initCacheProvider(this);
			
			long ct = System.currentTimeMillis();
			
			URL xml = CacheChannel.class.getResource(CONFIG_XML);
			if(xml == null)
				xml = getClass().getClassLoader().getParent().getResource(CONFIG_XML);
			channel = new JChannel(xml);
			channel.setReceiver(this);
			channel.connect(this.name);
			
			log.info("Connected to channel:" + this.name + ", time " + (System.currentTimeMillis()-ct) + " ms.");

		}catch(Exception e){
			throw new CacheException(e);
		}
	}

	/**
	 * 获取缓存中的数据
	 * @param region: Cache Region name
	 * @param key: Cache key
	 * @return cache object
	 */
	public CacheObject get(String region, Object key){
		CacheObject obj = new CacheObject();
		obj.setRegion(region);
		obj.setKey(key);
        if(region!=null && key != null){
        	obj.setValue(CacheManager.get(LEVEL_1, region, key));
            if(obj.getValue() == null) {
            	obj.setValue(CacheManager.get(LEVEL_2, region, key));
                if(obj.getValue() != null){
                	obj.setLevel(LEVEL_2);
                    CacheManager.set(LEVEL_1, region, key, obj.getValue());
                }
            }
            else
            	obj.setLevel(LEVEL_1);
        }
        return obj;
	}
	
	/**
	 * 写入缓存
	 * @param region: Cache Region name
	 * @param key: Cache key
	 * @param value: Cache value
	 */
	public void set(String region, Object key, Object value){
		if(region!=null && key != null){
			if(value == null)
				evict(region, key);
			else{
				//分几种情况
				//Object obj1 = CacheManager.get(LEVEL_1, region, key);
				//Object obj2 = CacheManager.get(LEVEL_2, region, key);
				//1. L1 和 L2 都没有
				//2. L1 有 L2 没有(这种情况不存在,除非是写 L2 的时候失败
				//3. L1 没有,L2 有
				//4. L1 和 L2 都有
				_sendEvictCmd(region, key);//清除原有的一级缓存的内容
				CacheManager.set(LEVEL_1, region, key, value);
				CacheManager.set(LEVEL_2, region, key, value);
			}
		}
		//log.info("write data to cache region="+region+",key="+key+",value="+value);
	}
	
	public void set(String region, Object key, Object value, Integer expireInSec){
		if(region!=null && key != null){
			if(value == null)
				evict(region, key);
			else{
				//分几种情况
				//Object obj1 = CacheManager.get(LEVEL_1, region, key);
				//Object obj2 = CacheManager.get(LEVEL_2, region, key);
				//1. L1 和 L2 都没有
				//2. L1 有 L2 没有(这种情况不存在,除非是写 L2 的时候失败
				//3. L1 没有,L2 有
				//4. L1 和 L2 都有
				_sendEvictCmd(region, key);//清除原有的一级缓存的内容
				CacheManager.set(LEVEL_1, region, key, value, expireInSec);
				CacheManager.set(LEVEL_2, region, key, value, expireInSec);
			}
		}
		//log.info("write data to cache region="+region+",key="+key+",value="+value);
	}
	
	/**
	 * 删除缓存
	 * @param region:  Cache Region name
	 * @param key: Cache key
	 */
	public void evict(String region, Object key) {
		CacheManager.evict(LEVEL_1, region, key); //删除一级缓存
		CacheManager.evict(LEVEL_2, region, key); //删除二级缓存
		_sendEvictCmd(region, key); //发送广播
	}

	/**
	 * 批量删除缓存
	 * @param region: Cache region name
	 * @param keys: Cache key
	 */
	@SuppressWarnings({ "rawtypes" })
	public void batchEvict(String region, List keys) {
		CacheManager.batchEvict(LEVEL_1, region, keys);
		CacheManager.batchEvict(LEVEL_2, region, keys);
		_sendEvictCmd(region, keys);
	}

	/**
	 * Clear the cache
	 * @param region: Cache region name
	 */
	public void clear(String region) throws CacheException {
		CacheManager.clear(LEVEL_1, region);
		CacheManager.clear(LEVEL_2, region);
		_sendClearCmd(region);
	}
	
	/**
	 * Get cache region keys
	 * @param region: Cache region name
	 * @return key list
	 */
	@SuppressWarnings("rawtypes")
	public List keys(String region) throws CacheException {
		return CacheManager.keys(LEVEL_1, region);
	}
	
	/**
	 * 为了保证每个节点缓存的一致,当某个缓存对象因为超时被清除时,应该通知群组其他成员
	 * @param region: Cache region name
	 * @param key: cache key
	 */
	@Override
	@SuppressWarnings("rawtypes")
	public void notifyElementExpired(String region, Object key) {

		log.debug("Cache data expired, region="+region+",key="+key);
		
		//删除二级缓存
		if(key instanceof List)
			CacheManager.batchEvict(LEVEL_2, region, (List)key);
		else
			CacheManager.evict(LEVEL_2, region, key);
		
		//发送广播
		_sendEvictCmd(region, key);
	}
	
	/**
	 * 发送删除缓存的广播命令
	 * @param region: Cache region name
	 * @param key: cache key
	 */
	private void _sendEvictCmd(String region, Object key) {
		//发送广播
		Command cmd = new Command(Command.OPT_DELETE_KEY, region, key);
		try {
			Message msg = new Message(null, null, cmd.toBuffers());
			channel.send(msg);
		} catch (Exception e) {
			log.error("Unable to delete cache,region="+region+",key="+key, e);
		}
	}

	/**
	 * 发送清除缓存的广播命令
	 * @param region: Cache region name
	 * @param key: cache key
	 */
	private void _sendClearCmd(String region) {
		//发送广播
		Command cmd = new Command(Command.OPT_CLEAR_KEY, region, "");
		try {
			Message msg = new Message(null, null, cmd.toBuffers());
			channel.send(msg);
		} catch (Exception e) {
			log.error("Unable to clear cache,region="+region, e);
		}
	}

	/**
	 * 删除一级缓存的键对应内容
	 * @param region: Cache region name
	 * @param key: cache key
	 */
	@SuppressWarnings("rawtypes")
	protected void onDeleteCacheKey(String region, Object key){
		if(key instanceof List)
			CacheManager.batchEvict(LEVEL_1, region, (List)key);
		else
			CacheManager.evict(LEVEL_1, region, key);
		log.debug("Received cache evict message, region="+region+",key="+key);
	}

	/**
	 * 清除一级缓存的键对应内容
	 * @param region
	 * 		 Cache region name
	 */
	protected void onClearCacheKey(String region){
		CacheManager.clear(LEVEL_1, region);
		log.debug("Received cache clear message, region="+region);
	}

	/**
	 * 消息接收
	 * @param msg 接收到的消息
	 */
	@Override
	public void receive(Message msg) {
		//无效消息
		byte[] buffers = msg.getBuffer();
		if(buffers.length < 1){
			log.warn("Message is empty.");
			return;
		}
		
		//不处理发送给自己的消息
		if(msg.getSrc().equals(channel.getAddress()))
			return ;
		
		try{
			Command cmd = Command.parse(buffers);
			
			if(cmd == null)
				return;
			
			switch(cmd.getOperator()){
			case Command.OPT_DELETE_KEY:
				onDeleteCacheKey(cmd.getRegion(), cmd.getKey());
				break;
			case Command.OPT_CLEAR_KEY:
				onClearCacheKey(cmd.getRegion());
				break;
			default:
				log.warn("Unknown message type = " + cmd.getOperator());
			}
		}catch(Exception e){
			log.error("Unable to handle received msg" , e);
		}
	}
	
	/**
	 * 组中成员变化时
	 * @param view group view
	 */
	public void viewAccepted(View view) {
		StringBuffer sb = new StringBuffer("Group Members Changed, LIST: ");
		List
addrs = view.getMembers(); for(int i=0; i 0) sb.append(','); sb.append(addrs.get(i).toString()); } log.info(sb.toString()); } /** * 关闭到通道的连接 */ public void close(){ CacheManager.shutdown(LEVEL_1); CacheManager.shutdown(LEVEL_2); channel.close(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy