SpringBoot 源碼解析 (七)----- Spring Boot的核心能力 - SpringBoot如何實現SpringMvc的?

上一篇咱們講了SpringBoot中Tomcat的啓動過程,本篇咱們接着講在SpringBoot中如何向Tomcat中添加Servlet、Filter、Listenerhtml

自定義Servlet、Filter、Listener

Spring容器中聲明ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean

@Bean public ServletRegistrationBean customServlet() { return new ServletRegistrationBean(new CustomServlet(), "/custom"); } private static class CustomServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("receive by custom servlet"); } }

先自定義一個Servlet,重寫service實現本身的業務邏輯,而後經過@Bean註解往Spring容器中注入一個ServletRegistrationBean類型的bean實例,而且實例化一個自定義的Servlet做爲參數,這樣就將自定義的Servlet加入Tomcat中了。前端

@ServletComponentScan註解和@WebServlet、@WebFilter以及@WebListener註解配合使用

@ServletComponentScan註解啓用ImportServletComponentScanRegistrar類,是個ImportBeanDefinitionRegistrar接口的實現類,會被Spring容器所解析。ServletComponentScanRegistrar內部會解析@ServletComponentScan註解,而後會在Spring容器中註冊ServletComponentRegisteringPostProcessor,是個BeanFactoryPostProcessor,會去解析掃描出來的類是否是有@WebServlet、@WebListener、@WebFilter這3種註解,有的話把這3種類型的類轉換成ServletRegistrationBean、FilterRegistrationBean或者ServletListenerRegistrationBean,而後讓Spring容器去解析:java

@SpringBootApplication @ServletComponentScan public class EmbeddedServletApplication { ... } @WebServlet(urlPatterns = "/simple") public class SimpleServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("receive by SimpleServlet"); } }

在Spring容器中聲明Servlet、Filter或者Listener

@Bean(name = "dispatcherServlet") public DispatcherServlet myDispatcherServlet() { return new DispatcherServlet(); }

咱們發現往Tomcat中添加Servlet、Filter或者Listener仍是挺容易的,你們還記得之前SpringMVC是怎麼配置DispatcherServlet的嗎?在web.xml中:web

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

和咱們SpringBoot中配置Servlet相比是否是複雜不少,雖然SpringBoot中自定義Servlet很簡單,可是其底層卻不簡單,下面咱們來分析一下其原理spring

ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean

咱們來看看這幾個特殊的類:spring-mvc

ServletRegistrationBean

public class ServletRegistrationBean extends RegistrationBean { //存放目標Servlet實例 private Servlet servlet; //存放Servlet的urlMapping private Set<String> urlMappings; private boolean alwaysMapUrl; private int loadOnStartup; private MultipartConfigElement multipartConfig; public ServletRegistrationBean(Servlet servlet, String... urlMappings) { this(servlet, true, urlMappings); } public ServletRegistrationBean(Servlet servlet, boolean alwaysMapUrl, String... urlMappings) { this.urlMappings = new LinkedHashSet(); this.alwaysMapUrl = true; this.loadOnStartup = -1; Assert.notNull(servlet, "Servlet must not be null"); Assert.notNull(urlMappings, "UrlMappings must not be null"); this.servlet = servlet; this.alwaysMapUrl = alwaysMapUrl; this.urlMappings.addAll(Arrays.asList(urlMappings)); } public void onStartup(ServletContext servletContext) throws ServletException { Assert.notNull(this.servlet, "Servlet must not be null"); String name = this.getServletName(); if (!this.isEnabled()) { logger.info("Servlet " + name + " was not registered (disabled)"); } else { logger.info("Mapping servlet: '" + name + "' to " + this.urlMappings); Dynamic added = servletContext.addServlet(name, this.servlet); if (added == null) { logger.info("Servlet " + name + " was not registered (possibly already registered?)"); } else { this.configure(added); } } } //
}

在咱們例子中咱們經過return new ServletRegistrationBean(new CustomServlet(), "/custom");就知道,ServletRegistrationBean裏會存放目標Servlet實例和urlMapping,而且繼承RegistrationBean這個類tomcat

FilterRegistrationBean

