採用Spring實現在容器啓動時把用ConcurrentHashMap實現的併發緩存加載到ServletContext中

1.ConstantDataDTO.java,一定要重寫hashcode和equals方法

import java.io.Serializable;
import java.util.Date;

/**
 * ConstantDataDTO.java
 * 
 * @author steveguoshao
 * @created 2014年07月10日 下午6:15:55
 * @version 1.0
 */
public class ConstantDataDTO implements Serializable {

	/**
	 * serialVersionUID:TODO
	 * 
	 * @since 1.0.0
	 */
	private static final long serialVersionUID = -504215100856069620L;

	private String codeSet;

	private String code;

	private String codeContent;

	private String parentCode;

	private Integer seqNum;

	private Date cjsj;

	private Date xgsj;

	public String getCodeSet() {
		return codeSet;
	}

	public void setCodeSet(String codeSet) {
		this.codeSet = codeSet;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public String getCodeContent() {
		return codeContent;
	}

	public void setCodeContent(String codeContent) {
		this.codeContent = codeContent;
	}

	public String getParentCode() {
		return parentCode;
	}

	public void setParentCode(String parentCode) {
		this.parentCode = parentCode;
	}

	public Integer getSeqNum() {
		return seqNum;
	}

	public void setSeqNum(Integer seqNum) {
		this.seqNum = seqNum;
	}

	public Date getCjsj() {
		return cjsj;
	}

	public void setCjsj(Date cjsj) {
		this.cjsj = cjsj;
	}

	public Date getXgsj() {
		return xgsj;
	}

	public void setXgsj(Date xgsj) {
		this.xgsj = xgsj;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((code == null) ? 0 : code.hashCode());
		result = prime * result + ((codeSet == null) ? 0 : codeSet.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		ConstantDataDTO other = (ConstantDataDTO) obj;
		if(other.getCode().equals(code) && other.getCodeSet().equals(codeSet)) {
			return true;
		} 
		return false;
	}

	
}

2.用ConcurrentHashMap實現緩存ConstantDataCache,剛開始雖然用的是ConcurrentHashMap當數據容器,但是各方法裏面的操作並不是採用ConcurrentMap接口裏面的方法,而是採用Map接口裏面的方法,而且各操作並不是原子的,所以並不能實現併發,還是會出現ConcurrentModificationException,要實現併發必須要用ConcurrentMap接口裏面的方法。

ConcurrentMap代碼如下,注意接口裏面每個方法的註釋,裏面寫了等同於原先採用Map接口裏面的方法實現代碼


public interface ConcurrentMap<K, V> extends Map<K, V> {
    /**
     * If the specified key is not already associated
     * with a value, associate it with the given value.
     * This is equivalent to
     * <pre>
     *   if (!map.containsKey(key))
     *       return map.put(key, value);
     *   else
     *       return map.get(key);</pre>
     *
     */
    V putIfAbsent(K key, V value);

    /**
     * Removes the entry for a key only if currently mapped to a given value.
     * This is equivalent to
     * <pre>
     *   if (map.containsKey(key) && map.get(key).equals(value)) {
     *       map.remove(key);
     *       return true;
     *   } else return false;</pre>
     */
    boolean remove(Object key, Object value);

    /**
     * Replaces the entry for a key only if currently mapped to a given value.
     * This is equivalent to
     * <pre>
     *   if (map.containsKey(key) && map.get(key).equals(oldValue)) {
     *       map.put(key, newValue);
     *       return true;
     *   } else return false;</pre>
     */
    boolean replace(K key, V oldValue, V newValue);

    /**
     * Replaces the entry for a key only if currently mapped to some value.
     * This is equivalent to
     * <pre>
     *   if (map.containsKey(key)) {
     *       return map.put(key, value);
     *   } else return null;</pre>
     */
    V replace(K key, V value);
}

ConstantDataCache.java

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
 * ConstantDataCache.java
 * @author 	  steveguoshao	
 * @created   2014年07月10日 下午2:54:46
 * @version   1.0
 */
@Component
@Scope(value="singleton")
public class ConstantDataCache {

	@Autowired(required = true)
	private ConstantDataServiceImpl constantDataService;
	
	private static ConcurrentMap<String, List<ConstantDataDTO>> CACHE = new ConcurrentHashMap<String, List<ConstantDataDTO>>();
	
	/**
	 * 從數據庫初始化緩存
	 * init 
	 * void
	 * @since  1.0.0
	 */
	@PostConstruct
	private void init() {
		load();
	}
	
	/**
	 * 加載緩存
	 * load 
	 * void
	 * @since  1.0.0
	 */
	public void load() {
		Set<String> codeSets = constantDataService.findAllCodeSet();
		for(String codeSet : codeSets) {
			CACHE.putIfAbsent(codeSet, constantDataService.findByCodeSet(codeSet));
		}
	}
	
	/*
	 * 重新加載緩存
	 */
	public void reload() {
		CACHE.clear();
		load();
	}
	
	/**
	 * 獲取緩存
	 * getCache
	 * @return 
	 * Map<String,List<ConstantDataDTO>>
	 * @exception 
	 * @since  1.0.0
	 */
	public Map<String, List<ConstantDataDTO>> getCache() {
		return CACHE;
	}
	
	/**
	 * 根據代碼集從緩存裏面獲取常量數據
	 * getCacheByCodeSet
	 * @param key
	 * @return 
	 * List<ConstantData>
	 * @since  1.0.0
	 */
	public List<ConstantDataDTO> getConstantDataList(String key) {
		return CACHE.get(key);
	}
	
	/**
	 * 根據代碼集和父代碼從緩存裏面獲取常量數據
	 * getConstantDataListByParentCode
	 * @param key
	 * @param parentCode
	 * @return 
	 * List<ConstantData>
	 * @since  1.0.0
	 */
	public List<ConstantDataDTO> getConstantDataListByParentCode(String key, String parentCode) {
		List<ConstantDataDTO> dtoList = CACHE.get(key);
		List<ConstantDataDTO> resultList = new ArrayList<ConstantDataDTO>();
		for (ConstantDataDTO dto : dtoList) {
			if (parentCode.equals(dto.getParentCode())) {
				resultList.add(dto);
			}
		}
		return resultList;
	}
	
	/**
	 * 根據代碼集和代碼從緩存裏面獲取常量數據
	 * getConstantData
	 * @param key
	 * @param code
	 * @return 
	 * ConstantData
	 * @since  1.0.0
	 */
	public ConstantDataDTO getConstantData(String key, String code) {
		if(StringUtils.isNotEmpty(key) 
				&& StringUtils.isNotEmpty(code)) {
			List<ConstantDataDTO> dtoList = CACHE.get(key);
			ConstantDataDTO dto = new ConstantDataDTO();
			dto.setCodeSet(key);
			dto.setCode(code);
			int index = dtoList.indexOf(dto);
			if(index > -1) {
				return dtoList.get(index);
			}
		}
		return null;
	}
	
	/**
	 * 根據代碼集和代碼獲取代碼內容
	 * getCodeContent
	 * @param key
	 * @param code
	 * @return 
	 * String
	 * @since  1.0.0
	 */
	public static String getCodeContent(String key, String code) {
		String codeContent = "";
		if(StringUtils.isNotEmpty(key) 
				&& StringUtils.isNotEmpty(code)) {
			List<ConstantDataDTO> dtoList = CACHE.get(key);
			ConstantDataDTO dto = new ConstantDataDTO();
			dto.setCodeSet(key);
			dto.setCode(code);
			int index = dtoList.indexOf(dto);
			if(index > -1) {
				codeContent = dtoList.get(index).getCodeContent();
			}
		}
		return codeContent;
	}
	
	/**
	 * 根據代碼集和父代碼從緩存裏面獲取常量數據
	 * getCacheByParentCode
	 * @param key
	 * @param parentCode
	 * @return 
	 * List<ConstantData>
	 * @since  1.0.0
	 */
	public static List<ConstantDataDTO> getCacheByParentCode(String key, String parentCode) {
		List<ConstantDataDTO> dtoList = CACHE.get(key);
		List<ConstantDataDTO> resultList = new ArrayList<ConstantDataDTO>();
		for (ConstantDataDTO dto : dtoList) {
			if (dto.getParentCode().equals(parentCode)) {
				resultList.add(dto);
			}
		}
		return resultList;
	}
	
	/**
	 * 把新增加或更新的常量加入到緩存中來
	 * put
	 * @param model 
	 * void
	 * @since  1.0.0
	 */
	public void put(ConstantDataDTO model) {
		List<ConstantDataDTO> dtoList = CACHE.get(model.getCodeSet());
		List<ConstantDataDTO> newDtoList = dtoList == null ? new ArrayList<ConstantDataDTO>() : dtoList;
		newDtoList.add(model);
		if(null != dtoList && dtoList.size() > 0) {
			CACHE.replace(model.getCodeSet(), newDtoList);
		} else {
			CACHE.putIfAbsent(model.getCodeSet(), newDtoList);
		}
	}
	
	/**
	 * 從緩存中刪除數據
	 * remove
	 * @param key 
	 * void
	 * @since  1.0.0
	 */
	public void remove(ConstantDataDTO model) {
		List<ConstantDataDTO> dtoList = CACHE.get(model.getCodeSet());
		if(null != dtoList ) {
			if(dtoList.size() > 1) {
				dtoList.remove(model);
				CACHE.replace(model.getCodeSet(), dtoList);
			} else {
				CACHE.remove(model.getCodeSet());
			}
		}
	}
	
	/**
	 * 銷燬緩存
	 * destory 
	 * void
	 * @since  1.0.0
	 */
	@PreDestroy
	public void destory() {
		CACHE.clear();
	}
}

3.實現InitializingBean接口讓Spring容器在啓動的時候能夠加載數據,實現ServletContextAware接口能夠通過AOP獲取ServletContext,從而實現把緩存放到application中。

SystemDataBean.java


import javax.servlet.ServletContext;
import javax.sql.DataSource;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.ServletContextAware;

/**
 * CacheBean.java
 * @author    steveguoshao	
 * @created   2014年07月10日 下午3:36:13
 * @version   1.0
 */
@Component
public class SystemDataBean implements InitializingBean,ServletContextAware {

	private ServletContext servletContext;
	@Override
	public void setServletContext(ServletContext servletContext) {
		this.servletContext = servletContext;
	}
	
	@Autowired
	private ConstantDataCache dataCache;
	
	@Autowired
	private DataSource dataSource;
	
	@Override
	public void afterPropertiesSet() throws Exception {
		// 把緩存放入到servletcontext
		servletContext.setAttribute(Constants.CACHE, dataCache.getCache());
		servletContext.setAttribute(Constants.DATA_SOURCE, dataSource);
	}

}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章