1. 开门见山
首先创建一个Application类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application .class, args);
}
}
第一步就看到一个注解@SpringBootApplication,启动SpringBoot项目的必备。
我们打开这个注解类,可以看到里面还包含3个比较特殊的注解
@SpringBootConfiguration其实是一个@Configuration,@Configuration生命可以把额外的bean或者导入的注册到spring容器的上下文,就相当于xml中的,最常配合的就是对应类的方法上添加@Bean注解。
@EnableAutoConfiguration根据项目依赖自动化配置
@ComponentScan 组件扫描
@SpringBootApplication就是一个一拖三的功能组合,当然也可以单独使用上面三个注解。
2. SpringApplication
调用SpringApplication.run(ApiApplication.class, args)方法,就进入到SpringApplication的处理逻辑,最终返回一个ApplicationContext上下文.
new一个SpringApplication,在其构造函数里面有ApplicationContentInitializer和ApplicationListener的初始化操作.
ApplicationContextInitializer是Spring框架原有的概念, 这个类的主要目的就是在ConfigurableApplicationContext类型的ApplicationContext做refresh之前,允许我们对ConfigurableApplicationContext的实例做进一步的设置或者处理。
1.实现ApplicationContextInitializer
2.在SpringApplication中添加对应的实例
application.addInitializers(new ApplicationContextInitializerImpl());
3.或者通过factories中添加
context.initializer.classes=\
xxx.ApplicationContextInitializerImpl
ApplicationListenter是配合ApplicationEvent的,实现ApplicationContext的事件机制.
主要事件有:
ApplicationFailedEvent:该事件在springboot启动失败是调用
ApplicationPreparedEvent:上下文context准备时触发
ApplicationReadyEvent:上下文已经准备完毕的时候触发
ApplicationStartedEvent:spring boot 启动监听类
SpringApplicationEvent:获取SpringApplication
ApplicationEnvironmentPreparedEvent:环境事先准备
也可以自定义事件:
1.事件源需要实现ApplicationEvent
2.listenter需要实现ApplicationListener,泛型对象就是上面定义的Event源
核心流程如下:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
- 第一步首先执行一个任务执行观察器
- 获取SpringApplicationRunListener集合
SpringApplicationRunListener 可以监听springboot应用启动过程中的一些生命周期事件,并做一些处理.
public interface SpringApplicationRunListener {
void starting();
void environmentPrepared(ConfigurableEnvironment environment);
void contextPrepared(ConfigurableApplicationContext context);
void contextLoaded(ConfigurableApplicationContext context);
void started(ConfigurableApplicationContext context);
void running(ConfigurableApplicationContext context);
void failed(ConfigurableApplicationContext context, Throwable exception);
}
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
2.1 SpringFactoriesLoader.loadFactoryNames方法
获取类路径下或者系统path路径的META-INF/spring.factories,解析出全部的类名
spring.factories是基于SPI的思想,实现一种解耦的方式.
在我们的日常应用中,org.springframework.boot.autoconfigure.EnableAutoConfiguration 自动配置基本是我们最常用的一种.
2.2 createSpringFactoriesInstances方法
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
T instance = BeanUtils.instantiateClass(constructor, args);
根据对应的类加载器和获得的class全路径,实例化对应的bean.
2.3 启动监听器
springboot中默认的RunListenter是EventPublishingRunListener,事件广播.
封装成SpringApplicationEvent事件然后广播出去给SpringApplication中的listeners所监听,启动监听.
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
- 环境准备
默认情况下,如果情况下会实例化StandardServletEnvironment对象,然后把它绑定到SpringApplicationRunListeners上去. - Banner
默认是OFF,关闭的 - 初始化容器上下文
部分代码省略
contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
- 加载SpringBootExceptionReporter异常上报实例
- 上下文初始化
将listeners、environment、applicationArguments、banner等重要组件与上下文对象关联.
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
- 上下文刷新
调用AbstractApplicationContext.refresh()方法,刷新上下文.
refresh()方法做了很多核心工作比如BeanFactory的设置,BeanFactoryPostProcessor接口的执行、BeanPostProcessor接口的执行、自动化配置类的解析、spring.factories的加载、bean的实例化等等.
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
}
- 进行一些收尾工作,监听器的状态变化等等,最后返回创建的context上下文实例对象.
3. SPI
SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的接口,它可以用来启用框架扩展和替换组件。 SPI的作用就是为这些被扩展的API寻找服务实现。
3.1 java spi
public interface SpiInterface {
void print();
}
public class SpiImpl implements SpiInterface{
@Override
public void print() {
System.out.println("print");
}
}
public class SpiMain {
public static void main(String[] args) {
ServiceLoader<SpiInterface> load = ServiceLoader.load(SpiInterface.class);
Iterator<SpiInterface> iterator = load.iterator();
while(iterator.hasNext()) {
SpiInterface next = iterator.next();
next.print();
}
}
}
最后在resources里面添加META-INF.services/接口的全路径名文件,文件里面添加对应的接口实现类的全路径.
java中的spi主要是依赖ServiceLoader,在使用的过程中实例的对象是懒加载的,通过迭代器的next()方法的时候会去实例化对应的接口实现.
迭代器
public Iterator<S> iterator() {
return new Iterator<S>() {
Iterator<Map.Entry<String,S>> knownProviders
= providers.entrySet().iterator();
public boolean hasNext() {
if (knownProviders.hasNext())
return true;
return lookupIterator.hasNext();
}
public S next() {
if (knownProviders.hasNext())
return knownProviders.next().getValue();
return lookupIterator.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
加载配置资源
if (configs == null) {
try {
String fullName = PREFIX + service.getName();
if (loader == null)
configs = ClassLoader.getSystemResources(fullName);
else
configs = loader.getResources(fullName);
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
}
首先获取类对象,然后通过反射的方法实例化对应对象.
3.2 spring factories
Spring的SpringFactoriesLoader工厂的加载机制类似java提供的SPI机制一样,是Spring提供的一种加载方式。只需要在classpath路径下新建一个文件META-INF/spring.factories,并在里面按照Properties格式填写好接口和实现类即可通过SpringFactoriesLoader来实例化相应的Bean。其中key可以是接口、注解、或者抽象类的全限定名。value为相应的实现类的全限定名,当存在多个实现类时,用“,”进行分割,换行用""。
SpringFactoriesLoader的主要方法:
public static <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader);
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader)
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader)
private static <T> T instantiateFactory(String instanceClassName, Class<T> factoryClass, ClassLoader classLoader)
更详细的代码请大家详细的看SpringFactoriesLoader.
加载spring factories的大致流程:
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
最后完成bean的实例化,以及刷新操作.