【Spring实战】Spring容器初始化完成后执行初始化数据方法

来源:互联网 发布:数据库原理 编辑:程序博客网 时间:2024/06/06 05:54

一、背景知识及需求

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

[java] view plain copy

  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

直接上代码

[java] view plain copy
  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

[java] view plain copy
  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

[java] view plain copy
  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()会分发事件

[java] view plain copy
  1. // Publish the final event.  
  2.         publishEvent(new ContextRefreshedEvent(this));  
关心ContextRefreshedEvent事件的bean中的onApplicationEvent方法会被调用

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

参考:

Spring容器中的Bean几种初始化方法和销毁方法的先后顺序

http://blog.csdn.net/truelove12358/article/details/78490517


原创粉丝点击