前言
最近打算扩展mybatis-plus,但是都是整合在springboot中,所以打算搞清楚两件事,一件事就是springboot启动都加载了哪些bean,yml文件怎么处理的,第二件事,就是请求数据库,mybatisplus如何处理的。
springboot源码版本
2.6.3
springboot程序入口
执行main方法,先不关心那个@SpringBootApplication注解:
@SpringBootApplication
public class SourceCodeApplication {
public static void main(String[] args) {
SpringApplication.run(SourceCodeApplication.class, args);
}
}
调用run方法:
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
new SpringApplication对象过程
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 初始化资源加载器
this.resourceLoader = resourceLoader;
// 校验资源不为null
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 判断使用的容器类型
/**
* 有这个org.springframework.web.reactive.DispatcherHandler类,
* 没有这个org.springframework.web.servlet.DispatcherServlet类,
* 你那么采用reactive响应式编程,否则默认采用sevlet
*/
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// 加载classpath下META-INF/spring.factories中配置的ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 加载classpath下META-INF/spring.factories中配置的ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 初始化入口main类
this.mainApplicationClass = deduceMainApplicationClass();
}
getSpringFactoriesInstances(ApplicationContextInitializer.class)加载classpath下META-INF/spring.factories:
读取META-INF/spring.factories文件,加载接口名和类名,生成map映射关系,返回map。
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
// 获取类加载器
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
// FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
// 存入接口的类型名称,对应value值为实现类的名称
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// 消除重复元素,生成不变的map
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
// 将加载的类都缓存到cache
// Map<ClassLoader, Map<String, List<String>>> cache = new ConcurrentReferenceHashMap<>();
cache.put(classLoader, result);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}
反射实例化类:
getSpringFactoriesInstances(ApplicationListener.class)加载classpath下META-INF/spring.factories:
this.mainApplicationClass = deduceMainApplicationClass();初始化入口main类
SpringApplication对象的run方法
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 设置系统变量java.awt.headless
configureHeadlessProperty();
// 加载SpringApplicationRunListener监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 创建配置environment
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// spring.beaninfo.ignore字段,忽略配置bean信息,
configureIgnoreBeanInfo(environment);
// 打印banner,SpringBoot启动时,控制台输出的一个歪歪扭扭的很不清楚的Spring几个大字母,也可以自定义
Banner printedBanner = printBanner(environment);
// 根据this.webApplicationType配置是加载reactive响应式编程,还是默认的servlet,创建上下文context
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 将前面配置的environment设置到context上下文
// springApplicationArguments、springBootBanner单例模式实例化
// 初始化循环依赖配置为false、BeanDefinition重写覆盖为false
// 初始化懒加载后置处理器
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 加载bean,里面调用refresh方法与之前的spring套路一样了
refreshContext(context);
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
listeners.started(context, timeTakenToStartup);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
refreshContext方法调用refresh方法,实现初始化容器
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
refresh(context);
}
老版spring加载xml文件,AbstractApplicationContext类之refresh方法加载bean:
参考:https://www.jianshu.com/p/56f863a44d96
springboot加载bean,实现refresh方法,慢慢分析。
网友评论