在上一章中,我们介绍了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.那么这是如何做到的呢?