Web项目启动加载数据至内存--SpringApplicationListener实现

来源:https://www.cnblogs.com/CoderGuokai/p/7884746.html

需求:

    1.项目开发中会有一些平凡使用的数据需要加载到内存中;以减少数据库交互次数.降低服务器和数据库压力.

思路:

    1.在系统启动时,将监听web容器创建完成事件;
    2.创建一个用于存储相关数据的Dic类;
    3.在监听到容器创建完成后,将为Dic类中的静态变量赋值;
    4.这样就可以在应用中随意使用Dic类中的数据;

优劣势:

    1.减少web服务与数据库的交互次数,减轻双方压力;
    2.web服务启动时间将会被延长;

环境:

     import org.springframework.context.ApplicationListener;
     import org.springframework.context.event.ContextRefreshedEvent;

过程:

    1.创建一个类实现接口 ApplicationListener<ContextRefreshedEvent>,并将这个类用@component标签扫描入Spring的对象管理池;
@Component
public class AppSpringEventListener implements ApplicationListener<ContextRefreshedEvent>{
	@Override
	public void onApplicationEvent(ContextRefreshedEvent arg0) {
		//spring会调用两次这个方法,因为启动时会创建了两个容器(root application context 和projectName-servlet context),
		//我们只在root上下文创建成功后执行这个方法,初始化参数
		if(arg0.getApplicationContext().getParent()==null){
			//初始化数据字典
			DictionariesHelper.getInstance().init();
			//初始化省市县字典
			RegionHelper.getInstance().init();
		}	
	}
}
 
    2.在DictionariesHelper类中定义静态变量用于存储字典信息,在RegionHelper中定义静态变量用于存储省市县信息;
@Component
public class DictionariesHelper {
	private static final Logger log = LoggerFactory.getLogger(DictionariesHelper.class);
	//按层级存储字典信息
	private static Map<Object,Object> dataDictionaries = new LinkedHashMap<Object,Object>();
	//存储所有字典信息
	private static Map<String, String> dataAllMap = new LinkedHashMap<String, String>();
	private static DictionariesHelper dictionariesHelper;
	//service组件
	private static DataDictionariesServise dataDictionariesServise;
	//私有化构造函数
	private DictionariesHelper(){}
	
	public static DictionariesHelper getInstance(){
		if(DictionariesHelper.dictionariesHelper==null){
			DictionariesHelper.dictionariesHelper = new DictionariesHelper();
		}
		return DictionariesHelper.dictionariesHelper;
	}
	/**
	 * 初始化数据字典
	 */
	public void init(){
		if(DictionariesHelper.dataDictionaries.size()==0){
			initDataDictionaries();
		}
	}
	/**
	 * 重载数据字典
	 */
	public void reLoad() {
		// TODO Auto-generated method stub
		DictionariesHelper.dataDictionaries.clear();
		DictionariesHelper.dataAllMap.clear();
		init();
	}
	/**
	 * 初始化数据字典
	 */
	private void initDataDictionaries(){
		log.info("--------------数据字典初始化开始---------------");
		//获取系统当前时间
		Long startTime = System.currentTimeMillis();
		List<Map<String, Object>> typeList = dataDictionariesServise.queryDataType();
		for(Map<String, Object> typeMap:typeList){
			LinkedHashMap<Object, Object> paraMap = new LinkedHashMap<Object,Object>();
			paraMap.put("OBJTYPE", typeMap.get("OBJTYPE"));
			paraMap.put("OBJNAME", typeMap.get("OBJNAME"));
			paraMap.put("OBJTYPECODE", typeMap.get("CONTYPEID"));
			List<Map<String, Object>> dataList = dataDictionariesServise.queryDataByType(typeMap);
			for(Map<String, Object> dataMap:dataList){
				//加载所有数据至dataAllMap
				DictionariesHelper.dataAllMap.put((String)dataMap.get("CONCODE"),(String)dataMap.get("CONNAME"));
			}
			DictionariesHelper.dataDictionaries.put(typeMap.get("OBJTYPE"), dataList);
		}
		log.info("--------------数据字典完成初始化,共用时"+(System.currentTimeMillis()-startTime)+"ms---------------");
	}
	
	/**
	 * 获取所有字典数据
	 */
	public static Map<Object,Object> getDataDictionaries(){
		return DictionariesHelper.dataDictionaries;
	}
	
    /**
	 * 根据类型获取下设的字典数据
	 * @param type 类型编码(T_COMMON_TYPE表中的OBJTYPE字段)
	 * @return map:key为code,value为name
	 */
	public static List getDicListByType(String type){
		return  (List)DictionariesHelper.dataDictionaries.get(type);
	}
	
