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

}

采用Spring实现在容器启动时把用ConcurrentHashMap实现的并发缓存加载到ServletContext中

时间: 2024-10-10 21:08:08

采用Spring实现在容器启动时把用ConcurrentHashMap实现的并发缓存加载到ServletContext中的相关文章

spring在web容器启动时执行初始化方法

需求:在tomcat启动时开启一个定时任务. 想法:容器启动时执行方法,最容易想到的就是servlet中可以配置load-on-startup,设置一个正整数也就可以随容器一起启动. 问题:上面的方法很好,但是由于定时任务需要去操作数据库,而项目采用了spring的依赖注入来管理对象,而servlet并不受Spring的管理.若此时在servlet中注入Spring管理的对象,则会报错:javax.naming.NameNotFoundException: Name com.test.InitS

spring mvc web应用启动时就执行特定处理(线程启动)

package com.sdt.platform.index.controller; import java.net.URL; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.annotation.Resource; import org.springframework.beans.BeansException; import org.sprin

spring加载jar包中多个配置文件(转)

转自:http://evan0625.iteye.com/blog/1598366 在使用spring加载jar包中的配置文件时,不支持通配符,需要一个一个引入,如下所示: Java代码 <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath*:beanconfigs/applicationContext_1.xml, classpath*:

spring加载jar包中的多个配置文件[转载]

在使用spring加载jar包中的配置文件时,不支持通配符,需要一个一个引入,如下所示: Java代码 <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath*:beanconfigs/applicationContext_1.xml, classpath*:beanconfigs/applicationContext_2.xml, ...

(备忘)vs2010编写动态链接库时导出函数的函数名问题及加载方式

在vs2010中使用.def文件导出函数时,仅仅添加.def文件是不够的,还要在 项目属性 -> 链接器 -> 输入 -> 模块定义文件 中添加自定义的.def文件名. (前提:导入导出都在头文件和源文件中定义好了) ##:静态加载动态链接库 将链接库的 头文件..lib文件 和 .dll 文件拷贝到工程目录下 然后#include 头文件,#pragma comment(lib,"**.lib") 最后直接在需要使用dll函数的地方使用函数就行 ##:动态加载动态链

Error 25007.初始化合成时发生错误。安装程序无法使用 LoadLibraryShim() 加载合成。

安装"Microsoft .NET Framework 2.exe"报错如下: c:\windows\microsoft.net\framework\...类似这种错误都因 .NET Framework受到损害.有一部分程序将无法使用.微软输入法也将瘫痪... ---------------------------Microsoft .NET Framework 2.0 安装程序---------------------------Error 25007.初始化合成时发生错误.安装程序

【Spring框架】 ? 项目启动时执行特定处理及ApplicationListener源码分析

1.背景 在一些业务场景中,在容器启动完成后,需要处理一些诸如:kafka业务注册,数据处理,初始化缓存等的操作. 本文重点介绍如何在服务启动中,或启动完成时执行相关处理. 2.针对上述场景,有如下实现方法 A:实现基于javaweb的ServletContextListener接口,重写contextInitialized()接口   B:实现基于javaweb的javax.servlet包下的Filter接口,重写init(FilterConfig filterConfig)接口   C:继

基于spring的web项目启动时预加载数据到ServletContext

1.要在web启动时预加载数据到ServletContext,实现方法有很多,一种比较简单的方案就是: 1)新建一个bean,定义其初始化方法: <bean id="beanId" init-method="初始化方法" />或者使用@PostConstruct注解到初始化方法上面 2)获取ServletContext实例对象,如何获取呢? 方法1: @Autowired private ServletContext application; 方法2:

关于tomcat下spring无法加载依赖jar中properties文件的原因分析

我们经常把spring需要加载的properties文件放在java/resources下面,这样存放的问题导致properties在打包后就在jar的根目录下,所以我们的spring的配置路径就是classpath*:xxx.properties,但是这样的jar我们在被其他项目引用的时候会发现properties文件老是无法加载,就这个问题从spring的源码来找找为什么会这样. 首先properties是当做一个resource来加载的,实现加载的是org.springframework.