第四期柚子营我们作为班长小组,接到通知需要分享三个主题,Spring Boot、Spring Cloud、和Mybatis Plus。第一感觉是能讲的的很多,但是不好讲,孤尽老师提示我们希望其他同学获得什么,怎么可以表达好自己的观点,让大家恍然大悟的地方有没有。比如Spring Boot,Pivotal这个公司有了解过吗,这个框架为什么如此流行,它的容器是怎么启动的等等,简单的东西背后也是复杂的。
这期开班是在孤尽老师在开课吧任CTO期间第一次再和大家见面,我们组也有幸拜访老师办公室,说起来大家都很久没见面了,各自在最忙的时候聚到一起,为同一件事情,也算是技术的情怀吧。柚子营的分享要求事实上是很严格的,我在想Spring Boot怎么分享的时候,很难受,似乎这是大家都很熟悉的东西。但是明明很熟悉的东西我们也总是被老师的问题难倒,所以,那就谈谈我们都头疼的问题,以及我们好像没有关注的一些地方吧。
2、Sring Boot还记得我们最初是怎么使用Spring框架的了吗?
要在复杂的配置和复杂的业务之间反复切换思维,更不要说项目的依赖管理其实也是一件非常吃力的事情。配置和依赖冲突带来的报错是生产力杀手。
Spring Boot做了什么事情,很简单,它是一个贴心的套餐,帮忙做好了你本不不必关心的部分。就像生活中的体检套餐、话费套餐、KFC套餐一样,成本降低,你甚至不用关心套餐中的细节。比如下面的web starter。
我们知道在Spring Boot的启动类中,通过run方法源码可以看到Spring 启动的原貌。但是有一个关键的部分——容器,它是怎么启动的呢?在Spring Boot的官方网页上,介绍Spring Boot为我们内嵌了三种容器供我们使用:Tomcat、Jetty和undertow,默认使用tomcat。我们再去看看tomcat容器是如何被内嵌到Spring Boot应用中的,借助于 IDE,查看 spring-boot-starter-tomcat 的 pom 文件。
org.apache.tomcat.embed tomcat-embed-core9.0.16 compile tomcat-annotations-api org.apache.tomcat org.apache.tomcat.embed tomcat-embed-el9.0.16 compile org.apache.tomcat.embed tomcat-embed-websocket9.0.16 compile
即Spring Boot内嵌的tomcat是一系列的jar包组成的,通过版本信息我们也知道,在Spring Boot 2.1.3中,内嵌tomcat的版本为9。我们再回到Spring Boot启动的原理的run方法中,去查找tomcat是如何启动的。
在进行SpringApplication的实例化时,构造函数中会去判断当前是否为Web环境,构造方法完成之后则是run(String[] args)方法。其中跟启动内置Tomcat相关的则是createApplicationContext()与refreshContext(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) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
可以看到,其主体是一个基于this.webApplicationType变量的判断,来决定启动的Spring Boot应用类型,此处我们获取到的ConfigurableApplicationContext具体实现是AnnotationConfigEmbeddedWebApplicationContext。然而Tomcat是在哪里启动的呢?接下来让我们看下refreshContext(context)的实现。
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
refresh(context);
}
继续往下走,我们在onRefresh方法中找到createWebServer方法,这就是真正Tomcat开始创建的入口。接着通过TomcatServletWebServerFactory完成webServer的获取
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
ServletWebServerFactory factory = getWebServerFactory();
createWebServer.tag("factory", factory.getClass().toString());
this.webServer = factory.getWebServer(getSelfInitializer());
createWebServer.end();
getBeanFactory().registerSingleton("webServerGracefulShutdown",
new WebServerGracefulShutdownLifecycle(this.webServer));
getBeanFactory().registerSingleton("webServerStartStop",
new WebServerStartStopLifecycle(this, this.webServer));
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}
至此,Spring boot内置ServletContainer已经完成了启动内置Web服务器的准备。
3、聊聊时间复杂度与排序 4、小结这一期的课程内容很多,手撕代码被虐之后有痛定思痛,也有继续在内网和外网继续把博客坚持下去的想法,行动起来。



