在上一章中,我们介绍了SpringBoot是如何启动一个内置tomcat的。我们知道我们在SpringBoot项目里面是可以直接使用诸如@RequestMapping
这类的SpringMVC的注解,那么你会不会奇怪,这是为什么?我明明没有配置SpringMVC为什么就可以使用呢?
你还记得我们如何在一个普通的WEB项目中使用SpringMVC吗?我们首先就是要在web.xml中配置如下配置
<servlet>
<description>spring mvc servlet</description>
<servlet-name>springMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
你有没有想过配置的这个东西到底是在干嘛呢?其实要说清楚这个是在干嘛,涉及到SpringMVC的底层原理,我们这里可以理解为这就是在配置一个Dispatcherservlet
,这个Dispatcherservlet
是可以帮我妈转发请求到其他的Servlet,理解不了没关系,我们只要知道在SpringMVC中,必须需要先配置一个Dispatcherservlet
,而在SpringBoot中,我们没有了web.xml文件,我们如何去配置一个Dispatcherservlet
呢?其实Serclet3.0规范中规定,要添加一个Servlet,除了采用xml配置的方式,还有一种通过代码的方式,伪代码如下
servletContext.addServlet(name, this.servlet);
那么也就是说,如果我们能动态往web容器中添加一个我们构造好的DispatcherServlet
对象,是不是就能实现自动装配SpringMVC了?那么SpringBoot又是什么时候把这个DispatcherServlet
装载进容器的呢?下面来说
不知道在前面讲解【SpringBoot源码解析】第二章:SpringBoot是如何通过内置Tomcat启动的你有没有注意到有这样一段代码
getSelfInitializer().onStartup(servletContext);
这段代码其实就是去加载SpringMVC,那么他是如何做到的呢?getSelfInitializer()
最终会去调用到ServletWebServerApplicationContext
的selfInitialize
方法,该方法代码如下
private void selfInitialize(ServletContext servletContext) throws ServletException {
prepareWebApplicationContext(servletContext);
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(
beanFactory);
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory,
getServletContext());
existingScopes.restore();
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory,
getServletContext());
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}
我们通过调试,知道getServletContextInitializerBeans()
返回的是一个ServletContextInitializer
集合,集合中有以下几个对象
然后依次去调用对象的onStartup
方法,那么对于上图标红的对象来说,就是会调用到DispatcherServletRegistrationBean
的onStartup
方法,这个类并没有这个方法,所以最终会调用到父类RegistrationBean
的onStartup
方法,该方法代码如下
public final void onStartup(ServletContext servletContext) throws ServletException {
//获取当前环境到底是一个filter 还是一个servlet 还是一个listener
String description = getDescription();
if (!isEnabled()) {
logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
return;
}
register(description, servletContext);
}
这边register(description, servletContext);
会调用到DynamicRegistrationBean
的register
方法,代码如下
protected final void register(String description, ServletContext servletContext) {
D registration = addRegistration(description, servletContext);
if (registration == null) {
logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)");
return;
}
configure(registration);
}
addRegistration(description, servletContext)
又会调用到ServletRegistrationBean
中的addRegistration
方法,代码如下
protected ServletRegistration.Dynamic addRegistration(String description, ServletContext servletContext) {
String name = getServletName();
return servletContext.addServlet(name, this.servlet);
}
看到了关键的servletContext.addServlet
代码了把,我们通过调试,即可知到this.servlet
就是dispatcherServlet
SpringBoot自动装配SpringMvc其实就是往ServletContext中加入了一个Dispatcherservlet
。
Serclet3.0规范中有这个说明,除了可以动态加Servlet,还可以动态加Listener,Filter
到此为止,还有一个问题,那便是springboot是如何加装其他应用的呢?我们知道,比如我们要在项目里面使用Feign,我们只需要使用这样一个注解@EnableFeignClients
.那么这是如何做到的呢?
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。