走进 Spring Boot 第二步之 SpringApplicaiton 构造函数
Spring Boot Java About 8,781 wordsSpring Boot 启动类
SpringApplication.run
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
SpringApplication
构造函数
resourceLoader
参数为空,primarySources
参数为DemoApplication
的字节码类。
//SpringApplication类
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// primarySources可变参数为单一的一个DemoApplication
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//判断DemoApplication的应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//从Spring工厂示例中获得Initializers
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//从Spring工厂示例中获得Listeners
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//判断应用main方法入口
this.mainApplicationClass = deduceMainApplicationClass();
}
deduceFromClasspath
从类路径推断应用类型,先判断是否是REACTIVE
,若不是,则判断SERVLET_INDICATOR_CLASSES
数组中的两个全路径类名能否加载,如果能加载则是SERVLET
应用,否则就是NONE
。
//WebApplicationType类
private static final String[] SERVLET_INDICATOR_CLASSES = {
"javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext"
};
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
ClassUtils
的isPresent
判断能否更具全路径名称加载该类,捕获了ClassNotFoundException
异常
//ClassUtils类
public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
try {
forName(className, classLoader);
return true;
}
catch (IllegalAccessError err) {
throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" +
className + "]: " + err.getMessage(), err);
}
catch (Throwable ex) {
// Typically ClassNotFoundException or NoClassDefFoundError...
return false;
}
}
public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
throws ClassNotFoundException, LinkageError {
Assert.notNull(name, "Name must not be null");
// 省略了判断字节码类是否原子类型
ClassLoader clToUse = classLoader;
if (clToUse == null) {
clToUse = getDefaultClassLoader();
}
try {
return Class.forName(name, false, clToUse);
}
catch (ClassNotFoundException ex) {
throw ex;
}
}
getSpringFactoriesInstances
根据全路径名从Spring
工厂中获得实例。
//SpringApplication类
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
// 获取classLoader,非重点,不展开
ClassLoader classLoader = getClassLoader();
// 使用名称确保唯一来防止重复
// 加载META-INF/spring.factories配置的类
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 创建实例
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
//根据注解来排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
//SpringFactoriesLoader类
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
// 根据key获取对应的value
// Initializers/Listeners的key正好都是interface基类
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
//省略了从缓存取
try {
// 加载META-INF/spring.factories配置文件
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
// 读取配置信息,PropertiesLoaderUtils为Spring工具类用于读取配置文件,此处不展开
// META-INF/spring.factories配置文件中的反斜杠\会被解析为一行,了解更多Java Properties类可参见先前文章
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryClassName = ((String) entry.getKey()).trim();
// 将逗号分隔的value值解析为String数组
// 遍历数组放入LinkedMultiValueMap对象中,LinkedMultiValueMap实际就是一个LinkedHashMap
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryClassName, factoryName.trim());
}
}
}
// 配置信息放入缓存
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
META-INF/spring.factories
中的Initializers
和Listeners
配置
# 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
createSpringFactoriesInstances
使用反射初始化各个Initializers
和Listeners
等。
//SpringApplication
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
// 遍历,使用反射初始化类,BeanUtils等反射初始化类等此处不展开
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;
}
deduceMainApplicationClass
主动new
出一个运行时异常,根据堆栈信息获取main
方法对应的堆栈元素,根据该堆栈元素来获取main
方法所在的类名。
//SpringApplication
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
流程总结
- 判断应用类型
- 获得
Initializers
实例集合 - 获得
Listeners
实例集合 - 获得
main
方法所在类
Views: 4,601 · Posted: 2020-04-04
————        END        ————
Give me a Star, Thanks:)
https://github.com/fendoudebb/LiteNote扫描下方二维码关注公众号和小程序↓↓↓
Loading...