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);
}
}