在日常开发中难免会经常遇到这样的应用场景,在项目初始化时执行指定的代码实现一些功能,或者在项目启动后执行一些代码实现功能。这个时候就需要用到Spring提供的一些接口、注解了。本文都是以SpringBoot为基础。
直接在代码中实现该接口afterPropertiesSet方法,并在该方法中执行代码。
值得注意的是 在该接口执行时Spring 容器是还没有初始化完成的。在这里取spring容器中的对象可能会被抛出空指针异常。
@Component
public class TestConfigInitializingBean implements InitializingBean {
private static final Logger LOGGER = LoggerFactory.getLogger(TestConfigInitializingBean.class);
@Override
public void afterPropertiesSet() throws Exception {
LOGGER.info("--------------------------------------------");
LOGGER.info("-----正在执行InitializingBean实现类代码-----");
LOGGER.info("--------------------------------------------");
}
}
这种方式相对于InitializingBean接口实现要方便一些。直接在需要的方法上添加该注解即可。
这种方式与上面InitializingBean接口一样都是在spring容器初始化前执行,所有在该注解方法中获取容器内对象可能存在空指针异常
@Component
public class TestPostConstruct {
private static final Logger LOGGER = LoggerFactory.getLogger(TestPostConstruct.class);
@PostConstruct
public void initPostConstruct() {
LOGGER.info("--------------------------------------------");
LOGGER.info("-----正在执行@PostConstruct实现类代码-----");
LOGGER.info("--------------------------------------------");
}
}
关于这个接口,很多人可能会遇到多次执行该方法。其实这是正常现象,我在执行这段代码时,被重复调用了3次
通过debug调试观察发现,3次执行参数ApplicationEvent event都是不同的。
第一次参数内source是AnnotationConfigEmbeddedWebApplicationContext
第二次参数内source是TomcatEmbeddedServletContainer
第三次参数内source是SpringApplication
我个人的理解为springboot web容器加载时触发该方法一次,springboot自带tomcat容器初始化时触发容器一次
第三次是springApplication 创建并初始化Spring上下文时再次触发该监听
直接上代码
@Component
public class TestConfigApplicationListener implements ApplicationListener {
private static final Logger LOGGER = LoggerFactory.getLogger(TestConfigApplicationListener.class);
@Override
public void onApplicationEvent(ApplicationEvent event) {
LOGGER.info("--------------------------------------------");
LOGGER.info("-----正在执行ApplicationListener实现类代码-----");
LOGGER.info("--------------------------------------------");
}
}
补充: ApplicationEvent该类是一个监听事件抽象类,它下面有很多子类。分别实现不同的事件监听。该监听器的具体执行时间可根据不同的监听类型对象(ApplicationEvent子类)在不同的时间执行 项目启动前、启动后等,具体每个类的监听后面的文章在分析。
原理:ApplicationContextAware接口提供了publishEvent方法,实现了Observe(观察者)设计模式的传播机制,实现了对bean的传播。通过ApplicationContextAware把系统中所有ApplicationEvent传播给所有的ApplicationListener。
在代码中实现接口的run方法,并在run方法中编写逻辑代码
该方法可以通过@order(value= 数字) 来控制执行顺序,顺序是依次从小到大执行
@Component
@Order(value = 3)
public class TestConfigApplicationRunner implements ApplicationRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(TestConfigApplicationRunner.class);
@Override
public void run(ApplicationArguments args) throws Exception {
LOGGER.info("--------------------------------------------");
LOGGER.info("-----正在执行ApplicationRunner实现类代码-----");
LOGGER.info("--------------------------------------------");
}
}
CommandLineRunner接口的使用方式与ApplicationRunner接口基本相似,不同的只是方法的参数类型,CommandLineRunner的参数是基本类型,而ApplicationRunner是的参数是ApplicationArguments对象,经过封装,用户可对参数进行更多操作
@Component
@Order(value = 2)
public class TestConfigCommandLineRunner implements CommandLineRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(TestConfigCommandLineRunner.class);
@Override
public void run(String... args) throws Exception {
LOGGER.info("--------------------------------------------");
LOGGER.info("-----正在执行CommandLineRunner实现类代码-----");
LOGGER.info("--------------------------------------------");
}
}
代码最终执行结果日志:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.10.RELEASE)
2018-09-05 12:20:08.212 INFO 7140 --- [ main] com.port.test.PortTestApp : Starting PortTestApp on DESKTOP-R7GPPNQ with PID 7140 (E:\workSpace\learn-project\port-test\target\classes started by zane in E:\workSpace\learn-project\port-test)
2018-09-05 12:20:08.214 INFO 7140 --- [ main] com.port.test.PortTestApp : No active profile set, falling back to default profiles: default
2018-09-05 12:20:08.255 INFO 7140 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@140e5a13: startup date [Wed Sep 05 12:20:08 CST 2018]; root of context hierarchy
2018-09-05 12:20:09.431 INFO 7140 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2018-09-05 12:20:09.443 INFO 7140 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2018-09-05 12:20:09.445 INFO 7140 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.27
2018-09-05 12:20:09.554 INFO 7140 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2018-09-05 12:20:09.554 INFO 7140 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1301 ms
2018-09-05 12:20:09.681 INFO 7140 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2018-09-05 12:20:09.684 INFO 7140 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-09-05 12:20:09.685 INFO 7140 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-09-05 12:20:09.685 INFO 7140 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2018-09-05 12:20:09.685 INFO 7140 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2018-09-05 12:20:09.733 INFO 7140 --- [ main] c.p.t.config.TestConfigInitializingBean : --------------------------------------------
2018-09-05 12:20:09.733 INFO 7140 --- [ main] c.p.t.config.TestConfigInitializingBean : -----正在执行InitializingBean实现类代码-----
2018-09-05 12:20:09.733 INFO 7140 --- [ main] c.p.t.config.TestConfigInitializingBean : --------------------------------------------
2018-09-05 12:20:09.736 INFO 7140 --- [ main] com.port.test.config.TestPostConstruct : --------------------------------------------
2018-09-05 12:20:09.736 INFO 7140 --- [ main] com.port.test.config.TestPostConstruct : -----正在执行@PostConstruct实现类代码-----
2018-09-05 12:20:09.736 INFO 7140 --- [ main] com.port.test.config.TestPostConstruct : --------------------------------------------
2018-09-05 12:20:09.969 INFO 7140 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@140e5a13: startup date [Wed Sep 05 12:20:08 CST 2018]; root of context hierarchy
2018-09-05 12:20:10.038 INFO 7140 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-09-05 12:20:10.039 INFO 7140 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-09-05 12:20:10.066 INFO 7140 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-09-05 12:20:10.066 INFO 7140 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-09-05 12:20:10.098 INFO 7140 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-09-05 12:20:10.220 INFO 7140 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-09-05 12:20:10.229 INFO 7140 --- [ main] c.p.t.c.TestConfigApplicationListener : --------------------------------------------
2018-09-05 12:20:10.230 INFO 7140 --- [ main] c.p.t.c.TestConfigApplicationListener : -----正在执行ApplicationListener实现类代码-----
2018-09-05 12:20:10.230 INFO 7140 --- [ main] c.p.t.c.TestConfigApplicationListener : --------------------------------------------
2018-09-05 12:20:10.290 INFO 7140 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2018-09-05 12:20:10.291 INFO 7140 --- [ main] c.p.t.c.TestConfigApplicationListener : --------------------------------------------
2018-09-05 12:20:10.291 INFO 7140 --- [ main] c.p.t.c.TestConfigApplicationListener : -----正在执行ApplicationListener实现类代码-----
2018-09-05 12:20:10.291 INFO 7140 --- [ main] c.p.t.c.TestConfigApplicationListener : --------------------------------------------
2018-09-05 12:20:10.293 INFO 7140 --- [ main] c.p.t.c.TestConfigCommandLineRunner : --------------------------------------------
2018-09-05 12:20:10.293 INFO 7140 --- [ main] c.p.t.c.TestConfigCommandLineRunner : -----正在执行CommandLineRunner实现类代码-----
2018-09-05 12:20:10.293 INFO 7140 --- [ main] c.p.t.c.TestConfigCommandLineRunner : --------------------------------------------
2018-09-05 12:20:10.293 INFO 7140 --- [ main] c.p.t.c.TestConfigApplicationRunner : --------------------------------------------
2018-09-05 12:20:10.293 INFO 7140 --- [ main] c.p.t.c.TestConfigApplicationRunner : -----正在执行ApplicationRunner实现类代码-----
2018-09-05 12:20:10.293 INFO 7140 --- [ main] c.p.t.c.TestConfigApplicationRunner : --------------------------------------------
2018-09-05 12:20:10.294 INFO 7140 --- [ main] c.p.t.c.TestConfigApplicationListener : --------------------------------------------
2018-09-05 12:20:10.294 INFO 7140 --- [ main] c.p.t.c.TestConfigApplicationListener : -----正在执行ApplicationListener实现类代码-----
2018-09-05 12:20:10.294 INFO 7140 --- [ main] c.p.t.c.TestConfigApplicationListener : --------------------------------------------
2018-09-05 12:20:10.295 INFO 7140 --- [ main] com.port.test.PortTestApp : Started PortTestApp in 2.328 seconds (JVM running for 2.652)