版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baijunzhijiang_01/article/details/84076230
从spring.factories文件中加载key对应的类的实例
读取spring.factories的key和value并通过反射选择性的创建一些实例的过程。源码如下:
spring.factories文件
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers
# 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.web.context.ServerPortInfoApplicationContextInitializer
# 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.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
读取spring.factories文件中
// type一般是接口值,通常为spring.factories文件中的k值。
// names 是key对应的value值的set集合。
// 根据key,value来创建spring.factories中key对应的value中的每个类的实例。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
// 根据key,value的值,通过反射创建spring.factories中key对应的value中的每个类的实例
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
SpringBoot启动流程
一、首先实例化SpringApplication对象
- 初始化
- 使用SpringFactoriesLoader扫描META-INF/spring.factories目录下的初始化器和10个监听器
- 设置main类
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推断webApplicationType
// 推断逻辑: 存在这两个类javax.servlet.Servlet,org.springframework.web.context.ConfigurableWebApplicationContext
this.webApplicationType = deduceWebApplicationType();
// 初始化6个初始化器
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 初始化10个监听器器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 设置main类
this.mainApplicationClass = deduceMainApplicationClass();
}
自动装载配置的过程
- 使用SpringFactoriesLoader扫描META-INF/spring.factories目录下的url
- 根据读到的url连接获取Resource文件
- PropertiesLoaderUtils从文件中获取Properties
- Properties转成set后,将Properties的value,然后将key和value放置到MultiValueMap的对象Result中
- 将result的数据更新到缓存cache中。
// SpringFactoriesLoader的缓存
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
List<String> factoryClassNames = Arrays.asList(
StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
result.addAll((String) entry.getKey(), factoryClassNames);
}
二、SpringApplication实例运行run方法
- 创建一个计时器stopwatch,分别打印各个阶段耗费时间
- 声明context和SpringBoot异常报告集合
- 配置java.awt.headless
- 实例化EventPublishingRunListener,用于在SpringAllication的run方法执行到不同阶段,发布相应的事件给相应的监听器
- 初始化默认应用参数类
- 准备Spring环境,根据webApplicationType值来创建WEB环境或者是Standard环境,同时初始化systemProperties
- 配置environment中spring.beaninfo.ignore的属性
- 打印 banner
- 根据webApplicationType实例化一个AnnotationConfigServletWebServerApplicationContext容器对象
- 异常报告集合
- 准备环境,包括(绑定environment对象到Context
- 刷新环境
- 计时器停止计时,监听器发布Context启动完成事件给其他的监听器
- 获取所有实现ApplicationRunner接口的类,获取所有实现CommandLineRunner的类根据其@Order进行排序,执行run()方法。
public ConfigurableApplicationContext run(String... args) {
//1. 创建一个计时器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 配置java.awt.headless
configureHeadlessProperty();
// 实例化一个监听器,用于在SpringAllication的run方法执行到不同阶段,发布相应的时间给相应的监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
// 初始化默认应用参数类
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备Spring环境,根据webApplicationType值来创建WEB环境 或者是Standard环境,同时初始化systemProperties
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//配置environment中spring.beaninfo.ignore的属性
configureIgnoreBeanInfo(environment);
// 打印 banner
Banner printedBanner = printBanner(environment);
//根据webApplicationType实例化一个AnnotationConfigServletWebServerApplicationContext对象
context = createApplicationContext();
// 异常报告集合
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 准备环境,包括(绑定environment对象到Context,
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 刷新环境
refreshContext(context);
// 刷新环境后
afterRefresh(context, applicationArguments);
// 计时器停止计时。
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// 监听器发布Context启动完成事件给其他的监听器
listeners.started(context);
//获取所有实现ApplicationRunner接口的类,获取所有实现CommandLineRunner的类根据其@Order进行排序,执行run()方法。
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 发送消息,广播给监听器ApplicationReadyEvent事件。
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
准备环境
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 创建or配置the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置environment
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 通知EventPublishingRunListener事件监听器,去广播一个ApplicationEnvironmentPreparedEvent事件给所有的监听器
listeners.environmentPrepared(environment);
// 绑定environment到当前SpringApplication实例
bindToSpringApplication(environment);
//
if (this.webApplicationType == WebApplicationType.NONE) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
ConfigurationPropertySources.attach(environment);
return environment;
}
准备容器
- 容器设置环境参数
- 后置处理容器( internalConfigurationAnnotationProcessor,internalAutowiredAnnotationProcessor, internalRequiredAnnotationProcessor, internalCommonAnnotationProcessor,internalEventListenerProcessor)
- 完成initializer的初始化
- 监听器发送事件给广播,广播给相应的监听器处理事件。
- 注册applicationArguments到容器的单例工场中
- 注册banner
- 监听器发送事件给广播,广播给相应的监听器处理事件。
- 装载bean到SpringIOC容器中。
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
// 应用初始化容器
// BackgroundPreinitializer完成MessageConverterInitializer,MBeanFactoryInitializer,ValidationInitializer,JacksonInitializer,ConversionServiceInitializer初始化
//ConfigurationWarningsApplicationContextInitializer 为Context添加一个bean工厂后置处理器
//ContextIdApplicationContextInitializer 给ApplicationContext设置一个ID,注册到容器中
//DelegatingApplicationContextInitializer 初始化器实际上将初始化的工作委托给context.initializer.classes环境变量指定的初始化器(通过类名)
// ServerPortInfoApplicationContextInitializer,将自己作为一个监听器注册到Context中。监听EmbeddedServletContainerInitializedEvent类型的事件。然后将内嵌的Web服务器使用的端口给设置到ApplicationContext中。
// SharedMetadataReaderFactoryContextInitializer 创建一个用于在ConfigurationClassPostProcessor和Spring Boot间共享的CachingMetadataReaderFactory。
applyInitializers(context);
// 监听器发送事件给广播,广播给相应的监听器处理事件。
// 将listeners加入到容器的listeners属性中。
// Loaded config file 'file:/D:/../target/classes/application.yml'
listeners.contextPrepared(context);
// 如果开始打印日志
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
// 注册banner
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
// internalConfigurationAnnotationProcessor
// internalAutowiredAnnotationProcessor
// internalRequiredAnnotationProcessor
// internalCommonAnnotationProcessor
// internalEventListenerProcessor
// internalEventListenerFactory
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 装载bean到SpringIOC容器中。
load(context, sources.toArray(new Object[0]));
// 监听器发送事件给广播,广播给相应的监听器处理事件。
listeners.contextLoaded(context);
}
后置处理容器,为容器设置beanNameGenerator,resourceLoader
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context)
.setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context)
.setClassLoader(this.resourceLoader.getClassLoader());
}
}
}
加载bean到容器中
- 创建bean定义加载器Loader
- 设置Loader的beanNameGenerator,resourceLoader,environment
- loader开始工作,装载bean
/**
* Load beans into the application context.
* @param context the context to load beans into
* @param sources the sources to load
*/
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug(
"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
// 创建bean定义加载器Loader
BeanDefinitionLoader loader = createBeanDefinitionLoader(
getBeanDefinitionRegistry(context), sources);
// 设置Loader的beanNameGenerator,resourceLoader,environment
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
// loader开始工作,加载bean到容器中
loader.load();
}
回调callRunner()方法
获取所有实现ApplicationRunner接口的类,获取所有实现CommandLineRunner的类根据其@Order进行排序,执行run()方法。
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
// 1.获取所有实现ApplicationRunner接口的类
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
// 2.获取所有实现CommandLineRunner的类
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// 3.根据其@Order进行排序
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<Object>(runners)) {
// 4.调用ApplicationRunner其run方法
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
// 5.调用CommandLineRunner其run方法
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
ApplicationRunner接口实现类
实现了这两个接口(ApplicationRunner,CommandLineRunner)的类将会在callRunner的时候执行
@Component
public class TestApplicationRunner implements ApplicationRunner {
@Override public void run(ApplicationArguments args) throws Exception {
System.out.println("服务启动,TestCommandLineRunner执行启动加载任务.start..");
if (null != args) {
System.out.println(args.getOptionNames());
}
System.out.println("服务启动,TestCommandLineRunner执行启动加载任务.end..");
}
}
来自SpringBoot框架的馈赠
StopWatch(秒表):计时器工具类。一个对开始时间,结束时间记录操作的Java类
public class StopWatchTest {
private Logger LOG = LoggerFactory.getLogger(getClass());
@Test
public void testStopWatch(){
StopWatch watch = new StopWatch();
try {
watch.start("watch1");
Thread.sleep(2000L);
watch.stop();
watch.start("watch2");
Thread.sleep(1030L);
watch.stop();
LOG.info(watch.prettyPrint());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}