public class FilterRegistrationBean extends AbstractFilterRegistrationBean { //存放目標Filter對象 private Filter filter; public FilterRegistrationBean() { super(new ServletRegistrationBean[0]); } public FilterRegistrationBean(Filter filter, ServletRegistrationBean... servletRegistrationBeans) { super(servletRegistrationBeans); Assert.notNull(filter, "Filter must not be null"); this.filter = filter; } public Filter getFilter() { return this.filter; } public void setFilter(Filter filter) { Assert.notNull(filter, "Filter must not be null"); this.filter = filter; } } abstract class AbstractFilterRegistrationBean extends RegistrationBean { private static final EnumSet<DispatcherType> ASYNC_DISPATCHER_TYPES; private static final EnumSet<DispatcherType> NON_ASYNC_DISPATCHER_TYPES; private static final String[] DEFAULT_URL_MAPPINGS; private Set<ServletRegistrationBean> servletRegistrationBeans = new LinkedHashSet(); private Set<String> servletNames = new LinkedHashSet(); private Set<String> urlPatterns = new LinkedHashSet(); //重寫onStartup方法
    public void onStartup(ServletContext servletContext) throws ServletException { Filter filter = this.getFilter(); Assert.notNull(filter, "Filter must not be null"); String name = this.getOrDeduceName(filter); if (!this.isEnabled()) { this.logger.info("Filter " + name + " was not registered (disabled)"); } else { Dynamic added = servletContext.addFilter(name, filter); if (added == null) { this.logger.info("Filter " + name + " was not registered (possibly already registered?)"); } else { this.configure(added); } } } //略...
}

咱們看到FilterRegistrationBean 中也保存了目標Filter對象,而且繼承了RegistrationBeanmvc

ServletListenerRegistrationBean

public class ServletListenerRegistrationBean<T extends EventListener> extends RegistrationBean { //存放了目標listener
    private T listener; public ServletListenerRegistrationBean() { } public ServletListenerRegistrationBean(T listener) { Assert.notNull(listener, "Listener must not be null"); Assert.isTrue(isSupportedType(listener), "Listener is not of a supported type"); this.listener = listener; } public void setListener(T listener) { Assert.notNull(listener, "Listener must not be null"); Assert.isTrue(isSupportedType(listener), "Listener is not of a supported type"); this.listener = listener; } public void onStartup(ServletContext servletContext) throws ServletException { if (!this.isEnabled()) { logger.info("Listener " + this.listener + " was not registered (disabled)"); } else { try { servletContext.addListener(this.listener); } catch (RuntimeException var3) { throw new IllegalStateException("Failed to add listener '" + this.listener + "' to servlet context", var3); } } } //略...
}

ServletListenerRegistrationBean也是同樣,那咱們來看看RegistrationBean這個類app

public abstract class RegistrationBean implements ServletContextInitializer, Ordered { ... } public interface ServletContextInitializer { void onStartup(ServletContext var1) throws ServletException; }

咱們發現RegistrationBean 實現了ServletContextInitializer這個接口,而且有一個onStartup方法,ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean都實現了onStartup方法。ide

ServletContextInitializer是 Servlet 容器初始化的時候,提供的初始化接口。因此,Servlet 容器初始化會獲取並觸發全部的FilterRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean實例中onStartup方法

那究竟是什麼時候觸發這些類的onStartup方法呢?

當Tomcat容器啓動時,會執行callInitializers,而後獲取全部的ServletContextInitializer,循環執行onStartup方法觸發回調方法。那FilterRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean實例是什麼時候加入到Initializers集合的呢?這要回顧一下咱們上一篇文章Tomcat的啓動過程

Servlet容器的啓動

你們能夠看看我上一篇文章,我這裏簡單的複製一下代碼

EmbeddedWebApplicationContext

 1 @Override  2 protected void onRefresh() {  3     super.onRefresh();  4     try {  5         //核心方法:會獲取嵌入式的Servlet容器工廠,並經過工廠來獲取Servlet容器
 6  createEmbeddedServletContainer();  7  }  8     catch (Throwable ex) {  9         throw new ApplicationContextException("Unable to start embedded container", ex); 10  } 11 } 12 
