Spring容器初始化完成后执行初始化数据方法

 

2017年06月16日 16:43:17

阅读数:13457

一、背景知识及需求

在做WEB项目时,经常在项目第一次启动时利用WEB容器的监听、Servlet加载初始化等切入点为数据库准备数据,这些初始化数据是系统开始运行前必须的数据,例如权限组、系统选项、默认管理员等等。而项目采用了Spring依赖注入来管理对象,而servlet并不受Spring的管理。若此时在servlet中注入Spring管理的对象,则无法使用,如下:

 
  1. public class InitServlet extends HttpServlet {

  2.  
  3. @Autowired

  4. private IProductService productService;

  5. @Autowired

  6. private IUserService userService;

  7. ......

  8. }

这个时候是无法使用上述中的两个service的,因为InitServlet不受Spring容器管理。虽然可以用getBean的方式手动获取service,但是违反了使用Spring的初衷。

 

该篇文章也在之前【Spring实战】系列的基础上进行优化和深入分析,本篇就是在更换了hsqldb数据库并初始化了商品、普通用户和管理员用户需求时产生的。

 

二、Spring提供的解决方案

1、InitializingBean

直接上代码

 
  1. /**

  2. * Created by Administrator on 2017/6/15.

  3. * spring容器启动后,初始化数据(产生一个默认商品、普通用户和管理员用户)

  4. */

  5. @Component

  6. public class InitServlet implements InitializingBean {

  7.  
  8. @Autowired

  9. private IProductService productService;

  10. @Autowired

  11. private IUserService userService;

  12.  
  13. @Override

  14. public void afterPropertiesSet() throws Exception {

  15. //库中没有商品则声称一个

  16. List<Product> products = productService.getProductList();

  17. if (null == products || products.isEmpty()){

  18. Product product = new Product();

  19. product.setProductName("Mango");

  20. product.setQuantity(100);

  21. product.setUnit("个");

  22. product.setUnitPrice(100);

  23. productService.saveProduct(product);

  24. }

  25.  
  26. //库中没有用户则添加普通用户和管理员用户

  27. List<MangoUser> mangoUsers = userService.getUserList();

  28. if(null == mangoUsers || mangoUsers.isEmpty()){

  29. MangoUser mangoUser = new MangoUser();

  30. mangoUser.setUserName("mango");

  31. mangoUser.setPassword(StringUtil.md5("123456"));

  32. mangoUser.setRole("ROLE_USER");

  33. userService.saveUser(mangoUser);

  34.  
  35. MangoUser mangoUser1 = new MangoUser();

  36. mangoUser1.setUserName("manager");

  37. mangoUser1.setPassword(StringUtil.md5("123456"));

  38. mangoUser1.setRole("ROLE_MANAGER");

  39. userService.saveUser(mangoUser1);

  40. }

  41. }

  42.  
  43. }

若采用XML来配置Bean的话,可以指定属性init-method。

 

2、ApplicationListener

 
  1. //交给Spring管理,如果不是自动扫描加载bean的方式,则在xml里配一个即可

  2. @Component

  3. public class InitData implements ApplicationListener<ContextRefreshedEvent> {

  4.  
  5. @Autowired

  6. private IProductService productService;

  7. @Autowired

  8. private IUserService userService;

  9.  
  10. @Override

  11. public void onApplicationEvent(ContextRefreshedEvent event) {

  12. if (event.getApplicationContext().getParent() == null) {

  13. //库中没有商品则声称一个

  14. List<Product> products = productService.getProductList();

  15. if (null == products || products.isEmpty()){

  16. Product product = new Product();

  17. product.setProductName("Mango");

  18. product.setQuantity(100);

  19. product.setUnit("个");

  20. product.setUnitPrice(100);

  21. productService.saveProduct(product);

  22. }

  23.  
  24. //库中没有用户则添加普通用户和管理员用户

  25. List<MangoUser> mangoUsers = userService.getUserList();

  26. if(null == mangoUsers || mangoUsers.isEmpty()){

  27. MangoUser mangoUser = new MangoUser();

  28. mangoUser.setUserName("mango");

  29. mangoUser.setPassword(StringUtil.md5("123456"));

  30. mangoUser.setRole("ROLE_USER");

  31. userService.saveUser(mangoUser);

  32.  
  33. MangoUser mangoUser1 = new MangoUser();

  34. mangoUser1.setUserName("manager");

  35. mangoUser1.setPassword(StringUtil.md5("123456"));

  36. mangoUser1.setRole("ROLE_MANAGER");

  37. userService.saveUser(mangoUser1);

  38. }

  39. }

  40.  
  41. }

  42. }

注意是监听的ContextRefreshedEvent事件。

在web 项目中(spring mvc),系统会存在两个容器,一个是root application context ,另一个就是我们自己的 projectName-servlet context(作为root application context的子容器)。这种情况下,就会造成onApplicationEvent方法被执行两次。为了避免上面提到的问题,我们可以只在root application context初始化完成后调用逻辑代码,其他的容器的初始化完成,则不做任何处理。

event.getApplicationContext().getParent() == null

 

3、@PostConstruct

 
  1. /**

  2. * Created by Administrator on 2017/6/15.

  3. * spring容器启动后,初始化数据(产生一个默认商品、普通用户和管理员用户)

  4. */

  5. @Component

  6. public class InitMango{

  7.  
  8. @Autowired

  9. private IProductService productService;

  10. @Autowired

  11. private IUserService userService;

  12.  
  13. @PostConstruct

  14. public void init() {

  15. //库中没有商品则声称一个

  16. List<Product> products = productService.getProductList();

  17. if (null == products || products.isEmpty()){

  18. Product product = new Product();

  19. product.setProductName("Mango");

  20. product.setQuantity(100);

  21. product.setUnit("个");

  22. product.setUnitPrice(100);

  23. productService.saveProduct(product);

  24. }

  25.  
  26. //库中没有用户则添加普通用户和管理员用户

  27. List<MangoUser> mangoUsers = userService.getUserList();

  28. if(null == mangoUsers || mangoUsers.isEmpty()){

  29. MangoUser mangoUser = new MangoUser();

  30. mangoUser.setUserName("mango");

  31. mangoUser.setPassword(StringUtil.md5("123456"));

  32. mangoUser.setRole("ROLE_USER");

  33. userService.saveUser(mangoUser);

  34.  
  35. MangoUser mangoUser1 = new MangoUser();

  36. mangoUser1.setUserName("manager");

  37. mangoUser1.setPassword(StringUtil.md5("123456"));

  38. mangoUser1.setRole("ROLE_MANAGER");

  39. userService.saveUser(mangoUser1);

  40. }

  41. }

  42.  
  43. }

 

 

下篇文章会分析其原理和源码实现。

 

三、代码托管

https://github.com/honghailiang/SpringMango

 

 

四、实现原理

其实现原理在【Spring实战】Spring注解工作原理源码解析中均能找到答案,简单说明下:

1)在bean创建的过程中,初始化时会先调用@PostConstruct注解标注的方法,而后调用实现InitializingBean接口的afterPropertiesSet方法

2)在finishRefresh()会分发事件,

 

 
  1. // Publish the final event.

  2. publishEvent(new ContextRefreshedEvent(this));

关心ContextRefreshedEvent事件的bean中的onApplicationEvent方法会被调用

3)建议使用@PostConstruct注解,减少Spring的侵入性以及耦合性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值