【Spring】原来SpringBoot是这样玩的
2020-12-24 00:29
标签:自身 webserver break 手动 imp 重要 ica scan conf 菜瓜:我自己去调Mvc的源码差点没给Spring的逻辑秀死。。。难受 水稻:那今天咱们看一个简单易用的SpringBoot吧 菜瓜:可以,这个我熟悉 水稻:熟悉? 菜瓜:当我没说,请开始你的表演 水稻:我没有别的意思,就是单纯的反问(手动狗头)。平时工作中用多了SpringBoot。咱们今天带着几个问题来看看它的操作吧 菜瓜:你确定这是我熟悉的SpringBoot??? 水稻:。。。看过来 水稻:好了,第一步和第二步完成了 菜瓜:就这??? 水稻:是不是极其简单,令人发指。重头戏是后面的自动装配 菜瓜:原来如此。你把调用链拎出来就简单了很多。自动装配就是通过SPI加载org.springframework.boot.autoconfigure包下的class,封装成BeanDefinition后交给容器加载 总结:SpringBoot只需要一行代码便能启动一个Java应用。完全解放开发者复杂的配置 【Spring】原来SpringBoot是这样玩的 标签:自身 webserver break 手动 imp 重要 ica scan conf 原文地址:https://www.cnblogs.com/nightOfStreet/p/13211045.html
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
...
listeners.starting();
try {
...
// ①创建Spring上下文容器对象 - 默认Servlet容器
context = createApplicationContext();
...
// ②调用refresh方法 - 回到熟悉的容器启动流程
refreshContext(context);
afterRefresh(context, applicationArguments);
...
...
return context;
}
protected ConfigurableApplicationContext createApplicationContext() {
Class> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
...
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
...
// ①springboot 内嵌tomcat容器
onRefresh();
...
}
@Override
protected void onRefresh() {
super.onRefresh();
try {
// ②创建Servlet容器 默认tomcat
createWebServer();
}
...
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
// ③看进去 回到mvc集成tomcat的场景
this.webServer = factory.getWebServer(getSelfInitializer());
}
...
initPropertySources();
}
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory
: createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);
}
...
// 标记自身被扫描
@SpringBootConfiguration
// 下一步 - 自动装配入口
@EnableAutoConfiguration
// 扫描bean路径 - 约定是启动类所在的包:所以没事别把启动类挪走(都是泪)
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication
->
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration
-> 重要
public class AutoConfigurationImportSelector ... {
@Override
public void process(AnnotationMetadata annotationMetadata,
DeferredImportSelector deferredImportSelector) {
...
// 获取以EnableAutoConfiguration命名的/META-INF/Spring.factories文件中的value去重
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector).getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
// 启动的时候断点可以看到
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
}AutoConfigurationImportSelector 中的process是被ConfigurationClassPostProcessor通过processConfigBeanDefinitions方法调用(调用链如下)
1. this.processConfigBeanDefinitions(registry);
2. parser.parse(candidates);
3. this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
4. sourceClass = this.doProcessConfigurationClass(configClass, sourceClass);
5. this.processImports(configClass, sourceClass, this.getImports(sourceClass), true);
6. this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector)selector);
7. handler.processGroupImports();
8. grouping.getImports().forEach...
9. this.group.process(...);
--
搜集到需要自动装配的类,封装成BeanDefinition后续实例化,实现自动装配功能
譬如引入WebMvcAutoConfiguration类 - webmvc功能自动集成
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
文章标题:【Spring】原来SpringBoot是这样玩的
文章链接:http://soscw.com/index.php/essay/37801.html