    /**
	 * 根据key获取value
	 * @param code 编码(T_COMMON_INFO中的CONCODE)
	 * @return 值(T_COMMON_INFO中的CONNAME)
	 */
	public static String getDicValueByCode(String code){
		return DictionariesHelper.dataAllMap.get(code);
	}
	
	@Autowired(required = true)
	public void setDataDictionariesServise(DataDictionariesServise dataDictionariesServise){
		DictionariesHelper.dataDictionariesServise = dataDictionariesServise;
	}
}
  @Component
public class RegionHelper {
	private static final Logger log = LoggerFactory.getLogger(RegionHelper.class);
	private static Map<Object,Object> regionDictionaries = new LinkedHashMap<Object, Object>(); 
	private static RegionHelper regionHelper;
	//service组件
	private static DataDictionariesServise dataDictionariesServise;
	private static List<Map<String, Object>> zTreeDatalist = new ArrayList<Map<String, Object>>();
	//省市县级别
	public static Integer province = 1;
	public static Integer city = 2;
	public static Integer town = 3;
	public static RegionHelper getInstance(){
		if(RegionHelper.regionHelper==null){
			RegionHelper.regionHelper = new RegionHelper();
		}
		return RegionHelper.regionHelper;
	}
    
	/**
	 * 初始化省市县字典
	 */
	public void init(){
		if(RegionHelper.regionDictionaries.size()==0){
			initRegionDictionaries();
		}
	}
    
	/**
	 * 重载省市县字典
	 */
	public void reLoad(){
		RegionHelper.regionDictionaries.clear();
		init();
	}
    
	/**
	 * 初始化省市县字典
	 */
	private void initRegionDictionaries() {
		log.info("--------------省市县字典初始化开始---------------");
		//获取系统当前时间
		Long startTime = System.currentTimeMillis();
		List<Map<String, Object>> list= dataDictionariesServise.queryRegion();
		for(Map<String, Object> map:list){
			//根据map构造字典
			loadRegionData(map);
		}
		log.info("--------------省市县字典完成初始化,共用时"+(System.currentTimeMillis()-startTime)+"ms---------------");
	}
	
	/**
	 * 根据编码获取这个区划的Map,其中AREALIST是下设区县
	 * @param regionCode 需要的省市县
	 * @return 区划Map
	 */
	public static Map<Object,Object> getRegionMapByRegionCode(String regionCode){
		Integer level = RegionHelper.getRegionLevelByCode(regionCode);
		if(level==RegionHelper.province){
			return (Map<Object,Object>)RegionHelper.regionDictionaries.get(regionCode);
		}else if(level==RegionHelper.city){
			return (Map<Object,Object>)((Map<Object,Object>)(((Map<Object,Object>)RegionHelper.regionDictionaries.get(regionCode.substring(0,2)+"0000")).get("AREALIST"))).get(regionCode);
		}else if(level==RegionHelper.town){
			return (Map<Object,Object>)((Map<Object,Object>)((Map<Object,Object>)((Map<Object,Object>)(((Map<Object,Object>)RegionHelper.regionDictionaries.get(regionCode.substring(0,2)+"0000")).get("AREALIST"))).get(regionCode.substring(0,4)+"00")).get("AREALIST")).get(regionCode);
		}else{
			return null;
		}
	}
    
	/**
	 * 根据编码获取这个区划的下设区域,数据符合zTree简单数据格式
	 * @param regionCode 需要的省市县编码
	 * @return 符合zTree简单数据格式的json字符串
	 */
	public static String getRegionZTreeDataByRegionCode(String regionCode){
		RegionHelper.zTreeDatalist.clear();
		return JSONArray.toJSONString(RegionHelper.getRegionZTreeListByMap(RegionHelper.getRegionMapByRegionCode(regionCode)));
	}

	private static List<Map<String, Object>> getRegionZTreeListByMap(Map<Object, Object> map) {
		Map<String,Object> resultMap = new LinkedHashMap<String, Object>();
		resultMap.put("id", map.get("CODE"));
		resultMap.put("name", map.get("NAME"));
		resultMap.put("pId", map.get("SUPERIOR"));
		boolean isAdd = true;
		if((Map<Object,Object>)map.get("AREALIST")!=null&&((Map<Object,Object>)map.get("AREALIST")).size()>0){
			resultMap.put("isParent",true);
			RegionHelper.zTreeDatalist.add(resultMap);
			isAdd = false;
			Iterator iter = ((Map<Object,Object>)map.get("AREALIST")).keySet().iterator();
			while(iter.hasNext()){
				RegionHelper.getRegionZTreeListByMap((Map<Object,Object>)((Map<Object,Object>)map.get("AREALIST")).get(iter.next()));
			}
		}else{
			resultMap.put("isParent",false);
		}
		if(isAdd){
			RegionHelper.zTreeDatalist.add(resultMap);
		}
		//数组反转
		//Collections.reverse(RegionHelper.zTreeDatalist);
		return RegionHelper.zTreeDatalist;
	}
    
