概述
该类位于包 :
org.springframework.boot.web.servlet
ServletContextInitializerBeans实例表示一个从ListableBeanFactory bean容器中获得的ServletContextInitializer实例的集合。这个集合中的每个元素来自容器中定义的每个如下类型的bean :
-
ServletContextInitializer bean,
- 具体可能以ServletRegistrationBean/FilterRegistrationBean/EventListenerRegistrationBean的形式存在
- 这些 bean 设计的目的是用来注册相应的 Servlet/Filter/EventListener bean 到 ServletContext
-
Servlet/Filter/EventListener bean
- 这些 bean直接以Servlet/Filter/EventListener bean的形式存在
- 但是Springboot将它们封装成相应的 RegistrationBean(也是ServletContextInitializer ),然后也注册到ServletContext
所有这些bean最终都会以 ServletContextInitializer 形式在随后Servlet容器启动阶段ServletContext创建后应用于初始化ServletContext。
在完全使用缺省配置的 Springboot Web应用中,其应用逻辑如下 :
// 类 org.springframework.boot.context.embedded.EmbeddedWebApplicationContext方法
// 在具体的内置Servlet容器启动过程中,Servlet上下文创建之后,
// Spring EmbeddedWebApplicationContext 使用 bean 容器中定义的ServletContextInitializer对
// Servlet上下文进行初始化。
private void selfInitialize(ServletContext servletContext) throws ServletException {
prepareEmbeddedWebApplicationContext(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); // <--- 将各个SCI应用到servletContext
}
}
// 返回需要在内置Servlet Context上应用的ServletContextInitializer bean。
// 缺省情况下,该方法先找直接定义为ServletContextInitializer的bean,然后是定义为Servlet,
// Filter,EventListener的bean,将它们封装成 ServletContextInitializer bean,
// 排序然后一并返回,排序算法使用 AnnotationAwareOrderComparator。
protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
return new ServletContextInitializerBeans(getBeanFactory());
}
完整的调用链如下 :
- 首先,在主线程中,Springboot启动过程交给内置Tomcat Servlet 容器一个ServletContextInitializer :
SpringApplication.run()
=> refreshContext()
=> EmbeddedWebApplicationContext.refresh()
=> onRefresh()
=> createEmbeddedServletContainer()
- 然后,在内置Tomcat Servlet容器启动线程中,ServletContext创建之后调用该ServletContextInitializer :
StandartContext.startInternal()
=> TomcatStarter.onStartup()
=> EmbeddedWebApplicationContext.selfInitialize()
// containerFactory.getEmbeddedServletContainer(getSelfInitializer());
如果你想知道为什么上面出现了两个线程,请参考 :
缺省配置Springboot Web应用中tomcat的启动过程
源代码分析
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.web.servlet;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.EventListener;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.Filter;
import javax.servlet.MultipartConfigElement;
import javax.servlet.Servlet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* A collection ServletContextInitializers obtained from a
* ListableBeanFactory. Includes all ServletContextInitializer beans and
* also adapts Servlet, Filter and certain EventListener beans.
*
* Items are sorted so that adapted beans are top (Servlet,Filter then
* EventListener) and direct ServletContextInitializer beans are at the
* end. Further sorting is applied within these groups using the
* AnnotationAwareOrderComparator.
*
* @author Dave Syer
* @author Phillip Webb
* @since 1.4.0
*/
public class ServletContextInitializerBeans
extends AbstractCollection<ServletContextInitializer> {
// Spring MVC 前端控制器Servlet固定使用的的名字,这里为什么要定义这个名字 ?因为该类中
// 的逻辑要使用该名字找到Spring MVC前端控制器Servlet并对其做特定的处理。
private static final String DISPATCHER_SERVLET_NAME = "dispatcherServlet";
private static final Log logger = LogFactory
.getLog(ServletContextInitializerBeans.class);
/**
* 记录已经发现的 bean, 主要用于排除同一个目标bean被重复处理
* Seen bean instances or bean names.
*/
private final Set<Object> seen = new HashSet<Object>();
// 保存所有从 beanFactory中获得的 ServletContextInitializer 实例,
// 每个Entry的key是一个类,value对应一个或者多个属于该类的 ServletContextInitializer 实例
private final MultiValueMap<Class<?>, ServletContextInitializer> initializers;
// 将所有获得的 ServletContextInitializer 实例排序后保存在这里,具体的排序算法看下面的分析
private List<ServletContextInitializer> sortedList;
// 构造函数要求参数是 beanFactory,表明所有目标ServletContextInitializer bean都将来自于
// 该 beanFactory
public ServletContextInitializerBeans(ListableBeanFactory beanFactory) {
// 创建的空的 ServletContextInitializer map initializers,
// 并从 beanFactory 获取所有实现了 ServletContextInitializer 接口的bean,
// 然后记录到该 ServletContextInitializer map initializers
this.initializers = new LinkedMultiValueMap<Class<?>, ServletContextInitializer>();
// 完全缺省配置的Springboot Web应用,其实只会有一个 :
// 注册 dispatcherServlet的dispatcherServletRegistration
addServletContextInitializerBeans(beanFactory);
// 从 beanFactory 获取相应的 Servlet,Filter, EventListener bean实例,然后
// 构造相应的RegistrationBean,记录到ServletContextInitializer map initializers
addAdaptableBeans(beanFactory);
// 现在已经从 beanFactory 分析出所有的 ServletContextInitializer,他们都在
// map initializers 每个 Entry的 value 中。现在将他们从 map 中取出,使用
// AnnotationAwareOrderComparator 排序,然后都添加到 sortedInitializers
List<ServletContextInitializer> sortedInitializers = new ArrayList<ServletContextInitializer>();
for (Map.Entry<?, List<ServletContextInitializer>> entry : this.initializers
.entrySet()) {
AnnotationAwareOrderComparator.sort(entry.getValue());
sortedInitializers.addAll(entry.getValue());
}
this.sortedList = Collections.unmodifiableList(sortedInitializers);
}
// 从 beanFactory 获取所有实现了 ServletContextInitializer 接口的bean,
// 然后记录到该 ServletContextInitializer map initializers
private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
for (Entry<String, ServletContextInitializer> initializerBean : getOrderedBeansOfType(
beanFactory, ServletContextInitializer.class)) {
addServletContextInitializerBean(initializerBean.getKey(),
initializerBean.getValue(), beanFactory);
}
}
/**
* beanName bean 的名称
* initializer 将要处理的ServletContextInitializer bean实例,
* beanFactory bean容器
*/
private void addServletContextInitializerBean(String beanName,
ServletContextInitializer initializer, ListableBeanFactory beanFactory) {
if (initializer instanceof ServletRegistrationBean) {
// 参数 initializer 是一个 ServletRegistrationBean 的情况
Servlet source = ((ServletRegistrationBean) initializer).getServlet();
addServletContextInitializerBean(Servlet.class, beanName, initializer,
beanFactory, source);
}
else if (initializer instanceof FilterRegistrationBean) {
// 参数 initializer 是一个 FilterRegistrationBean 的情况
Filter source = ((FilterRegistrationBean) initializer).getFilter();
addServletContextInitializerBean(Filter.class, beanName, initializer,
beanFactory, source);
}
// 参数 initializer 是一个 DelegatingFilterProxyRegistrationBean 的情况
else if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
String source = ((DelegatingFilterProxyRegistrationBean) initializer)
.getTargetBeanName();
addServletContextInitializerBean(Filter.class, beanName, initializer,
beanFactory, source);
}
else if (initializer instanceof ServletListenerRegistrationBean) {
// 参数 initializer 是一个 ServletListenerRegistrationBean 的情况
EventListener source = ((ServletListenerRegistrationBean<?>) initializer)
.getListener();
addServletContextInitializerBean(EventListener.class, beanName, initializer,
beanFactory, source);
}
else {
// 参数 initializer 不属于上各种情况的话,直接使用类型 ServletContextInitializer 记录
addServletContextInitializerBean(ServletContextInitializer.class, beanName,
initializer, beanFactory, initializer);
}
}
/**
* type : 将要把ServletContextInitializer bean initializer使用哪种类型来记录
* beanName : initializer bean的名称
* beanFactory : bean容器
* source : initializer bean中所要注册的Servlet/Filter/EventListener对象
**/
private void addServletContextInitializerBean(Class<?> type, String beanName,
ServletContextInitializer initializer, ListableBeanFactory beanFactory,
Object source) {
this.initializers.add(type, initializer);
if (source != null) {
// 如果指定了source,也就是initializer所对应的Servlet或者Filter或者EventListener
// 对象,将它记到 seen, 表示对该对象已经做了处理,随后对其他initializer的处理过程中
// 如果发现其对应的Servlet或者Filter或者EventListener如果已经在 seen 中,则不再
// 重复处理
// Mark the underlying source as seen in case it wraps an existing bean
this.seen.add(source);
}
if (ServletContextInitializerBeans.logger.isDebugEnabled()) {
// 调试模式下的日志输出逻辑
String resourceDescription = getResourceDescription(beanName, beanFactory);
int order = getOrder(initializer);
ServletContextInitializerBeans.logger.debug("Added existing "
+ type.getSimpleName() + " initializer bean '" + beanName
+ "'; order=" + order + ", resource=" + resourceDescription);
}
}
// 用于调试模式下的日志输出
private String getResourceDescription(String beanName,
ListableBeanFactory beanFactory) {
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
return registry.getBeanDefinition(beanName).getResourceDescription();
}
return "unknown";
}
// 添加适配器bean到initializers
@SuppressWarnings("unchecked")
private void addAdaptableBeans(ListableBeanFactory beanFactory) {
// 获取bean容器中的 MultipartConfigElement bean定义,文件上传相关的配置bean
MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);
// 完全采用缺省配置的Springboot Web应用,会处理0个Servlet,
// 因为唯一一个 DispatcherServlet已经被addServletContextInitializerBeans()处理
addAsRegistrationBean(beanFactory, Servlet.class,
new ServletRegistrationBeanAdapter(multipartConfig));
// 完全采用缺省配置的Springboot Web应用,会处理4个Filter,它们分别是 :
// 0 characterEncodingFilter
// 1 hiddenHttpMethodFilter
// 2 httpPutFormContentFilter
// 3 requestContextFilter
addAsRegistrationBean(beanFactory, Filter.class,
new FilterRegistrationBeanAdapter());
for (Class<?> listenerType : ServletListenerRegistrationBean
.getSupportedTypes()) {
addAsRegistrationBean(beanFactory, EventListener.class,
(Class<EventListener>) listenerType,
new ServletListenerRegistrationBeanAdapter());
}
}
// 找到注册到容器中的MultipartConfigElement bean,如果有多个,则排序后返回第一个,
// 排序方法是 AnnotationAwareOrderComparator
private MultipartConfigElement getMultipartConfig(ListableBeanFactory beanFactory) {
List<Entry<String, MultipartConfigElement>> beans = getOrderedBeansOfType(
beanFactory, MultipartConfigElement.class);
return (beans.isEmpty() ? null : beans.get(0).getValue());
}
private <T> void addAsRegistrationBean(ListableBeanFactory beanFactory, Class<T> type,
RegistrationBeanAdapter<T> adapter) {
addAsRegistrationBean(beanFactory, type, type, adapter);
}
/**
*
* @beanFactory bean容器
* @type 将要记录到 initializers 的 RegistrationBean 所要注册的 bean 的类型
* @beanType bean的类型 ,一般和 type 一样
* @adapter RegistrationBeanAdapter,注册该bean的适配器,添加一些适配逻辑然后返回一个RegistrationBean
**/
private <T, B extends T> void addAsRegistrationBean(ListableBeanFactory beanFactory,
Class<T> type, Class<B> beanType, RegistrationBeanAdapter<T> adapter) {
List<Map.Entry<String, B>> beans = getOrderedBeansOfType(beanFactory, beanType,
this.seen);
for (Entry<String, B> bean : beans) {
if (this.seen.add(bean.getValue())) {
int order = getOrder(bean.getValue());
String beanName = bean.getKey();
// One that we haven't already seen
// 使用指定的适配器将要注册的bean封装成一个RegistrationBean ,然后记录到 initializers
RegistrationBean registration = adapter.createRegistrationBean(beanName,
bean.getValue(), beans.size());
registration.setName(beanName);
registration.setOrder(order);
this.initializers.add(type, registration);
if (ServletContextInitializerBeans.logger.isDebugEnabled()) {
ServletContextInitializerBeans.logger.debug(
"Created " + type.getSimpleName() + " initializer for bean '"
+ beanName + "'; order=" + order + ", resource="
+ getResourceDescription(beanName, beanFactory));
}
}
}
}
private int getOrder(Object value) {
return new AnnotationAwareOrderComparator() {
@Override
public int getOrder(Object obj) {
return super.getOrder(obj);
}
}.getOrder(value);
}
// 从 beanFactory 中获取所有属于类型 type 的 bean,
// 结果List使用排序器 AnnotationAwareOrderComparator 排序后返回
private <T> List<Entry<String, T>> getOrderedBeansOfType(
ListableBeanFactory beanFactory, Class<T> type) {
return getOrderedBeansOfType(beanFactory, type, Collections.emptySet());
}
// 从 beanFactory 中获取所有属于类型 type 但是又不属于集合 excludes 的 bean,
// 结果List使用排序器 AnnotationAwareOrderComparator 排序后返回
private <T> List<Entry<String, T>> getOrderedBeansOfType(
ListableBeanFactory beanFactory, Class<T> type, Set<?> excludes) {
List<Entry<String, T>> beans = new ArrayList<Entry<String, T>>();
Comparator<Entry<String, T>> comparator = new Comparator<Entry<String, T>>() {
@Override
public int compare(Entry<String, T> o1, Entry<String, T> o2) {
return AnnotationAwareOrderComparator.INSTANCE.compare(o1.getValue(),
o2.getValue());
}
};
// 返回 beanFactory 中所有类型类 type 的 bean 的名称,可能为空,也可能多个值
String[] names = beanFactory.getBeanNamesForType(type, true, false);
// 准备返回数据,map格式
Map<String, T> map = new LinkedHashMap<String, T>();
// 逐一检查每个bean是否需要被排除,如果不需要被排除,将它们添加到结果 map
for (String name : names) {
if (!excludes.contains(name) && !ScopedProxyUtils.isScopedTarget(name)) {
T bean = beanFactory.getBean(name, type);
if (!excludes.contains(bean)) {
map.put(name, bean);
}
}
}
// 将结果map中所有 Entry 添加到结果list然后执行排序,在Entry的value上应用
// AnnotationAwareOrderComparator
beans.addAll(map.entrySet());
Collections.sort(beans, comparator);
return beans;
}
@Override
public Iterator<ServletContextInitializer> iterator() {
return this.sortedList.iterator();
}
@Override
public int size() {
return this.sortedList.size();
}
/**
* Adapter to convert a given Bean type into a RegistrationBean (and hence a
* ServletContextInitializer.
* 将一个Bean转化成一个RegistrationBean的适配器接口,RegistrationBean实现了
* ServletContextInitializer 接口
*/
private interface RegistrationBeanAdapter<T> {
/**
* name, 将要注册的bean的名称
* source , 将要注册的 bean的实例
* totalNumberOfSourceBeans , 将要注册的 bean 的个数
**/
RegistrationBean createRegistrationBean(String name, T source,
int totalNumberOfSourceBeans);
}
/**
* RegistrationBeanAdapter for Servlet beans.
*/
private static class ServletRegistrationBeanAdapter
implements RegistrationBeanAdapter<Servlet> {
private final MultipartConfigElement multipartConfig;
ServletRegistrationBeanAdapter(MultipartConfigElement multipartConfig) {
this.multipartConfig = multipartConfig;
}
@Override
public RegistrationBean createRegistrationBean(String name, Servlet source,
int totalNumberOfSourceBeans) {
String url = (totalNumberOfSourceBeans == 1 ? "/" : "/" + name + "/");
if (name.equals(DISPATCHER_SERVLET_NAME)) {
// 对 dispatcherServlet 的特殊处理,总是映射到 /
url = "/"; // always map the main dispatcherServlet to "/"
}
ServletRegistrationBean bean = new ServletRegistrationBean(source, url);
bean.setMultipartConfig(this.multipartConfig);
return bean;
}
}
/**
* RegistrationBeanAdapter for Filter beans.
*/
private static class FilterRegistrationBeanAdapter
implements RegistrationBeanAdapter<Filter> {
@Override
public RegistrationBean createRegistrationBean(String name, Filter source,
int totalNumberOfSourceBeans) {
return new FilterRegistrationBean(source);
}
}
/**
* RegistrationBeanAdapter for certain EventListener beans.
*/
private static class ServletListenerRegistrationBeanAdapter
implements RegistrationBeanAdapter<EventListener> {
@Override
public RegistrationBean createRegistrationBean(String name, EventListener source,
int totalNumberOfSourceBeans) {
return new ServletListenerRegistrationBean<EventListener>(source);
}
}
}