Springboot工作原理:
工作原理包含很多:ioc,自动配置,启动过程,监听,注解,扩展点,SpringFactoriesLoader工厂加载机制
注解:
点击@SpringBootApplication注解后我们可以发现这是个复合注解,可以发现
@SpringbootApplication=@Configuration+@EnableAutoConfiguration+@ComponentScan这三个注解。
@Configuration:用于定义配置类,可替换XML配置文件,被注解的类内部包含一个或多个 @Bean注解方法。可以被AnnotationConfigApplicationContext或者 AnnotationConfigWebApplicationContext进行扫描。用于构建bean定义以及初始化Spring 容器。
(https://www.jianshu.com/p/21f3e074e91a)
@EnableAutoConfiguration:Springboot自动配置的实现就是通过这个注解实现的。借助 @Import的帮助,将所有符合自动配置条件的bean定义加载到ioc容器中。从classpath 中搜寻所有的META-INF/spring.factories配置文件,并将其中 org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射 (java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的ioc容器配 置类,然后汇总为一个并加载到ioc容器。
(https://blog.csdn.net/kmhysoft/article/details/71056027)
@ComponentScan:创建一个配置类,在配置类上添加@ComponentScan注解,该注解默认 会扫描该类所在的包下所有的配置类,相当于之前的<context:component-scan>。
(https://www.jianshu.com/p/64aac6461d5b)
启动过程:
当我们启动springboot中的主方法main时,会经历如下过程:
首先创建SpringApplication实例(执行SpringApplication构造方法):
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//1.构造方法中的逻辑:
this.resourceLoader = resourceLoader;
//2.一定要指定primarySources,也就是我们的主方法所在的类
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//3.deduce(推断)web类型(Servlet,Reactive,NoWeb)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//4.从META-INF/spring.factories中获取ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//5.从META-INF/spring.factories中获取ApplicationListrnre
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//6.推断执行的main方法的定义类
this.mainApplicationClass = deduceMainApplicationClass();
}
ApplicationContextInitializer是Spring提供的用于应用启动时回调的接口,需要实现此接口的initializeinitialize(ConfigurableApplicationContext applicationContext)方法。当Spring启动(即执行run方法)并初始化环境配置以后,完成应用初始化以前,会回调所有ApplicationContextInitializer的子类(当然是已经配置了的子类)。
当实例初始化完后则就开始执行启动方法(Run)了:
public ConfigurableApplicationContext run(String... args) {
//1.StopWatch开启计时
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//这是设置系统属性java.awt.headles(通知系统进入配置模式)
configureHeadlessProperty();
//2.获取到META-INF/spring.factories中配置的SpringApplicationRunListener
//这个监听器是监听这个run方法的
//可通过它的接口定义,注解了解它的用途
SpringApplicationRunListeners listeners = getRunListeners(args);
//启动监听器
listeners.starting();
try {
//命令行参数包装为ApplicationArguments
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//3.准备好了Environment(环境),此刻Environment中都有哪些配置参数呢?
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
//4.打印springboot LoGo图表
Banner printedBanner = printBanner(environment);
//5.创建ApplicationContext
context = createApplicationContext();
//6.获取到META-ING/spring.factories中配置的SpringBootExceptionReporter
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//7.准备ApplicationContext
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//8.刷新ApplicationContext
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//9.发布started事件
listeners.started(context);
//10.执行所有的Runners
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//11.发布running中事件
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
//12.返回ok的ConfigurableApplicationContext
return context;
}
到此,算是完成了。
环境准备过程,上面的第3步:
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment 》》创建和配置环境
//根据应用类型,创建对应的Environment(环境)对象,会装载环境变量,系统参数,具
//体应用类型配置参数
ConfigurableEnvironment environment = getOrCreateEnvironment();
//配置环境:加入命令行参数PropertySource,配置启用的profiles
configureEnvironment(environment, applicationArguments.getSourceArgs());
//触发RunListener环境准备完成回调
listeners.environmentPrepared(environment);
//将Environment绑定到SpringApplication
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
创建ApplicationContext即ConfigurableApplicationContext创建与准备过程:
创建过程,上面的第5步:
protected ConfigurableApplicationContext createApplicationContext() {
//逻辑:如果没有变成式指定contextClass,则根据之前推断的webApplicationType来选择对//应默认的ApplicationContext实现类
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
上面Class.forName里的三个参数如下:
准备过程,上面的第7步:
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//1.设置环境对象
context.setEnvironment(environment);
//2.设置ApplicationContext的beanNameGenerator,resourceLoader,addConversionService(如果通过SpringApplication编程方式指定了他们)
postProcessApplicationContext(context);
//3.应用初始化器对ApplicationContext进行初始化处理(Initializers在构造SpringApplication时就从spring.factories中加载到了)
applyInitializers(context);
//4.发布ApplicationContext准备妥当事件
listeners.contextPrepared(context);
//5.打印startup日志信息
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
//6.添加springboot中特定的单例bean到beanfactory中
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//7.加载PrimarySource其他编程式指定的source配置类中的bean定义
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
//8.发布ApplicationContext加载Bean定义完毕事件
listeners.contextLoaded(context);
}
刷新过程,run方法中的第8步:
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
/**
* Refresh the underlying(刷新底层) {@link ApplicationContext}.
* @param applicationContext the application context to refresh(应用程序上下文刷新)
*/
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
会加载自动配置的配置类,上文run方法的第10步:
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
try {
(runner).run(args);
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
}
}
private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
try {
(runner).run(args.getSourceArgs());
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
}
}
从代码中可以看出,从ApplicationContext获取了所有ApplicationRunner,CommandLineRunner类型的bean,并执行了他们的run方法。
ApplicationRunner和CommandLineRunner是一样的用途,当ApplicationContext刷新好后,用来执行我们的应用逻辑。
比如:
@SpringBootApplication
public class SpringBootStudyConfigApplication implements ApplicationRunner {
public static void main(String[] args) {
SpringApplication.run(SpringBootStudyConfigApplication.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("***************** " + mybean);
}
}
除此之外我们还可以用如下方式来执行我们的逻辑:
@SpringBootApplication
public class SpringBootStudyConfigApplication implements ApplicationRunner {
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(SpringBootStudyConfigApplication.class, args);
MyBean mybean = context.getBean(MyBean.class);
mybean.doService();
}
}
待完善,望多提意见。