13 private void createEmbeddedServletContainer() { 14     EmbeddedServletContainer localContainer = this.embeddedServletContainer; 15     ServletContext localServletContext = getServletContext(); 16     if (localContainer == null && localServletContext == null) { 17         //先獲取嵌入式Servlet容器工廠
18         EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory(); 19         //根據容器工廠來獲取對應的嵌入式Servlet容器 20 this.embeddedServletContainer = containerFactory.getEmbeddedServletContainer(getSelfInitializer()); 21  } 22     else if (localServletContext != null) { 23         try { 24  getSelfInitializer().onStartup(localServletContext); 25  } 26         catch (ServletException ex) { 27             throw new ApplicationContextException("Cannot initialize servlet context",ex); 28  } 29  } 30  initPropertySources(); 31 }

關鍵代碼在第20行,先經過getSelfInitializer()獲取到全部的Initializer,傳入Servlet容器中,那核心就在getSelfInitializer()方法:

1 private ServletContextInitializer getSelfInitializer() { 2     //只是建立了一個ServletContextInitializer實例返回 3     //因此Servlet容器啓動的時候,會調用這個對象的onStartup方法
4     return new ServletContextInitializer() { 5         public void onStartup(ServletContext servletContext) throws ServletException { 6 EmbeddedWebApplicationContext.this.selfInitialize(servletContext); 7  } 8  }; 9 }

咱們看到只是建立了一個ServletContextInitializer實例返回,因此Servlet容器啓動的時候,會調用這個對象的onStartup方法,那咱們來分析其onStartup中的邏輯,也就是selfInitialize方法,並將Servlet上下文對象傳進去了

selfInitialize

 1 private void selfInitialize(ServletContext servletContext) throws ServletException {  2  prepareWebApplicationContext(servletContext);  3     ConfigurableListableBeanFactory beanFactory = getBeanFactory();  4     ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(beanFactory);  5  WebApplicationContextUtils.registerWebApplicationScopes(beanFactory,getServletContext());  6  existingScopes.restore();  7  WebApplicationContextUtils.registerEnvironmentBeans(beanFactory,getServletContext());  8     //這裏即是獲取全部的 ServletContextInitializer 實現類,會獲取全部的註冊組件  9 for (ServletContextInitializer beans : getServletContextInitializerBeans()) { 10 //執行全部ServletContextInitializer的onStartup方法 11  beans.onStartup(servletContext); 12  } 13 }

關鍵代碼在第9和第11行,先獲取全部的ServletContextInitializer 實現類,而後遍歷執行全部ServletContextInitializer的onStartup方法

獲取全部的ServletContextInitializer

咱們來看看getServletContextInitializerBeans方法

protected Collection<ServletContextInitializer> getServletContextInitializerBeans() { return new ServletContextInitializerBeans(getBeanFactory()); }

ServletContextInitializerBeans對象是對ServletContextInitializer的一種包裝:

 1 public class ServletContextInitializerBeans extends AbstractCollection<ServletContextInitializer> {  2     private final MultiValueMap<Class<?>, ServletContextInitializer> initializers = new LinkedMultiValueMap();  3 //存放全部的ServletContextInitializer  4 private List<ServletContextInitializer> sortedList;  5 
 6     public ServletContextInitializerBeans(ListableBeanFactory beanFactory) {  7 //執行addServletContextInitializerBeans  8 this.addServletContextInitializerBeans(beanFactory);  9 //執行addAdaptableBeans 10 this.addAdaptableBeans(beanFactory); 11 List<ServletContextInitializer> sortedInitializers = new ArrayList(); 12 Iterator var3 = this.initializers.entrySet().iterator(); 13 14 while(var3.hasNext()) { 15 Entry<?, List<ServletContextInitializer>> entry = (Entry)var3.next(); 16  AnnotationAwareOrderComparator.sort((List)entry.getValue()); 17  sortedInitializers.addAll((Collection)entry.getValue()); 18  } 19 this.sortedList = Collections.unmodifiableList(sortedInitializers); 20  } 21 
22     private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) { 23         Iterator var2 = this.getOrderedBeansOfType(beanFactory, ServletContextInitializer.class).iterator(); 24 
25         while(var2.hasNext()) { 26             Entry<String, ServletContextInitializer> initializerBean = (Entry)var2.next(); 27             this.addServletContextInitializerBean((String)initializerBean.getKey(), (ServletContextInitializer)initializerBean.getValue(), beanFactory); 28  } 29 
30  } 31 
32     private void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer, ListableBeanFactory beanFactory) { 33         if (initializer instanceof ServletRegistrationBean) { 34             Servlet source = ((ServletRegistrationBean)initializer).getServlet(); 35             this.addServletContextInitializerBean(Servlet.class, beanName, initializer, beanFactory, source); 36         } else if (initializer instanceof FilterRegistrationBean) { 37             Filter source = ((FilterRegistrationBean)initializer).getFilter(); 38             this.addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source); 39         } else if (initializer instanceof DelegatingFilterProxyRegistrationBean) { 40             String source = ((DelegatingFilterProxyRegistrationBean)initializer).getTargetBeanName(); 41             this.addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source); 42         } else if (initializer instanceof ServletListenerRegistrationBean) { 43             EventListener source = ((ServletListenerRegistrationBean)initializer).getListener(); 44             this.addServletContextInitializerBean(EventListener.class, beanName, initializer, beanFactory, source); 45         } else { 46             this.addServletContextInitializerBean(ServletContextInitializer.class, beanName, initializer, beanFactory, initializer); 47  } 48 
49  } 50 
51     private void addServletContextInitializerBean(Class<?> type, String beanName, ServletContextInitializer initializer, ListableBeanFactory beanFactory, Object source) { 52         this.initializers.add(type, initializer); 53         if (source != null) { 54             this.seen.add(source); 55  } 56 
57         if (logger.isDebugEnabled()) { 58             String resourceDescription = this.getResourceDescription(beanName, beanFactory); 59             int order = this.getOrder(initializer); 60             logger.debug("Added existing " + type.getSimpleName() + " initializer bean '" + beanName + "'; order=" + order + ", resource=" + resourceDescription); 61  } 62 
63  } 64 
65     private void addAdaptableBeans(ListableBeanFactory beanFactory) { 66         MultipartConfigElement multipartConfig = this.getMultipartConfig(beanFactory); 67         this.addAsRegistrationBean(beanFactory, Servlet.class, new ServletContextInitializerBeans.ServletRegistrationBeanAdapter(multipartConfig)); 68         this.addAsRegistrationBean(beanFactory, Filter.class, new ServletContextInitializerBeans.FilterRegistrationBeanAdapter(null)); 69         Iterator var3 = ServletListenerRegistrationBean.getSupportedTypes().iterator(); 70 
71         while(var3.hasNext()) { 72             Class<?> listenerType = (Class)var3.next(); 73             this.addAsRegistrationBean(beanFactory, EventListener.class, listenerType, new ServletContextInitializerBeans.ServletListenerRegistrationBeanAdapter(null)); 74  } 75 
76  } 77     
78     public Iterator<ServletContextInitializer> iterator() { 79         //返回全部的ServletContextInitializer
80         return this.sortedList.iterator(); 81  } 82 
83     //略...
84 }

