1. 自定义Servlet、Filter、Listener 1.1 Spring容器中声明ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean 1 2 3 4 5 6 7 8 9 10 11 @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中了。
1.2 @ServletComponentScan注解和@WebServlet、@WebFilter以及@WebListener注解配合使用 @ServletComponentScan注解启用ImportServletComponentScanRegistrar类,是个ImportBeanDefinitionRegistrar接口的实现类,会被Spring容器所解析。ServletComponentScanRegistrar内部会解析@ServletComponentScan注解,然后会在Spring容器中注册ServletComponentRegisteringPostProcessor,是个BeanFactoryPostProcessor,会去解析扫描出来的类是不是有@WebServlet、@WebListener、@WebFilter这3种注解,有的话把这3种类型的类转换成ServletRegistrationBean、FilterRegistrationBean或者ServletListenerRegistrationBean,然后让Spring容器去解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @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"); } }
1.3 在Spring容器中声明Servlet、Filter或者Listener 1 2 3 4 @Bean(name = "dispatcherServlet") public DispatcherServlet myDispatcherServlet() { return new DispatcherServlet(); }
我们发现往Tomcat中添加Servlet、Filter或者Listener还是挺容易的,大家还记得以前SpringMVC是怎么配置DispatcherServlet 的吗?在web.xml中:
1 2 3 4 5 6 7 8 9 10 11 12 13 <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很简单,但是其底层却不简单,下面我们来分析一下其原理
2. ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean 我们来看看这几个特殊的类:
2.1 ServletRegistrationBean 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 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这个类。
2.2 FilterRegistrationBean 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 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对象,并且继承了****RegistrationBean
2.3 ServletListenerRegistrationBean 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 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这个类
1 2 3 4 5 6 public abstract class RegistrationBean implements ServletContextInitializer, Ordered { ... } public interface ServletContextInitializer { void onStartup(ServletContext var1) throws ServletException; }
我们发现RegistrationBean 实现了****ServletContextInitializer这个接口,并且有一个onStartup方法, ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean都实现了onStartup方法。
ServletContextInitializer
是 Servlet 容器初始化的时候,提供的初始化接口。所以,Servlet 容器初始化会获取并触发所有的`FilterRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean实例中onStartup方法
那到底是何时触发这些类的onStartup方法呢?
当Tomcat容器启动时,会执行callInitializers
,然后获取所有的**ServletContextInitializer,循环执行
**onStartup
方法触发回调方法。那FilterRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean实例是何时加入到
Initializers集合的呢?
3. Servlet容器的启动 EmbeddedWebApplicationContext
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 @Override protected void onRefresh() { super.onRefresh(); try { //核心方法:会获取嵌入式的Servlet容器工厂,并通过工厂来获取Servlet容器 createEmbeddedServletContainer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start embedded container", ex); } } private void createEmbeddedServletContainer() { EmbeddedServletContainer localContainer = this.embeddedServletContainer; ServletContext localServletContext = getServletContext(); if (localContainer == null && localServletContext == null) { //先获取嵌入式Servlet容器工厂 EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory(); //根据容器工厂来获取对应的嵌入式Servlet容器 this.embeddedServletContainer = containerFactory.getEmbeddedServletContainer(getSelfInitializer()); } else if (localServletContext != null) { try { getSelfInitializer().onStartup(localServletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context",ex); } } initPropertySources(); }
关键代码在第20行,先通过getSelfInitializer()获取到所有的Initializer,传入Servlet容器中,那核心就在getSelfInitializer()方法:
1 2 3 4 5 6 7 8 9 private ServletContextInitializer getSelfInitializer() { //只是创建了一个ServletContextInitializer实例返回 //所以Servlet容器启动的时候,会调用这个对象的onStartup方法 return new ServletContextInitializer() { public void onStartup(ServletContext servletContext) throws ServletException { EmbeddedWebApplicationContext.this.selfInitialize(servletContext); } }; }
我们看到只是创建了一个ServletContextInitializer实例返回,所以Servlet容器启动的时候,会调用这个对象的onStartup方法,那我们来分析其onStartup中的逻辑,也就是selfInitialize方法,并将Servlet上下文对象传进去了
selfInitialize
1 2 3 4 5 6 7 8 9 10 11 12 13 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()); //这里便是获取所有的 ServletContextInitializer 实现类,会获取所有的注册组件 for (ServletContextInitializer beans : getServletContextInitializerBeans()) { //执行所有ServletContextInitializer的onStartup方法 beans.onStartup(servletContext); } }
关键代码在第9和第11行,先获取所有的ServletContextInitializer 实现类,然后遍历执行所有ServletContextInitializer的onStartup方法
3.1 获取所有的ServletContextInitializer 我们来看看getServletContextInitializerBeans方法
1 2 3 protected Collection<ServletContextInitializer> getServletContextInitializerBeans() { return new ServletContextInitializerBeans(getBeanFactory()); }
ServletContextInitializerBeans对象是对ServletContextInitializer
的一种包装:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 public class ServletContextInitializerBeans extends AbstractCollection<ServletContextInitializer> { private final MultiValueMap<Class<?>, ServletContextInitializer> initializers = new LinkedMultiValueMap(); //存放所有的ServletContextInitializer private List<ServletContextInitializer> sortedList; public ServletContextInitializerBeans(ListableBeanFactory beanFactory) { //执行addServletContextInitializerBeans this.addServletContextInitializerBeans(beanFactory); //执行addAdaptableBeans this.addAdaptableBeans(beanFactory); List<ServletContextInitializer> sortedInitializers = new ArrayList(); Iterator var3 = this.initializers.entrySet().iterator(); while(var3.hasNext()) { Entry<?, List<ServletContextInitializer>> entry = (Entry)var3.next(); AnnotationAwareOrderComparator.sort((List)entry.getValue()); sortedInitializers.addAll((Collection)entry.getValue()); } this.sortedList = Collections.unmodifiableList(sortedInitializers); } private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) { Iterator var2 = this.getOrderedBeansOfType(beanFactory, ServletContextInitializer.class).iterator(); while(var2.hasNext()) { Entry<String, ServletContextInitializer> initializerBean = (Entry)var2.next(); this.addServletContextInitializerBean((String)initializerBean.getKey(), (ServletContextInitializer)initializerBean.getValue(), beanFactory); } } private void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer, ListableBeanFactory beanFactory) { if (initializer instanceof ServletRegistrationBean) { Servlet source = ((ServletRegistrationBean)initializer).getServlet(); this.addServletContextInitializerBean(Servlet.class, beanName, initializer, beanFactory, source); } else if (initializer instanceof FilterRegistrationBean) { Filter source = ((FilterRegistrationBean)initializer).getFilter(); this.addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source); } else if (initializer instanceof DelegatingFilterProxyRegistrationBean) { String source = ((DelegatingFilterProxyRegistrationBean)initializer).getTargetBeanName(); this.addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source); } else if (initializer instanceof ServletListenerRegistrationBean) { EventListener source = ((ServletListenerRegistrationBean)initializer).getListener(); this.addServletContextInitializerBean(EventListener.class, beanName, initializer, beanFactory, source); } else { this.addServletContextInitializerBean(ServletContextInitializer.class, beanName, initializer, beanFactory, initializer); } } private void addServletContextInitializerBean(Class<?> type, String beanName, ServletContextInitializer initializer, ListableBeanFactory beanFactory, Object source) { this.initializers.add(type, initializer); if (source != null) { this.seen.add(source); } if (logger.isDebugEnabled()) { String resourceDescription = this.getResourceDescription(beanName, beanFactory); int order = this.getOrder(initializer); logger.debug("Added existing " + type.getSimpleName() + " initializer bean '" + beanName + "'; order=" + order + ", resource=" + resourceDescription); } } private void addAdaptableBeans(ListableBeanFactory beanFactory) { MultipartConfigElement multipartConfig = this.getMultipartConfig(beanFactory); this.addAsRegistrationBean(beanFactory, Servlet.class, new ServletContextInitializerBeans.ServletRegistrationBeanAdapter(multipartConfig)); this.addAsRegistrationBean(beanFactory, Filter.class, new ServletContextInitializerBeans.FilterRegistrationBeanAdapter(null)); Iterator var3 = ServletListenerRegistrationBean.getSupportedTypes().iterator(); while(var3.hasNext()) { Class<?> listenerType = (Class)var3.next(); this.addAsRegistrationBean(beanFactory, EventListener.class, listenerType, new ServletContextInitializerBeans.ServletListenerRegistrationBeanAdapter(null)); } } public Iterator<ServletContextInitializer> iterator() { //返回所有的ServletContextInitializer return this.sortedList.iterator(); } //略... }
我们看到ServletContextInitializerBeans 中有一个存放所有ServletContextInitializer的集合sortedList,就是在其构造方法中获取所有的ServletContextInitializer,并放入sortedList集合中,那我们来看看其构造方法的逻辑,看到第8行先调用
addServletContextInitializerBeans方法:
1 2 3 4 5 6 7 private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) { //从Spring容器中获取所有ServletContextInitializer.class 类型的Bean for (Entry<String, ServletContextInitializer> initializerBean : getOrderedBeansOfType(beanFactory, ServletContextInitializer.class)) { //添加到具体的集合中 addServletContextInitializerBean(initializerBean.getKey(),initializerBean.getValue(), beanFactory); } }
我们看到先从Spring容器中获取所有ServletContextInitializer.class 类型的Bean,这里我们自定义的ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean就被获取到了,然后调用addServletContextInitializerBean方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 private void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer, ListableBeanFactory beanFactory) { //判断ServletRegistrationBean类型 if (initializer instanceof ServletRegistrationBean) { Servlet source = ((ServletRegistrationBean)initializer).getServlet(); //将ServletRegistrationBean加入到集合中 this.addServletContextInitializerBean(Servlet.class, beanName, initializer, beanFactory, source); //判断FilterRegistrationBean类型 } else if (initializer instanceof FilterRegistrationBean) { Filter source = ((FilterRegistrationBean)initializer).getFilter(); //将ServletRegistrationBean加入到集合中 this.addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source); } else if (initializer instanceof DelegatingFilterProxyRegistrationBean) { String source = ((DelegatingFilterProxyRegistrationBean)initializer).getTargetBeanName(); this.addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source); } else if (initializer instanceof ServletListenerRegistrationBean) { EventListener source = ((ServletListenerRegistrationBean)initializer).getListener(); this.addServletContextInitializerBean(EventListener.class, beanName, initializer, beanFactory, source); } else { this.addServletContextInitializerBean(ServletContextInitializer.class, beanName, initializer, beanFactory, initializer); } } private void addServletContextInitializerBean(Class<?> type, String beanName, ServletContextInitializer initializer, ListableBeanFactory beanFactory, Object source) { //加入到initializers中 this.initializers.add(type, initializer); }
很明显,判断从Spring容器中获取的ServletContextInitializer类型,如ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean,并加入到initializers集合中去,我们再来看构造器中的另外一个方法addAdaptableBeans(beanFactory):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 private void addAdaptableBeans(ListableBeanFactory beanFactory) { //从beanFactory获取所有Servlet.class和Filter.class类型的Bean,并封装成RegistrationBean对象,加入到集合中 this.addAsRegistrationBean(beanFactory, Servlet.class, new ServletContextInitializerBeans.ServletRegistrationBeanAdapter(multipartConfig)); this.addAsRegistrationBean(beanFactory, Filter.class, new ServletContextInitializerBeans.FilterRegistrationBeanAdapter(null)); } private <T, B extends T> void addAsRegistrationBean(ListableBeanFactory beanFactory, Class<T> type, Class<B> beanType, ServletContextInitializerBeans.RegistrationBeanAdapter<T> adapter) { //从Spring容器中获取所有的Servlet.class和Filter.class类型的Bean List<Entry<String, B>> beans = this.getOrderedBeansOfType(beanFactory, beanType, this.seen); Iterator var6 = beans.iterator(); while(var6.hasNext()) { Entry<String, B> bean = (Entry)var6.next(); if (this.seen.add(bean.getValue())) { int order = this.getOrder(bean.getValue()); String beanName = (String)bean.getKey(); //创建Servlet.class和Filter.class包装成RegistrationBean对象 RegistrationBean registration = adapter.createRegistrationBean(beanName, bean.getValue(), beans.size()); registration.setName(beanName); registration.setOrder(order); this.initializers.add(type, registration); if (logger.isDebugEnabled()) { logger.debug("Created " + type.getSimpleName() + " initializer for bean '" + beanName + "'; order=" + order + ", resource=" + this.getResourceDescription(beanName, beanFactory)); } } } }
我们看到先从beanFactory获取所有Servlet.class和Filter.class类型的Bean,然后通过ServletRegistrationBeanAdapter和FilterRegistrationBeanAdapter两个适配器将Servlet.class和Filter.class封装成 RegistrationBean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 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 sortedList这个集合中去了,接着就是遍历这个集合,执行其onStartup 方法了
3.2 ServletContextInitializer的onStartup方法 ServletRegistrationBean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 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
1 2 3 4 5 6 7 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就能拦截我们请求了。
4. DispatcherServletAutoConfiguration 最熟悉的莫过于,在Spring Boot在自动配置SpringMVC的时候,会自动注册SpringMVC前端控制器:DispatcherServlet ,该控制器主要在DispatcherServletAutoConfiguration 自动配置类中进行注册的。DispatcherServlet是SpringMVC中的核心分发器。DispatcherServletAutoConfiguration也在spring.factories中配置了
DispatcherServletConfiguration
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 @Configuration @ConditionalOnWebApplication // 先看下ClassPath下是否有DispatcherServlet.class字节码 // 我们引入了spring-boot-starter-web,同时引入了tomcat和SpringMvc,肯定会存在DispatcherServlet.class字节码 @ConditionalOnClass({DispatcherServlet.class}) // 这个配置类的执行要在EmbeddedServletContainerAutoConfiguration配置类生效之后执行 // 毕竟要等Tomcat启动后才能往其中注入DispatcherServlet @AutoConfigureAfter({EmbeddedServletContainerAutoConfiguration.class}) protected static class DispatcherServletConfiguration { public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet"; public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration"; @Autowired private ServerProperties server; @Autowired private WebMvcProperties webMvcProperties; @Autowired(required = false) private MultipartConfigElement multipartConfig; // Spring容器注册DispatcherServlet @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet() { // 直接构造DispatcherServlet,并设置WebMvcProperties中的一些配置 DispatcherServlet dispatcherServlet = new DispatcherServlet(); dispatcherServlet.setDispatchOptionsRequest(this.webMvcProperties.isDispatchOptionsRequest()); dispatcherServlet.setDispatchTraceRequest(this.webMvcProperties.isDispatchTraceRequest()); dispatcherServlet.setThrowExceptionIfNoHandlerFound(this.webMvcProperties.isThrowExceptionIfNoHandlerFound()); return dispatcherServlet; } @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME) public ServletRegistrationBean dispatcherServletRegistration() { // 直接使用DispatcherServlet和server配置中的servletPath路径构造ServletRegistrationBean // ServletRegistrationBean实现了ServletContextInitializer接口,在onStartup方法中对应的Servlet注册到Servlet容器中 // 所以这里DispatcherServlet会被注册到Servlet容器中,对应的urlMapping为server.servletPath配置 ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet(), this.server.getServletMapping()); registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME); if (this.multipartConfig != null) { registration.setMultipartConfig(this.multipartConfig); } return registration; } @Bean // 构造文件上传相关的bean @ConditionalOnBean(MultipartResolver.class) @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) public MultipartResolver multipartResolver(MultipartResolver resolver) { return resolver; } }
先看下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。
1 2 3 4 5 6 7 8 9 <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对象,这样就能接收到我们的请求了