1,pom引用
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> </parent>
<!--web应用--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
2,在src/main/java 下创建一个Application.java 文件
@RestController @SpringBootApplication public class Application { @RequestMapping("/") String hello() { return "Hello World!"; } public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
3,启动java文件,运行示例
可以看到springboot启动默认使用端口8080
4,修改端口号
在src/resources 下新建application.properties 文件
写入:
server.port=8081
启动后端口号则更改为8081
5,运行结果
6,启动原理
SpringBoot整个启动流程分为两个步骤:初始化一个SpringApplication对象、执行该对象的run方法
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) { this.sources = new LinkedHashSet(); this.bannerMode = Mode.CONSOLE; this.logStartupInfo = true; this.addCommandLineProperties = true; this.addConversionService = true; this.headless = true; this.registerShutdownHook = true; this.additionalProfiles = new HashSet(); this.isCustomEnvironment = false; this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = this.deduceMainApplicationClass(); }
-
ApplicationContextInitializer的主要目的是在ConfigurableApplicationContext做refresh之前,对ConfigurableApplicationContext实例做进一步的设置或处理。
-
ApplicationListener它是Spring框架对Java事件监听机制的一种框架实现
Spring Boot应用的整个启动流程都封装在SpringApplication.run方法中
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); //1.通过SpringFactoriesLoader查找并加载所有的SpringApplicationRunListeners,通过调用 //starting()方法通知所有的SpringApplicationRunListeners:应用开始启动了 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { //2.创建并配置当前应用将要使用的Environment ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); //3.打印banner Banner printedBanner = printBanner(environment); //4.根据是否是web项目,来创建不同的ApplicationContext容器 context = createApplicationContext(); //5.创建一系列FailureAnalyzer exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); //6.初始化ApplicationContext prepareContext(context, environment, listeners, applicationArguments, printedBanner); //7.调用ApplicationContext的refresh()方法,刷新容器 refreshContext(context); //8.查找当前context中是否注册有CommandLineRunner和ApplicationRunner,如果有则遍历执行它们。 afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, listeners, exceptionReporters, ex); throw new IllegalStateException(ex); } listeners.running(context); return context; }
1.通过SpringFactoriesLoader查找并加载所有的SpringApplicationRunListeners,通过调用starting()方法通知所有的SpringApplicationRunListeners:应用开始启动了。(SpringApplicationRunListeners其本质上就是一个事件发布者,它在SpringBoot应用启动的不同时间点发布不同应用事件类型(ApplicationEvent),如果有哪些事件监听者(ApplicationListener)对这些事件感兴趣,则可以接收并且处理)
public interface SpringApplicationRunListener {
// 运行run方法时立即调用此方法,可以用户非常早期的初始化工作
void starting();
// Environment准备好后,并且ApplicationContext创建之前调用
void environmentPrepared(ConfigurableEnvironment environment);
// ApplicationContext创建好后立即调用
void contextPrepared(ConfigurableApplicationContext context);
// ApplicationContext加载完成,在refresh之前调用
void contextLoaded(ConfigurableApplicationContext context);
// 当run方法结束之前调用
void finished(ConfigurableApplicationContext context, Throwable exception);
}
SpringApplicationRunListener只有一个实现类:EventPublishingRunListener。①处的代码只会获取到一个EventPublishingRunListener的实例,我们来看看starting()方法的内容:
public void starting() {
// 发布一个ApplicationStartedEvent
this.initialMulticaster.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
}
2.创建并配置当前应用将要使用的Environment,Environment用于描述应用程序当前的运行环境,其抽象了两个方面的内容:配置文件(profile)和属性(properties),不同的环境(eg:生产环境、预发布环境)可以使用不同的配置文件,而属性则可以从配置文件、环境变量、命令行参数等来源获取。因此,当Environment准备好后,在整个应用的任何时候,都可以从Environment中获取资源。
判断Environment是否存在,不存在就创建(如果是web项目就创建StandardServletEnvironment,否则创建StandardEnvironment)
配置Environment:配置profile以及properties
调用SpringApplicationRunListener的environmentPrepared()方法,通知事件监听者:应用的Environment已经准备好
3.打印banner(可以自定义)
4.根据是否是web项目,来创建不同的ApplicationContext容器
5.创建一系列FailureAnalyzer,创建流程依然是通过SpringFactoriesLoader获取到所有实现FailureAnalyzer接口的class,然后在创建对应的实例。FailureAnalyzer用于分析故障并提供相关诊断信息。
6.初始化ApplicationContext
-
将准备好的Environment设置给ApplicationContext
-
遍历调用所有的ApplicationContextInitializer的initialize()方法来对已经创建好的ApplicationContext进行进一步的处理
-
调用SpringApplicationRunListener的contextPrepared()方法,通知所有的监听者:ApplicationContext已经准备完毕
-
将所有的bean加载到容器中
-
调用SpringApplicationRunListener的contextLoaded()方法,通知所有的监听者:ApplicationContext已经装载完毕
7.调用ApplicationContext的refresh()方法,刷新容器
-
这里的刷新和spring中刷新原理类似,这里重点关注invokeBeanFactoryPostProcessors(beanFactory);方法,主要完成获取到所有的BeanFactoryPostProcessor来对容器做一些额外的操作,通过源可以进入到PostProcessorRegistrationDelegate类
的invokeBeanFactoryPostProcessors()方法,会获取类型为BeanDefinitionRegistryPostProcessor的beanorg.springframework.context.annotation.internalConfigurationAnnotationProcessor,对应的Class为ConfigurationClassPostProcessor。ConfigurationClassPostProcessor用于解析处理各种注解,包括:@Configuration、@ComponentScan、@Import、@PropertySource、@ImportResource、@Bean。当处理@import注解的时候,就会调用<自动配置>这一小节中的EnableAutoConfigurationImportSelector.selectImports()来完成自动配置功能
8.查找当前context中是否注册有CommandLineRunner和ApplicationRunner,如果有则遍历执行它们。