010-Spring Boot 扩展分析-ApplicationContextInitializer、CommandLineRunner、ApplicationRunner
一、常见的两个扩展点
1、ApplicationContextInitializer
1.1、作用实现
作用:接口实在Spring容器执行refresh之前的一个回调。
Callback interface for initializing a Spring {@link ConfigurableApplicationContext}
实现:
/* * Copyright 2002-2011 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.context; /** * Callback interface for initializing a Spring {@link ConfigurableApplicationContext} * prior to being {@linkplain ConfigurableApplicationContext#refresh() refreshed}. * * <p>Typically used within web applications that require some programmatic initialization * of the application context. For example, registering property sources or activating * profiles against the {@linkplain ConfigurableApplicationContext#getEnvironment() * context's environment}. See {@code ContextLoader} and {@code FrameworkServlet} support * for declaring a "contextInitializerClasses" context-param and init-param, respectively. * * <p>{@code ApplicationContextInitializer} processors are encouraged to detect * whether Spring's {@link org.springframework.core.Ordered Ordered} interface has been * implemented or if the @{@link org.springframework.core.annotation.Order Order} * annotation is present and to sort instances accordingly if so prior to invocation. * * @author Chris Beams * @since 3.1 * @see org.springframework.web.context.ContextLoader#customizeContext * @see org.springframework.web.context.ContextLoader#CONTEXT_INITIALIZER_CLASSES_PARAM * @see org.springframework.web.servlet.FrameworkServlet#setContextInitializerClasses * @see org.springframework.web.servlet.FrameworkServlet#applyInitializers */ public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> { /** * Initialize the given application context. * @param applicationContext the application to configure */ void initialize(C applicationContext); }
1.2、使用步骤
步骤一、写一个类,实现ApplicationContextInitializer接口
步骤二、注册ApplicationContextInitializer接口的实现
注册方式
方式一、SpringApplication
SpringApplication application = new SpringApplication(App.class); application.addInitializers(new MyApplicationContextInitializer());
方式二、配置文件
context.initializer.classes=com.lhx.spring.springboot_enableauto.MyApplicationContextInitializer
多个用逗号隔开
方式三、使用spring.factories配置机制,注册监听器
在需要注入的项目包中添加META-INF/spring.factories
org.springframework.context.ApplicationContextInitializer=类名
1.3、使用:
新建一个:MyApplicationContextInitializer
package com.lhx.spring.springboot_enableauto; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println("bean count:" + applicationContext.getBeanDefinitionCount()); // ConfigurableListableBeanFactory factory = // applicationContext.getBeanFactory(); } }
调用
package com.lhx.spring.springboot_enableauto; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; @SpringBootApplication public class App { public static void main(String[] args) { // ConfigurableApplicationContext context = SpringApplication.run(App.class, // args); SpringApplication application = new SpringApplication(App.class); application.addInitializers(new MyApplicationContextInitializer()); ConfigurableApplicationContext context = application.run(args); context.close(); } }
2、CommandLineRunner、ApplicationRunner【类似开机自启动】
2.1、作用于实现
作用:在spring容器全部初始化完毕,接口在容器启动成功后的最后一步回调
* Interface used to indicate that a bean should <em>run</em> when it is contained within
* a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined
* within the same application context and can be ordered using the {@link Ordered}
* interface or {@link Order @Order} annotation.
实现
/* * Copyright 2012-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.boot; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; /** * Interface used to indicate that a bean should <em>run</em> when it is contained within * a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined * within the same application context and can be ordered using the {@link Ordered} * interface or {@link Order @Order} annotation. * <p> * If you need access to {@link ApplicationArguments} instead of the raw String array * consider using {@link ApplicationRunner}. * * @author Dave Syer * @see ApplicationRunner */ public interface CommandLineRunner { /** * Callback used to run the bean. * @param args incoming main method arguments * @throws Exception on error */ void run(String... args) throws Exception; }
2.2、使用步骤
步骤一、写一个类实现CommandLineRunner接口
步骤二、把该类加入到Spring容器之中,可以通过@Order或Ordered接口控制顺序,注解越小越先执行
2.3、使用
新建一个类ServerSuccessReport实现接口CommandLineRunner
package com.lhx.spring.springboot_enableauto; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; @Component public class ServerSuccessReport implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("----CommandLineRunner执行-----"); } }
注意同类接口
ApplicationRunner,
void run(ApplicationArguments args)
只是参数不一样
CommandLineRunner是原始参数,没有任何处理
ApplicationRunner是ApplicationArguments 对象,是对原始参数进一步的封装
3.ApplicationArguments
是对参数(main方法)进一步重载
可以解析--name=value的,可以通过name获取value
package com.lhx.spring.springboot_enableauto; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication application = new SpringApplication(App.class); ConfigurableApplicationContext context = application.run(args); ApplicationArguments arguments = context.getBean(ApplicationArguments.class); System.out.println(arguments.getSourceArgs().length); System.out.println(arguments.getOptionNames()); System.out.println(arguments.getOptionValues("name")); context.close(); } }