美文网首页
【转载】Spring容器初始化完成后执行初始化数据方法

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

作者: dancer4code | 来源:发表于2019-10-05 15:47 被阅读0次

    本文转载自:https://blog.csdn.net/honghailiang888/article/details/73333821

    一、背景知识及需求

    在做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的侵入性以及耦合性

    本文转载自:https://blog.csdn.net/honghailiang888/article/details/73333821

    spring请参考
    Spring容器初始化完成后执行初始化数据方法

    spring boot请参考
    Spring boot 启动之后,执行某些初始化的几种方法

    Spring Boot学习--项目启动时执行特定方法

    springboot项目启动后,自动执行需要的初始化操作

    相关文章

      网友评论

          本文标题:【转载】Spring容器初始化完成后执行初始化数据方法

          本文链接:https://www.haomeiwen.com/subject/xhtypctx.html