	/**
	 * @param regionCode 地区编码
	 * @return 省市县级别:1代表省;2代表市3代表县
	 */
	public static Integer getRegionLevelByCode(String regionCode){
		Integer i = Integer.parseInt(regionCode);
		if(i%100==0){
			if(i%10000==0){
				return RegionHelper.province;
			}else {
				return RegionHelper.city;
			}
		}else{
			return RegionHelper.town;
		}
	}
	
	private Boolean loadRegionData(Map<String, Object> map) {
		//加载省
		if(RegionHelper.regionDictionaries.get(map.get("PROCODE"))==null){
			Map<Object,Object> dataMap = new LinkedHashMap<Object,Object>();
			dataMap.put("CODE", map.get("PROCODE"));
			dataMap.put("NAME", map.get("PRONAME"));
			dataMap.put("AREALIST",new LinkedHashMap<Object,Object>());
			RegionHelper.regionDictionaries.put(map.get("PROCODE"), dataMap);
		}
		if(map.get("PROCODE")==null){
			return true;
		}
		//加载市
		Map<Object,Object> obj = (Map<Object,Object>)(((Map<Object,Object>)RegionHelper.regionDictionaries.get(map.get("PROCODE"))).get("AREALIST"));
		if(obj.get(map.get("CITYCODE"))==null&&map.get("CITYCODE")!=null){
			Map<Object,Object> dataMap = new LinkedHashMap<Object,Object>();
			dataMap.put("CODE", map.get("CITYCODE"));
			dataMap.put("NAME", map.get("CITYNAME"));
			dataMap.put("SUPERIOR", map.get("PROCODE"));
			dataMap.put("AREALIST",new LinkedHashMap<Object,Object>());
			obj.put(map.get("CITYCODE"), dataMap);
		}
		if(map.get("CITYCODE")==null){
			return true;
		}
		//加载县
		obj = (Map<Object,Object>)((Map<Object,Object>)((Map<Object,Object>)(((Map<Object,Object>)RegionHelper.regionDictionaries.get(map.get("PROCODE"))).get("AREALIST"))).get(map.get("CITYCODE"))).get("AREALIST");
		if(obj.get("TOWNCODE")==null&&map.get("TOWNCODE")!=null){
			Map<Object,Object> dataMap = new LinkedHashMap<Object,Object>();
			dataMap.put("CODE", map.get("TOWNCODE"));
			dataMap.put("NAME", map.get("TOWNNAME"));
			dataMap.put("SUPERIOR", map.get("CITYCODE"));
			obj.put(map.get("TOWNCODE"), dataMap);
		}
		return true;
	}
	
	@Autowired(required = true)
	public void setDataDictionariesServise(DataDictionariesServise dataDictionariesServise){
		RegionHelper.dataDictionariesServise = dataDictionariesServise;
	} 
}
   //调用省市县内存数据
String ztreeData = RegionHelper.getRegionZTreeDataByRegionCode("XXX");
//调用字典内存数据
List dicList = DictionariesHelper.getDicListByType("xxx");

原理:

    1.Spring会在web容器创建完成时调用SpringApplicationListener接口中的onApplicationEvent方法,所以我们自定义类实现 SpringApplicationListener接口,重写onApplicationEvent方法.以便spring在容器完成创建事件后调用我的实现类,运行自定义方法.

总结:

    1.使用@Component标注两个工具类是为了可以使用@Autowired标签帮助我将service对象注入对象中;
    2.不能在在声明service对象的属性名上直接使用@Autowired标签,那样的话值注不进去还spring报错(不清楚为什么).所以我写了set方法用于注入service;
    3.在两个Helper类中,我用于存储数据的都是LinkedHashMap,而不是HashMap,因为,字典和省市县在读取数据时很多时候都会排序的寻求.而HashMap是无序的.这样就算我在SQL中将数据排序.当放入Map中时又变成无序的了.而LinkedHashMap会记录数据进入的循序.这样的话就可以满足我排序的要求;
    4.在 SpringApplicationListener中的onApplicationEvent方法中我做了一个if判断,是因为Spring在启动中会在两个容器创建时(root application context和projectName-servlet context).其中projectName-servlet context是root application context的子容器.所以,我们判断当当前容器的父容器是空时(也就是root application context),才执行我们的初始化方法.
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值