spring boot 2.0 源码分析(二)
- 时间:
- 浏览:0
- 来源:极速快3_快3平台登陆_极速快3平台登陆
在上一章学习了spring boot 2.0启动的要花费流程时候,今天朋友来深挖一下SpringApplication实例变量的run函数。
先把这段run函数的代码贴出来:
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
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, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
朋友先来分析其中的第俩个多多关键代码:SpringApplicationRunListeners listeners = getRunListeners(args);
这行代码是获取监听器,朋友先跳转到getRunListeners中看一下:
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
在这段代码中,朋友想看
获取监听器,是new出来了俩个多多SpringApplicationRunListeners实例并返回。
再次跳转到SpringApplicationRunListeners的构造函数中,想看
一分类整理生了什么:
SpringApplicationRunListeners(Log log,
Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList(listeners);
}
在这名
构造函数里,朋友想看
其只是把接收到的listeners参数,保存到实例变量里,这样过多
的操作。
某些,重点是在listeners参数这里,而listeners是通过getSpringFactoriesInstances创建出来的,来看一下getSpringFactoriesInstances函数做了什么事情吧:
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;
}
在这里朋友想看 ,首先创建了俩个多多classloader,而且用SpringFactoriesLoader.loadFactoryNames(type, classLoader),加载了SpringFactoriesLoader列表。朋友来看一下loadFactoryNames底下的代码:
public static List<String> loadFactoryNames(Class<?> factoryClass,
@Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName,
Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap result = (MultiValueMap)cache.get(classLoader);
if(result != null) {
return result;
} else {
try {
Enumeration ex = classLoader != null?
classLoader.getResources("META-INF/spring.factories")
:ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result1 = new LinkedMultiValueMap();
while(ex.hasMoreElements()) {
URL url = (URL)ex.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry entry = (Entry)var6.next();
List factoryClassNames = Arrays.asList(StringUtils
.commaDelimitedListToStringArray((String)entry.getValue()));
result1.addAll((String)entry.getKey(), factoryClassNames);
}
}
cache.put(classLoader, result1);
return result1;
} catch (IOException var9) {
throw new IllegalArgumentException(
"Unable to load factories from location [META-INF/spring.factories]", var9);
}
}
}
通过这里朋友想看 了其首先加载了META-INF/spring.factories这名 配置文件下的所有资源,并插进缓存,而且再获取了org.springframework.context.ApplicationListener定义的资源列表。
小发现:在这里朋友发现spring boot自动装配文件的位置。
获取到META-INF/spring.factories这名 配置文件下的资源名称列表时候,通过createSpringFactoriesInstances函数创建了SpringFactories的实例。
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set<String> names) {
ArrayList instances = new ArrayList(names.size());
Iterator var7 = names.iterator();
while(var7.hasNext()) {
String name = (String)var7.next();
try {
Class ex = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, ex);
Constructor constructor = ex.getDeclaredConstructor(parameterTypes);
Object instance = BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
} catch (Throwable var12) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name,
var12);
}
}
return instances;
}
通过底下的什么代码流转,朋友要花费搞清楚了listeners是为什么会么会会么会创建出来的。
而且调用了listeners的starting妙招。朋友先要花费地看一下EventPublishingRunListener底下的starting的实现:
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application,
this.args));
}
关键代码在这里:
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = eventType != null?eventType:this.resolveDefaultEventType(event);
Iterator var4 = this.getApplicationListeners(event, type).iterator();
while(var4.hasNext()) {
ApplicationListener listener = (ApplicationListener)var4.next();
Executor executor = this.getTaskExecutor();
if(executor != null) {
executor.execute(() -> {
this.invokeListener(listener, event);
});
} else {
this.invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = this.getErrorHandler();
if(errorHandler != null) {
try {
this.doInvokeListener(listener, event);
} catch (Throwable var5) {
errorHandler.handleError(var5);
}
} else {
this.doInvokeListener(listener, event);
}
}
在底下代码中朋友想看 ,starting只是拿到META-INF/spring.factories中定义的资源的实例时候,而且再创建俩个多多tcp连接去启动起来。
通过底下的什么代码朋友知道了spring boot会获取META-INF/spring.factories中的资源,并创建什么资源的实例(listeners监听器),而且为每俩个多多监听器创建俩个多多tcp连接启动起来。
篇幅有限, 今天就写到这里吧。有希望一起去学习spring boot 2.0源码的同学还都都里能 关注我,跟我一起去分析spring boot 2.0 源码的实现妙招。