详解Spring Boot中初始化资源的几种方式
假设有这么一个需求,要求在项目启动过程中,完成线程池的初始化,加密证书加载等功能,你会怎么做?如果没想好答案,请接着往下看。今天介绍几种在SpringBoot中进行资源初始化的方式,帮助大家解决和回答这个问题。
CommandLineRunner
- 定义初始化类MyCommandLineRunner
- 实现CommandLineRunner接口,并实现它的run()方法,在该方法中编写初始化逻辑
- 注册成Bean,添加@Component注解即可
示例代码如下:
@Component publicclassMyCommandLineRunnerimplementsCommandLineRunner{ @Override publicvoidrun(String...args)throwsException{ System.out.println("...initresourcesbyimplementsCommandLineRunner"); } }
实现了CommandLineRunner接口的Component会在所有SpringBeans初始化完成之后,在SpringApplication.run()执行之前完成。下面通过加两行打印来验证我们的测试。
@SpringBootApplication publicclassDemoApplication{ publicstaticvoidmain(String[]args){ System.out.println("...startSpringApplication.run()"); SpringApplication.run(DemoApplication.class,args); System.out.println("...endSpringApplication.run()"); } }
控制台打印结果如下。
...startSpringApplication.run()
. ____ _ ____
/\\/___'_____(_)___ ___\\\\
(()\___|'_|'_||'_\/_`|\\\\
\\/ ___)||_)|||||||(_|| ))))
' |____|.__|_||_|_||_\__,|////
=========|_|==============|___/=/_/_/_/
::SpringBoot:: (v1.5.11.RELEASE)
。。。。。。(此处省略一堆打印信息)
2018-05-0217:01:19.700 INFO21236---[ main]s.b.c.e.t.TomcatEmbeddedServletContainer:Tomcatstartedonport(s):8080(http)
...initresourcesbyimplementsCommandLineRunner
2018-05-0217:01:19.708 INFO21236---[ main]cn.mariojd.demo.DemoApplication :StartedDemoApplicationin2.282seconds(JVMrunningfor3.125)
...endSpringApplication.run()
ApplicationRunner
- 定义初始化类MyApplicationRunner
- 实现ApplicationRunner接口,并实现它的run()方法,在该方法中编写初始化逻辑
- 注册成Bean,添加@Component注解即可
示例代码如下:
@Component publicclassMyApplicationRunnerimplementsApplicationRunner{ @Override publicvoidrun(ApplicationArgumentsapplicationArguments)throwsException{ System.out.println("...initresourcesbyimplementsApplicationRunner"); } }
可以看到,通过实现ApplicationRunner接口,和通过实现CommandLineRunner接口都可以完成项目的初始化操作,实现相同的效果。两者之间唯一的区别是run()方法中自带的形参不相同,在CommandLineRunner中只是简单的String...args形参,而ApplicationRunner则是包含了ApplicationArguments对象,可以帮助获得更丰富的项目信息。
ApplicationArguments
@Order
如果项目中既有实现了ApplicationRunner接口的初始化类,又有实现了CommandLineRunner接口的初始化类,那么会是哪一个先执行呢?测试告诉我们,答案是实现了ApplicationRunner接口的初始化类先执行,我想这点倒是不需要大家过分去关注为什么。但如果需要改变两个初始化类之间的默认执行顺序,那么使用@Order注解就可以帮助我们解决这个问题。
@Order @Component @Order(1) publicclassMyCommandLineRunnerimplementsCommandLineRunner{ @Override publicvoidrun(String...args)throwsException{ System.out.println("...initresourcesbyimplementsCommandLineRunner"); } }
@Component @Order(2) publicclassMyApplicationRunnerimplementsApplicationRunner{ @Override publicvoidrun(ApplicationArgumentsapplicationArguments)throwsException{ System.out.println("...initresourcesbyimplementsApplicationRunner"); } }
最终,控制台中打印如下。通过控制台输出我们发现,@Order注解值越小,该初始化类也就越早执行。
。。。。。。(此处省略一堆打印信息)
2018-05-0217:27:31.450 INFO28304---[ main]s.b.c.e.t.TomcatEmbeddedServletContainer:Tomcatstartedonport(s):8080(http)
...initresourcesbyimplementsCommandLineRunner
...initresourcesbyimplementsApplicationRunner
2018-05-0217:27:31.453 INFO28304---[ main]cn.mariojd.demo.DemoApplication :StartedDemoApplicationin2.086seconds(JVMrunningfor2.977)
@PostConstruct
使用@PostConstruct注解同样可以帮助我们完成资源的初始化操作,前提是这些初始化操作不需要依赖于其它Springbeans的初始化工作。
@PostConstruct
可以看到@PostConstruct注解是用在方法上的,写一个方法测试一下吧。
@PostConstruct publicvoidpostConstruct(){ System.out.println("...PostConstruct"); }
启动项目,控制台中最终打印如下。
...startSpringApplication.run()
. ____ _ ____
/\\/___'_____(_)___ ___\\\\
(()\___|'_|'_||'_\/_`|\\\\
\\/ ___)||_)|||||||(_|| ))))
' |____|.__|_||_|_||_\__,|////
=========|_|==============|___/=/_/_/_/
::SpringBoot:: (v1.5.11.RELEASE)
。。。。。。(此处省略一堆打印信息)
...PostConstruct
。。。。。。(此处省略一堆打印信息)
2018-05-0217:40:22.300 INFO29796---[ main]s.b.c.e.t.TomcatEmbeddedServletContainer:Tomcatstartedonport(s):8080(http)
...initresourcesbyimplementsCommandLineRunner
...initresourcesbyimplementsApplicationRunner
2018-05-0217:40:22.303 INFO29796---[ main]cn.mariojd.demo.DemoApplication :StartedDemoApplicationin2.387seconds(JVMrunningfor3.267)
...endSpringApplication.run()
文末小结
综上,使用@PostConstruct注解进行初始化操作的顺序是最快的,前提是这些操作不能依赖于其它Bean的初始化完成。通过添加@Order注解,我们可以改变同层级之间不同Bean的加载顺序。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。