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); } }
采用Spring实现在容器启动时把用ConcurrentHashMap实现的并发缓存加载到ServletContext中
时间: 2024-10-10 21:08:08