【Spring实战】Spring容器初始化完成后执行初始化数据方法
一、背景知识及需求
在做WEB项目时,经常在项目第一次启动时利用WEB容器的监听、Servlet加载初始化等切入点为数据库准备数据,这些初始化数据是系统开始运行前必须的数据,例如权限组、系统选项、默认管理员等等。而项目采用了Spring依赖注入来管理对象,而servlet并不受Spring的管理。若此时在servlet中注入Spring管理的对象,则无法使用,如下:
public class InitServlet extends HttpServlet {
@Autowired
private IProductService productService;
@Autowired
private IUserService userService;
......
}
这个时候是无法使用上述中的两个service的,因为InitServlet不受Spring容器管理。虽然可以用getBean的方式手动获取service,但是违反了使用Spring的初衷。
该篇文章也在之前【Spring实战】系列的基础上进行优化和深入分析,本篇就是在更换了hsqldb数据库并初始化了商品、普通用户和管理员用户需求时产生的。
二、Spring提供的解决方案
1、InitializingBean
直接上代码
/**
* Created by Administrator on 2017/6/15.
* spring容器启动后,初始化数据(产生一个默认商品、普通用户和管理员用户)
*/
@Component
public class InitServlet implements InitializingBean {
@Autowired
private IProductService productService;
@Autowired
private IUserService userService;
@Override
public void afterPropertiesSet() throws Exception {
//库中没有商品则声称一个
List<Product> products = productService.getProductList();
if (null == products || products.isEmpty()){
Product product = new Product();
product.setProductName("Mango");
product.setQuantity(100);
product.setUnit("个");
product.setUnitPrice(100);
productService.saveProduct(product);
}
//库中没有用户则添加普通用户和管理员用户
List<MangoUser> mangoUsers = userService.getUserList();
if(null == mangoUsers || mangoUsers.isEmpty()){
MangoUser mangoUser = new MangoUser();
mangoUser.setUserName("mango");
mangoUser.setPassword(StringUtil.md5("123456"));
mangoUser.setRole("ROLE_USER");
userService.saveUser(mangoUser);
MangoUser mangoUser1 = new MangoUser();
mangoUser1.setUserName("manager");
mangoUser1.setPassword(StringUtil.md5("123456"));
mangoUser1.setRole("ROLE_MANAGER");
userService.saveUser(mangoUser1);
}
}
}
若采用XML来配置Bean的话,可以指定属性init-method。
2、ApplicationListener
//交给Spring管理,如果不是自动扫描加载bean的方式,则在xml里配一个即可
@Component
public class InitData implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
private IProductService productService;
@Autowired
private IUserService userService;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (event.getApplicationContext().getParent() == null) {
//库中没有商品则声称一个
List<Product> products = productService.getProductList();
if (null == products || products.isEmpty()){
Product product = new Product();
product.setProductName("Mango");
product.setQuantity(100);
product.setUnit("个");
product.setUnitPrice(100);
productService.saveProduct(product);
}
//库中没有用户则添加普通用户和管理员用户
List<MangoUser> mangoUsers = userService.getUserList();
if(null == mangoUsers || mangoUsers.isEmpty()){
MangoUser mangoUser = new MangoUser();
mangoUser.setUserName("mango");
mangoUser.setPassword(StringUtil.md5("123456"));
mangoUser.setRole("ROLE_USER");
userService.saveUser(mangoUser);
MangoUser mangoUser1 = new MangoUser();
mangoUser1.setUserName("manager");
mangoUser1.setPassword(StringUtil.md5("123456"));
mangoUser1.setRole("ROLE_MANAGER");
userService.saveUser(mangoUser1);
}
}
}
}
注意是监听的ContextRefreshedEvent事件。
在web 项目中(spring mvc),系统会存在两个容器,一个是root application context ,另一个就是我们自己的 projectName-servlet context(作为root application context的子容器)。这种情况下,就会造成onApplicationEvent方法被执行两次。为了避免上面提到的问题,我们可以只在root application context初始化完成后调用逻辑代码,其他的容器的初始化完成,则不做任何处理。
event.getApplicationContext().getParent() == null
3、@PostConstruct
/**
* Created by Administrator on 2017/6/15.
* spring容器启动后,初始化数据(产生一个默认商品、普通用户和管理员用户)
*/
@Component
public class InitMango{
@Autowired
private IProductService productService;
@Autowired
private IUserService userService;
@PostConstruct
public void init() {
//库中没有商品则声称一个
List<Product> products = productService.getProductList();
if (null == products || products.isEmpty()){
Product product = new Product();
product.setProductName("Mango");
product.setQuantity(100);
product.setUnit("个");
product.setUnitPrice(100);
productService.saveProduct(product);
}
//库中没有用户则添加普通用户和管理员用户
List<MangoUser> mangoUsers = userService.getUserList();
if(null == mangoUsers || mangoUsers.isEmpty()){
MangoUser mangoUser = new MangoUser();
mangoUser.setUserName("mango");
mangoUser.setPassword(StringUtil.md5("123456"));
mangoUser.setRole("ROLE_USER");
userService.saveUser(mangoUser);
MangoUser mangoUser1 = new MangoUser();
mangoUser1.setUserName("manager");
mangoUser1.setPassword(StringUtil.md5("123456"));
mangoUser1.setRole("ROLE_MANAGER");
userService.saveUser(mangoUser1);
}
}
}
下篇文章会分析其原理和源码实现。
三、代码托管
https://github.com/honghailiang/SpringMango
四、实现原理
其实现原理在【Spring实战】Spring注解工作原理源码解析中均能找到答案,简单说明下:
1)在bean创建的过程中,初始化时会先调用@PostConstruct注解标注的方法,而后调用实现InitializingBean接口的afterPropertiesSet方法
2)在finishRefresh()会分发事件,
// Publish the final event. publishEvent(new ContextRefreshedEvent(this));
关心ContextRefreshedEvent事件的bean中的onApplicationEvent方法会被调用
3)建议使用@PostConstruct注解,减少Spring的侵入性以及耦合性
【Spring实战】Spring容器初始化完成后执行初始化数据方法的更多相关文章
- spring bean容器加载后执行初始化处理@PostConstruct
先说业务场景,我在系统启动后想要维护一个List常驻内存,因为我可能经常需要查询它,但它很少更新,而且数据量不大,明显符合缓存的特质,但我又不像引入第三方缓存.现在的问题是,该List的内容是从数据库 ...
- spring初始化完成后执行初始化数据方法
Spring提供的解决方案三种: 1.InitializingBean package com.foriseland.fsoa.fabricca; import com.foriseland.fsoa ...
- 当spring 容器初始化完成后执行某个方法
在做web项目开发中,尤其是企业级应用开发的时候,往往会在工程启动的时候做许多的前置检查. 比如检查是否使用了我们组禁止使用的Mysql的group_concat函数,如果使用了项目就不能启动,并指出 ...
- 当springMVC 容器初始化完成后执行某个方法
分类: spring java2013-06-19 16:40 8289人阅读 评论(4) 收藏 举报 在某些应用中,我们希望,当spring 容器将所有的bean都初始化完成后,做一个操作(例如:将 ...
- 当spring 容器初始化完成后执行某个方法 防止onApplicationEvent方法被执行两次
在做web项目开发中,尤其是企业级应用开发的时候,往往会在工程启动的时候做许多的前置检查. 比如检查是否使用了我们组禁止使用的Mysql的group_concat函数,如果使用了项目就不能启动,并指出 ...
- angular指令监听ng-repeat渲染完成后执行自定义事件方法
今天工作中遇到需要用到ng-repeat遍历渲染完后执行某个操作,angular本身并没有提供监听ng-repeat渲染完成的指令,所以需要自己创建自定义指令. 在ng-repeat模板实例内部会暴露 ...
- spring boot 启动后执行初始化方法
http://blog.csdn.net/catoop/article/details/50501710 1.创建实现接口 CommandLineRunner 的类 package org.sprin ...
- spring web.xml配置服务启动后执行文件
<bean id="readXmlService" class="com.xxx.xxx.readXmlServiceImpl" init-method= ...
- React Native初始化项目后执行react-native run-ios,构建失败
今天是肿么了......一上班创建React Native项目,react-native run-ios运行就报错,运行不了...呜呜...... 一开始以为自己react-native run-io ...
随机推荐
- 20145314郑凯杰 《Java程序设计》第8周学习总结
20145314郑凯杰 <Java程序设计>第8周学习总结 教材学习内容总结 代码已托管 第十五章 通用API ①日志: 日志对信息安全意义重大,审计.取证.入侵检测等都会用到日志信息 使 ...
- 20145329 《Java程序设计》第九周学习总结
教材学习内容总结 十六章 1.Metadata即"诠读数据的数据",数据库是用来存储数据的地方,然而数据库本身产品名称为何?数据库中有几个数据表格?表格名称为何?表格中有几个字段等 ...
- 如何在repeater中找到checkbox并实现全选删除
checkbox使用客户端控件,且给repeater里边的checkbox添加ruanat=server属性表头中的chkTotal的属性一定不要加此属性....然后 全选的javascript代码 ...
- C语言一些总结
预处理#include<stdio.h>:头文件. stdio.h 标准输入输出. string.h 字符串预处理,. int main()主函数,返回的是int整型, return 0; ...
- Shell脚本 curl获取必应每日壁纸(Mac OS)
Mac上Safari不能下载壁纸,遇到好看的很想用作壁纸.写了一小段脚本用来拉取网页图片. curl: -sS 参数用来取消下载状态显示 grep 首先把含有图片网址的行提取了出来,针对这一行再做se ...
- 【乱码】Request QueryString 编码,传值乱码的几种情况和解决办法(单页,多页)
自己的项目还好,合作接口神马的传值乱码是很常见的. 遇到了几次这种恶心情况,积累了一点经验,有不对的地方欢迎指正. 乱码原因: 一般来说,常用的编码不是utf-8就是gb2312,一样的 HttpUt ...
- iOS 可变字符串NSMutableString的使用
.创建一个可变字符串 NSMutableString * ms1 = [[NSMutableString alloc]init]; .可以通过类方法来创建 NSMutableString * ms2 ...
- 缓存技术内部交流_03_Cache Aside
参考资料: http://www.ehcache.org/documentation/3.2/caching-patterns.html http://www.ehcache.org/document ...
- Floyd判圈算法 Floyd Cycle Detection Algorithm
2018-01-13 20:55:56 Floyd判圈算法(Floyd Cycle Detection Algorithm),又称龟兔赛跑算法(Tortoise and Hare Algorithm) ...
- UVALive - 6709树套树
题意:给你一个矩阵,q次操作,每次查询长宽l的矩阵最大值a和最小值b,然后把中间点换成floor((a+b)/2), 解法:暴力可过,建n颗线段树暴力更新,但是正解应该是树套树,树套树需要注意的是当建 ...