转载自:http://blog.youkuaiyun.com/dm_vincent/article/details/76735888
http://blog.youkuaiyun.com/dm_vincent/article/details/77151122
Spring Boot的启动始于:
然后设置初始化器,会从类路径的META-INF/spring.factories处读取相应配置文件,读取配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value。以spring-boot这个包为例,它的META-INF/spring.factories部分定义如下所示:
之后设置监听器,同上读取配置文件中Key为:org.springframework.context. ApplicationListener的value,然后加载实例化后,设置在listeners中。
然后设置mainApplicationClass:
完成了实例化,下面开始调用run方法:
上下文后置处理afterRefresh()方法:
基于上面的了解,我们就可以在Spring Boot启动添加自定义的初始化器、监听器等。
添加定制化的初始化器:
添加定制化的监听器:
添加定制化的后置Runners:
启动打印Banner:
扩展的方式也很简单,看源代码就清楚该怎么扩展了:
http://blog.youkuaiyun.com/dm_vincent/article/details/77151122
Spring Boot的启动始于:
SpringApplication.run(DemoApplication.class, args);
相应实现: public static ConfigurableApplicationContext run(Object source, String... args) {
return run(new Object[] { source }, args);
}
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
它实际上会构造一个SpringApplication的实例,然后运行它的run方法: public SpringApplication(Object... sources) {
initialize(sources);
}
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
deduceWebEnvironment()是推断应用类型是Standard还是Web,方法是在当类路径中找是否存在"javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext"的类来判断的。然后设置初始化器,会从类路径的META-INF/spring.factories处读取相应配置文件,读取配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value。以spring-boot这个包为例,它的META-INF/spring.factories部分定义如下所示:
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer
因此这几个类名会实例化出来放在SpringApplication 的initializers中。之后设置监听器,同上读取配置文件中Key为:org.springframework.context. ApplicationListener的value,然后加载实例化后,设置在listeners中。
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener
然后设置mainApplicationClass:
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
它通过构造一个运行时异常,通过异常栈中方法名为main的栈帧来得到入口类的名字。至此,对于SpringApplication实例的初始化过程就结束了。完成了实例化,下面开始调用run方法:
public ConfigurableApplicationContext run(String... args) {
// 计时工具
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
// 设置java.awt.headless系统属性为true - 没有图形化界面
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
// Banner打印器,就是启动Spring Boot的时候打印在console上的
Banner printedBanner = printBanner(environment);
// 创建Spring上下文
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
// Spring上下文前置处理
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
// Spring上下文后置处理
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
createApplicationContext()即创建Spring的主要组件ApplicationContext,对于Web应用,上ApplicationContext就是AnnotationConfigEmbeddedWebApplicationContext。refreshContext(context)即刷新ApplicationContext: private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
最终会调用到我们熟知的AbstractApplicationContext的refresh()方法。上下文后置处理afterRefresh()方法:
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
callRunners(context, args);
}
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<Object>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
所谓的后置操作,就是在容器完成刷新后,依次调用注册的Runners。Runners可以是两个接口的实现类:org.springframework.boot.ApplicationRunner与org.springframework.boot.CommandLineRunner。基于上面的了解,我们就可以在Spring Boot启动添加自定义的初始化器、监听器等。
添加定制化的初始化器:
public static void main(String[] args) {
// 创建SpringApplication的实例
SpringApplication app = new SpringApplication(Application.class);
// 添加定制的初始化器
app.addInitializers(new CustomApplicationContextInitializer());
// 执行SpringApplication实例的run方法
app.run(args);
}
public class CustomApplicationContextInitializer implements ApplicationContextInitializer {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomApplicationContextInitializer.class);
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
LOGGER.info("自定义的初始化器的initialize方法被执行了");
}
}
添加定制化的监听器:
app. addListeners(new CustomApplicationListener());
public class CustomApplicationListener implements ApplicationListener {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomApplicationListener.class);
public void onApplicationEvent(ApplicationEvent event) {
// 监听ApplicationStartingEvent
if (event instanceof ApplicationStartedEvent) {
logInfo("ApplicationStartedEvent listened");
}
// 监听ApplicationEnvironmentPreparedEvent
else if (event instanceof ApplicationEnvironmentPreparedEvent) {
logInfo("ApplicationEnvironmentPreparedEvent listened");
}
// 监听ApplicationPreparedEvent
else if (event instanceof ApplicationPreparedEvent) {
logInfo("ApplicationPreparedEvent listened");
}
// 监听ApplicationReadyEvent
else if (event instanceof ApplicationReadyEvent) {
logInfo("ApplicationReadyEvent listened");
}
// 监听ApplicationFailedEvent
else if (event instanceof ApplicationFailedEvent) {
logInfo("ApplicationFailedEvent listened");
}
}
private void logInfo(String log) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(log);
}
}
}
添加定制化的后置Runners:
@Component
@Order(2)
public class CustomApplicationRunner implements ApplicationRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomApplicationRunner.class);
@Override
public void run(ApplicationArguments arg) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("自定义ApplicationRunner运行了");
}
}
}
@Component
@Order(1)
public class CustomCommandLineRunner implements CommandLineRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomCommandLineRunner.class);
@Override
public void run(String... strings) throws Exception {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("自定义CommandLineRunner运行了");
}
}
}
自定义Runner的添加方式和上述的初始化器以及监听器有点不同,就是Runners直接通过@Component注解添加即可,借助于包扫描机制,它们会被注册到容器中。至于它们运行的顺序,则可以通过上述的@Order注解来完成标注,数值越小的Runner优先级越高,因为源码中有AnnotationAwareOrderComparator.sort(runners),因此上面代码中,CustomCommandLineRunner将先于CustomApplicationRunner被执行。启动打印Banner:
扩展的方式也很简单,看源代码就清楚该怎么扩展了:
private Banner printBanner(ConfigurableEnvironment environment) {
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader
: new DefaultResourceLoader(getClassLoader());
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
resourceLoader, this.banner);
if (this.bannerMode == Mode.LOG) {
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}