咱們看到ServletContextInitializerBeans 中有一個存放全部ServletContextInitializer的集合sortedList,就是在其構造方法中獲取全部的ServletContextInitializer,並放入sortedList集合中,那咱們來看看其構造方法的邏輯,看到第8行先調用

addServletContextInitializerBeans方法:  

1 private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) { 2     //從Spring容器中獲取全部ServletContextInitializer.class 類型的Bean
3     for (Entry<String, ServletContextInitializer> initializerBean : getOrderedBeansOfType(beanFactory, ServletContextInitializer.class)) { 4         //添加到具體的集合中 5  addServletContextInitializerBean(initializerBean.getKey(),initializerBean.getValue(), beanFactory); 6  } 7 }

咱們看到先從Spring容器中獲取全部ServletContextInitializer.class 類型的Bean,這裏咱們自定義的ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean就被獲取到了,而後調用addServletContextInitializerBean方法:

 1 private void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer, ListableBeanFactory beanFactory) {  2     //判斷ServletRegistrationBean類型
 3     if (initializer instanceof ServletRegistrationBean) {  4         Servlet source = ((ServletRegistrationBean)initializer).getServlet();  5         //將ServletRegistrationBean加入到集合中  6 this.addServletContextInitializerBean(Servlet.class, beanName, initializer, beanFactory, source);  7     //判斷FilterRegistrationBean類型
 8     } else if (initializer instanceof FilterRegistrationBean) {  9         Filter source = ((FilterRegistrationBean)initializer).getFilter(); 10         //將ServletRegistrationBean加入到集合中 11 this.addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source); 12     } else if (initializer instanceof DelegatingFilterProxyRegistrationBean) { 13         String source = ((DelegatingFilterProxyRegistrationBean)initializer).getTargetBeanName(); 14         this.addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source); 15     } else if (initializer instanceof ServletListenerRegistrationBean) { 16         EventListener source = ((ServletListenerRegistrationBean)initializer).getListener(); 17         this.addServletContextInitializerBean(EventListener.class, beanName, initializer, beanFactory, source); 18     } else { 19         this.addServletContextInitializerBean(ServletContextInitializer.class, beanName, initializer, beanFactory, initializer); 20  } 21 
22 } 23 
24 private void addServletContextInitializerBean(Class<?> type, String beanName, 25  ServletContextInitializer initializer, ListableBeanFactory beanFactory, Object source) { 26     //加入到initializers中
27     this.initializers.add(type, initializer); 28 }

很明顯,判斷從Spring容器中獲取的ServletContextInitializer類型,如ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean,並加入到initializers集合中去,咱們再來看構造器中的另一個方法addAdaptableBeans(beanFactory):

 1 private void addAdaptableBeans(ListableBeanFactory beanFactory) {  2    //從beanFactory獲取全部Servlet.class和Filter.class類型的Bean,並封裝成RegistrationBean對象,加入到集合中
 3     this.addAsRegistrationBean(beanFactory, Servlet.class, new ServletContextInitializerBeans.ServletRegistrationBeanAdapter(multipartConfig));  4     this.addAsRegistrationBean(beanFactory, Filter.class, new ServletContextInitializerBeans.FilterRegistrationBeanAdapter(null));  5 }  6 
 7 private <T, B extends T> void addAsRegistrationBean(ListableBeanFactory beanFactory, Class<T> type, Class<B> beanType, ServletContextInitializerBeans.RegistrationBeanAdapter<T> adapter) {  8 //從Spring容器中獲取全部的Servlet.class和Filter.class類型的Bean  9 List<Entry<String, B>> beans = this.getOrderedBeansOfType(beanFactory, beanType, this.seen); 10     Iterator var6 = beans.iterator(); 11 
12     while(var6.hasNext()) { 13         Entry<String, B> bean = (Entry)var6.next(); 14         if (this.seen.add(bean.getValue())) { 15             int order = this.getOrder(bean.getValue()); 16             String beanName = (String)bean.getKey(); 17            //建立Servlet.class和Filter.class包裝成RegistrationBean對象 18 RegistrationBean registration = adapter.createRegistrationBean(beanName, bean.getValue(), beans.size()); 19  registration.setName(beanName); 20  registration.setOrder(order); 21           this.initializers.add(type, registration); 22             if (logger.isDebugEnabled()) { 23                 logger.debug("Created " + type.getSimpleName() + " initializer for bean '" + beanName + "'; order=" + order + ", resource=" + this.getResourceDescription(beanName, beanFactory)); 24  } 25  } 26  } 27 
28 }

咱們看到先從beanFactory獲取全部Servlet.class和Filter.class類型的Bean,而後經過ServletRegistrationBeanAdapter和FilterRegistrationBeanAdapter兩個適配器將Servlet.class和Filter.class封裝成RegistrationBean

private static class ServletRegistrationBeanAdapter implements ServletContextInitializerBeans.RegistrationBeanAdapter<Servlet> { private final MultipartConfigElement multipartConfig; ServletRegistrationBeanAdapter(MultipartConfigElement multipartConfig) { this.multipartConfig = multipartConfig; } public RegistrationBean createRegistrationBean(String name, Servlet source, int totalNumberOfSourceBeans) { String url = totalNumberOfSourceBeans == 1 ? "/" : "/" + name + "/"; if (name.equals("dispatcherServlet")) { url = "/"; } //仍是將Servlet.class實例封裝成ServletRegistrationBean對象 //這和咱們本身建立ServletRegistrationBean對象是如出一轍的 ServletRegistrationBean bean = new ServletRegistrationBean(source, new String[]{url}); bean.setMultipartConfig(this.multipartConfig); return bean; } } private static class FilterRegistrationBeanAdapter implements ServletContextInitializerBeans.RegistrationBeanAdapter<Filter> { private FilterRegistrationBeanAdapter() { } public RegistrationBean createRegistrationBean(String name, Filter source, int totalNumberOfSourceBeans) { //Filter.class實例封裝成FilterRegistrationBean對象 return new FilterRegistrationBean(source, new ServletRegistrationBean[0]); } }

代碼中註釋很清楚了仍是將Servlet.class實例封裝成ServletRegistrationBean對象,將Filter.class實例封裝成FilterRegistrationBean對象,這和咱們本身定義ServletRegistrationBean對象是如出一轍的,如今全部的ServletRegistrationBean、FilterRegistrationBean

Servlet.class、Filter.class都添加到List<ServletContextInitializer> sortedList這個集合中去了,接着就是遍歷這個集合,執行其onStartup方法了

ServletContextInitializer的onStartup方法

ServletRegistrationBean

public class ServletRegistrationBean extends RegistrationBean { private static final Log logger = LogFactory.getLog(ServletRegistrationBean.class); private static final String[] DEFAULT_MAPPINGS = new String[]{"/*"}; private Servlet servlet; public void onStartup(ServletContext servletContext) throws ServletException { Assert.notNull(this.servlet, "Servlet must not be null"); String name = this.getServletName(); //調用ServletContext的addServlet
        Dynamic added = servletContext.addServlet(name, this.servlet); } //略...
} private javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, String servletClass, Servlet servlet, Map<String, String> initParams) throws IllegalStateException { if (servletName != null && !servletName.equals("")) { if (!this.context.getState().equals(LifecycleState.STARTING_PREP)) { throw new IllegalStateException(sm.getString("applicationContext.addServlet.ise", new Object[]{this.getContextPath()})); } else { Wrapper wrapper = (Wrapper)this.context.findChild(servletName); if (wrapper == null) { wrapper = this.context.createWrapper(); wrapper.setName(servletName); this.context.addChild(wrapper); } else if (wrapper.getName() != null && wrapper.getServletClass() != null) { if (!wrapper.isOverridable()) { return null; } wrapper.setOverridable(false); } if (servlet == null) { wrapper.setServletClass(servletClass); } else { wrapper.setServletClass(servlet.getClass().getName()); wrapper.setServlet(servlet); } if (initParams != null) { Iterator i$ = initParams.entrySet().iterator(); while(i$.hasNext()) { Entry<String, String> initParam = (Entry)i$.next(); wrapper.addInitParameter((String)initParam.getKey(), (String)initParam.getValue()); } } return this.context.dynamicServletAdded(wrapper); } } else { throw new IllegalArgumentException(sm.getString("applicationContext.invalidServletName", new Object[]{servletName})); } }

看到沒,ServletRegistrationBean 中的 onStartup先獲取Servlet的name,而後調用ServletContext的addServlet將Servlet加入到Tomcat中,這樣咱們就能發請求給這個Servlet了。

AbstractFilterRegistrationBean

public void onStartup(ServletContext servletContext) throws ServletException { Filter filter = this.getFilter(); Assert.notNull(filter, "Filter must not be null");  String name = this.getOrDeduceName(filter); //調用ServletContext的addFilter Dynamic added = servletContext.addFilter(name, filter); }

AbstractFilterRegistrationBean也是一樣的原理,先獲取目標Filter,而後調用ServletContext的addFilter將Filter加入到Tomcat中,這樣Filter就能攔截咱們請求了。

DispatcherServletAutoConfiguration

最熟悉的莫過於,在Spring Boot在自動配置SpringMVC的時候,會自動註冊SpringMVC前端控制器: DispatcherServlet,該控制器主要在 DispatcherServletAutoConfiguration自動配置類中進行註冊的。DispatcherServlet是SpringMVC中的核心分發器。DispatcherServletAutoConfiguration也在spring.factories中配置了

DispatcherServletConfiguration

 1 @Configuration  2 @ConditionalOnWebApplication  3 // 先看下ClassPath下是否有DispatcherServlet.class字節碼  4 // 咱們引入了spring-boot-starter-web,同時引入了tomcat和SpringMvc,確定會存在DispatcherServlet.class字節碼  5 @ConditionalOnClass({DispatcherServlet.class})  6 // 這個配置類的執行要在EmbeddedServletContainerAutoConfiguration配置類生效以後執行  7 // 畢竟要等Tomcat啓動後才能往其中注入DispatcherServlet  8 @AutoConfigureAfter({EmbeddedServletContainerAutoConfiguration.class})  9 protected static class DispatcherServletConfiguration { 10   public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet"; 11   public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration"; 12  @Autowired 13   private ServerProperties server; 14 
15  @Autowired 16   private WebMvcProperties webMvcProperties; 17 
18   @Autowired(required = false) 19   private MultipartConfigElement multipartConfig; 20 
21   // Spring容器註冊DispatcherServlet 22 @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) 23   public DispatcherServlet dispatcherServlet() { 24    // 直接構造DispatcherServlet,並設置WebMvcProperties中的一些配置 25 DispatcherServlet dispatcherServlet = new DispatcherServlet(); 26     dispatcherServlet.setDispatchOptionsRequest(this.webMvcProperties.isDispatchOptionsRequest()); 27     dispatcherServlet.setDispatchTraceRequest(this.webMvcProperties.isDispatchTraceRequest()); 28     dispatcherServlet.setThrowExceptionIfNoHandlerFound(this.webMvcProperties.isThrowExceptionIfNoHandlerFound()); 29     return dispatcherServlet; 30  } 31 
32   @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME) 33   public ServletRegistrationBean dispatcherServletRegistration() { 34     // 直接使用DispatcherServlet和server配置中的servletPath路徑構造ServletRegistrationBean 35 // ServletRegistrationBean實現了ServletContextInitializer接口,在onStartup方法中對應的Servlet註冊到Servlet容器中 36 // 因此這裏DispatcherServlet會被註冊到Servlet容器中,對應的urlMapping爲server.servletPath配置 37 ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet(), this.server.getServletMapping()); 38  registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME); 39     if (this.multipartConfig != null) { 40       registration.setMultipartConfig(this.multipartConfig); 41  } 42     return registration; 43  } 44 
45   @Bean // 構造文件上傳相關的bean
46   @ConditionalOnBean(MultipartResolver.class) 47   @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) 48   public MultipartResolver multipartResolver(MultipartResolver resolver) { 49     return resolver; 50  } 51 
52 }

先看下ClassPath下是否有DispatcherServlet.class字節碼, 咱們引入了spring-boot-starter-web,同時引入了tomcat和SpringMvc,確定會存在DispatcherServlet.class字節碼,若是沒有導入spring-boot-starter-web,則這個配置類將不會生效

而後往Spring容器中註冊DispatcherServlet實例,接着又加入ServletRegistrationBean實例,並把DispatcherServlet實例做爲參數,上面咱們已經學過了ServletRegistrationBean的邏輯,在Tomcat啓動的時候,會獲取全部的ServletRegistrationBean,並執行其中的onstartup方法,將DispatcherServlet註冊到Servlet容器中,這樣就相似原來的web.xml中配置的dispatcherServlet。

<servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

因此只要導入了spring-boot-starter-web這個starter,SpringBoot就有了Tomcat容器,而且往Tomcat容器中註冊了DispatcherServlet對象,這樣就能接收到咱們的請求了

 
 

 

原文出處:https://www.cnblogs.com/java-chen-hao/p/11842611.html

相關文章
相關標籤/搜索