在启动spring boot工程时利用@SpringBootApplication注解,该注解启动@EnableAutoConfiguration自动配置,加载META-INF/spring.factories文件
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,...
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration, ...
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
其中EmbeddedServletContainerAutoConfiguration被加载
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration {
...
}
@ConditionalOnWebApplication注解表明只有在web环境下才会创建容器相关信息,因此应用无需容器则使用
new SpringApplicationBuilder(Xxx.class).web(false).run(args)实现。
TomcatEmbeddedServletContainerFactory.java
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory();
}
}
优先创建TomcatEmbeddedServletContainerFactory,由于存在@ConditionalOnMissingBean因此优先使用用户自定义的EmbeddedServletContainerFactory,
此时创建了工厂,但是tomcat是如何启动的呢?
在spring boot中常使用的上下文为AnnotationConfigEmbeddedWebApplicationContext,通过前面的文章也知道加载BeanDefinition是在
AbstractApplicationContext#refresh()方法中,具体详细的实现可以参考这里1 2,有阅读源码的备注信息.
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) { //同步锁
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory); //为BeanFactory设置后处理器,用依拓展
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory); //执行BeanFactoryPostProcessor,因此在执行BeanFactoryPostProcessor子类时,bean是没有被实例化的
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset ‘active‘ flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring‘s core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches(); //释放缓存
}
}
}
其中的onRefresh();交由子类实现EmbeddedWebApplicationContext(public class AnnotationConfigEmbeddedWebApplicationContext )
extends EmbeddedWebApplicationContext
@Override
protected void onRefresh() {
super.onRefresh();
try {
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) {
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory(); //获取自动加载的工厂
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();
}
getEmbeddedServletContainerFactory 获取容器工厂,通过
containerFactory.getEmbeddedServletContainer(getSelfInitializer());
创建一个内建容器,这里的getSelfInitializer()返回一个ServletContextInitializer,其实现为
return new ServletContextInitializer() {
@Override
prepareContext(tomcat.getHost(), initializers); public void onStartup(ServletContext servletContext) throws ServletException {
selfInitialize(servletContext);
}
}; customizer.customize(bean)
其中的selfInitialize(servletContext);等后续再回过来看,这里很关键。
继续看containerFactory.getEmbeddedServletContainer(getSelfInitializer());方法,默认调用TomcatEmbeddedServletContainerFactory中的方法:
@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat(); //构建tomcat实例
File baseDir = (this.baseDirectory != null ? this.baseDirectory
: createTempDir("tomcat"));
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
tomcat.getEngine().setBackgroundProcessorDelay(-1);
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatEmbeddedServletContainer(tomcat);
}
首先构造一个tomcat实例,设置connector信息,在customizeConnector(connector)中会设置端口等其他配置信息,那么有个疑问来了,tomcat中的配置信息是怎么加载的?
那么又要回到EmbeddedServletContainerAutoConfiguration类,其申明@Import(BeanPostProcessorsRegistrar.class),那么需要看下BeanPostProcessorsRegistrar,其实现很简单
public static class BeanPostProcessorsRegistrar
implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
/**
* 在解析import的时候自动绑定各种aware
* @param beanFactory
* @throws BeansException
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (beanFactory instanceof ConfigurableListableBeanFactory) {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if (this.beanFactory == null) {
return;
}
if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(
EmbeddedServletContainerCustomizerBeanPostProcessor.class, true,
false))) {
registry.registerBeanDefinition(
"embeddedServletContainerCustomizerBeanPostProcessor",
new RootBeanDefinition(
EmbeddedServletContainerCustomizerBeanPostProcessor.class));
}
if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(
ErrorPageRegistrarBeanPostProcessor.class, true, false))) {
registry.registerBeanDefinition("errorPageRegistrarBeanPostProcessor",
new RootBeanDefinition(
ErrorPageRegistrarBeanPostProcessor.class));
}
}
}
在registerBeanDefinitions注册了一个名称为embeddedServletContainerCustomizerBeanPostProcessor的bean,其类型为EmbeddedServletContainerCustomizerBeanPostProcessor(在自定义Beandefinition时可以采用BeanDefinitionBuilder工具类),该bean为一个bean的后处理器
public class EmbeddedServletContainerCustomizerBeanPostProcessor
implements BeanPostProcessor, ApplicationContextAware {
}
覆写postProcessBeforeInitialization和postProcessAfterInitialization方法,其大概的调用顺序可以简单理解为:
调用顺序
BeanFactoryPostProcessor#postProcessBeanFactory ->
构造方法 ->
ApplicationContextAware#setApplicationContext ->
BeanPostProcessor#postProcessBeforeInitialization->
PostConstruct注解方法 ->
InitializingBean#afterPropertiesSet ->
BeanPostProcessor#postProcessAfterInitialization
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof ConfigurableEmbeddedServletContainer) {
postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
}
return bean;
}
调用postProcessBeforeInitialization方法
private void postProcessBeforeInitialization(
ConfigurableEmbeddedServletContainer bean) {
for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) { //
customizer.customize(bean);
}
}
需要获取getCustomizers
private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {
if (this.customizers == null) {
// Look up does not include the parent context
this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
this.applicationContext
.getBeansOfType(EmbeddedServletContainerCustomizer.class,
false, false)
.values());
Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
this.customizers = Collections.unmodifiableList(this.customizers);
}
return this.customizers;
}
获取EmbeddedServletContainerCustomizer类型的bean,调用其customizer.customize(bean),那么来看下ServerProperties的实现
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties
implements EmbeddedServletContainerCustomizer, EnvironmentAware, Ordered {
}
其customize方法为
public void customize(ConfigurableEmbeddedServletContainer container) {
if (getPort() != null) {
container.setPort(getPort());
}
if (getAddress() != null) {
container.setAddress(getAddress());
}
if (getContextPath() != null) {
container.setContextPath(getContextPath());
}
if (getDisplayName() != null) {
container.setDisplayName(getDisplayName());
}
if (getSession().getTimeout() != null) {
container.setSessionTimeout(getSession().getTimeout());
}
container.setPersistSession(getSession().isPersistent());
container.setSessionStoreDir(getSession().getStoreDir());
if (getSsl() != null) {
container.setSsl(getSsl());
}
if (getJspServlet() != null) {
container.setJspServlet(getJspServlet());
}
if (getCompression() != null) {
container.setCompression(getCompression());
}
container.setServerHeader(getServerHeader());
if (container instanceof TomcatEmbeddedServletContainerFactory) {
getTomcat().customizeTomcat(this,
(TomcatEmbeddedServletContainerFactory) container);
}
if (container instanceof JettyEmbeddedServletContainerFactory) {
getJetty().customizeJetty(this,
(JettyEmbeddedServletContainerFactory) container);
}
if (container instanceof UndertowEmbeddedServletContainerFactory) {
getUndertow().customizeUndertow(this,
(UndertowEmbeddedServletContainerFactory) container);
}
container.addInitializers(new SessionConfiguringInitializer(this.session));
container.addInitializers(new InitParameterConfiguringServletContextInitializer(
getContextParameters()));
}
为container设置了各种属性值,至此,内嵌容器属性赋值解释完毕,继续看前面的prepareContext(tomcat.getHost(), initializers);方法
protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
File docBase = getValidDocumentRoot();
docBase = (docBase != null ? docBase : createTempDir("tomcat-docbase"));
TomcatEmbeddedContext context = new TomcatEmbeddedContext(); //上下文,继承StandardContext
context.setName(getContextPath());
context.setDisplayName(getDisplayName());
context.setPath(getContextPath());
context.setDocBase(docBase.getAbsolutePath());
context.addLifecycleListener(new FixContextListener());
context.setParentClassLoader(
this.resourceLoader != null ? this.resourceLoader.getClassLoader()
: ClassUtils.getDefaultClassLoader());
try {
context.setUseRelativeRedirects(false);
context.setMapperContextRootRedirectEnabled(true);
}
catch (NoSuchMethodError ex) {
// Tomcat is < 8.0.30. Continue
}
SkipPatternJarScanner.apply(context, this.tldSkip);
WebappLoader loader = new WebappLoader(context.getParentClassLoader());
loader.setLoaderClass(TomcatEmbeddedWebappClassLoader.class.getName());
loader.setDelegate(true);
context.setLoader(loader);
if (isRegisterDefaultServlet()) {
addDefaultServlet(context);
}
if (shouldRegisterJspServlet()) {
addJspServlet(context);
addJasperInitializer(context);
context.addLifecycleListener(new StoreMergedWebXmlListener());
}
ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
configureContext(context, initializersToUse);
host.addChild(context);
postProcessContext(context);
}
首先设置TomcatEmbeddedContext上下文,它为StandardContext子类,后续设置上下文的若干属性,例如上下文路径等,
执行configureContext
protected void configureContext(Context context,
ServletContextInitializer[] initializers) {
TomcatStarter starter = new TomcatStarter(initializers);
if (context instanceof TomcatEmbeddedContext) {
// Should be true
((TomcatEmbeddedContext) context).setStarter(starter);
}
context.addServletContainerInitializer(starter, NO_CLASSES);
for (LifecycleListener lifecycleListener : this.contextLifecycleListeners) {
context.addLifecycleListener(lifecycleListener);
}
for (Valve valve : this.contextValves) {
context.getPipeline().addValve(valve);
}
for (ErrorPage errorPage : getErrorPages()) {
new TomcatErrorPage(errorPage).addToContext(context);
}
for (MimeMappings.Mapping mapping : getMimeMappings()) {
context.addMimeMapping(mapping.getExtension(), mapping.getMimeType());
}
configureSession(context);
for (TomcatContextCustomizer customizer : this.tomcatContextCustomizers) {
customizer.customize(context);
}
}
执行TomcatStarter starter = new TomcatStarter(initializers);然后将其加入到context中context.addServletContainerInitializer(starter, NO_CLASSES);,则会在tomcat启动时会调用start中的onStartup方法
@Override
public void onStartup(Set<Class<?>> classes, ServletContext servletContext)
throws ServletException {
try {
for (ServletContextInitializer initializer : this.initializers) {
initializer.onStartup(servletContext);
}
}
catch (Exception ex) {
this.startUpException = ex;
// Prevent Tomcat from logging and re-throwing when we know we can
// deal with it in the main thread, but log for information here.
if (logger.isErrorEnabled()) {
logger.error("Error starting Tomcat context. Exception: "
+ ex.getClass().getName() + ". Message: " + ex.getMessage());
}
}
}
调用了initializer.onStartup(servletContext); 则可以回到前面提到的`selfInitialize(servletContext);了
private void selfInitialize(ServletContext servletContext) throws ServletException {
prepareEmbeddedWebApplicationContext(servletContext);
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(
beanFactory); //设置web scope
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory,
getServletContext());
existingScopes.restore();
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory,
getServletContext());
for (ServletContextInitializer beans : getServletContextInitializerBeans()) { //核心方法
beans.onStartup(servletContext); //servlet、filter和listen都会注册到ServletContext上
}
}
registerWebApplicationScopes注册了各种属于web的scoperegisterEnvironmentBeans注册了web特定的contextParameters,contextAttributes等getServletContextInitializerBeans()实现为
protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
return new ServletContextInitializerBeans(getBeanFactory());
}
ServletContextInitializerBeans为Collection的子类,继承了AbstractCollection,调用构造方法
public ServletContextInitializerBeans(ListableBeanFactory beanFactory) {
this.initializers = new LinkedMultiValueMap<Class<?>, ServletContextInitializer>();
addServletContextInitializerBeans(beanFactory); //处理ServletContextInitializer
addAdaptableBeans(beanFactory); //核心方法,将所有申明的Servlet ,Filter等转换成对应的XxxRegistrationBean
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);
}
首先看this.initializers = new LinkedMultiValueMap<Class<?>, ServletContextInitializer>(); 其中的initializers为一个多值的map结构,
简单来说就是map中的key对应多个value,其内部实现看LinkedMultiValueMap,利用Map<K, List<V>> targetMap内部属性来实现。
public class LinkedMultiValueMap<K, V> implements MultiValueMap<K, V>, Serializable {
private static final long serialVersionUID = 3801124242820219131L;
private final Map<K, List<V>> targetMap;
@Override
public void add(K key, V value) {
List<V> values = this.targetMap.get(key);
if (values == null) {
values = new LinkedList<V>();
this.targetMap.put(key, values);
}
values.add(value);
}
}
...
更多集合操作可以使用guava避免重复造轮子
addServletContextInitializerBeans()方法
private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
for (Entry<String, ServletContextInitializer> initializerBean : getOrderedBeansOfType(
beanFactory, ServletContextInitializer.class)) {
addServletContextInitializerBean(initializerBean.getKey(),
initializerBean.getValue(), beanFactory);
}
}
获取所有类型为ServletContextInitializer,进入如下处理
private void addServletContextInitializerBean(String beanName,
ServletContextInitializer initializer, ListableBeanFactory beanFactory) {
if (initializer instanceof ServletRegistrationBean) {
Servlet source = ((ServletRegistrationBean) initializer).getServlet();
addServletContextInitializerBean(Servlet.class, beanName, initializer,
beanFactory, source);
}
else if (initializer instanceof FilterRegistrationBean) {
Filter source = ((FilterRegistrationBean) initializer).getFilter();
addServletContextInitializerBean(Filter.class, beanName, initializer,
beanFactory, source);
}
else if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
String source = ((DelegatingFilterProxyRegistrationBean) initializer)
.getTargetBeanName();
addServletContextInitializerBean(Filter.class, beanName, initializer,
beanFactory, source);
}
else if (initializer instanceof ServletListenerRegistrationBean) {
EventListener source = ((ServletListenerRegistrationBean<?>) initializer)
.getListener();
addServletContextInitializerBean(EventListener.class, beanName, initializer,
beanFactory, source);
}
else {
addServletContextInitializerBean(ServletContextInitializer.class, beanName,
initializer, beanFactory, null);
}
}
如果类型为FilterRegistrationBean,DelegatingFilterProxyRegistrationBean,ServletRegistrationBean,ServletListenerRegistrationBean分别对应到Filter,Filter,Servlet,EventListener,调用
private void addServletContextInitializerBean(Class<?> type, String beanName,
ServletContextInitializer initializer, ListableBeanFactory beanFactory,
Object source) {
this.initializers.add(type, initializer);
if (source != null) {
// 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);
}
}
将其类型type作为key存储在initializers中,seen记录处理过的source避免重复处理。
这里将spring boot中的XxxRegistrationBean与web中的servlet,filter,listen等对应起来,因此后期处理web中的元素,只需要处理XxxRegistrationBean即可。
继续看addAdaptableBeans(beanFactory);方法
private void addAdaptableBeans(ListableBeanFactory beanFactory) {
MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);
addAsRegistrationBean(beanFactory, Servlet.class,
new ServletRegistrationBeanAdapter(multipartConfig)); //将所有类型的Servlet对应bean转换成ServletRegistrationBean
addAsRegistrationBean(beanFactory, Filter.class,
new FilterRegistrationBeanAdapter());
for (Class<?> listenerType : ServletListenerRegistrationBean
.getSupportedTypes()) { //处理servlet中支持的监听
addAsRegistrationBean(beanFactory, EventListener.class,
(Class<EventListener>) listenerType,
new ServletListenerRegistrationBeanAdapter());
}
}
要看懂这块代码,首先要知道addAsRegistrationBean的作用
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); //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
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));
}
}
}
}
FilterRegistration.Dynamic
组合起来看,发现其功能:将所有的servlet,filter,listener对应的bean适配成XxxRegistrationBean,然后存入initializers集合中。
通过前面代码可以发现,在spring boot中可以直接申明的servlet,fiter或者listener,只要将其申明为bean后spring boot自然识别,
因此在spring boot中申明filter有两种方式(servlet,listener)一样
伪代码如下:
@Component
public MyFilter implements Filter{
...
}
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(MyFilter.class);
bean.addUrlPatterns("/*");
return bean;
}
这种将外部对象统一适配为内部对象后,只要处理内部对象即可完成对内部对象+外部对象的处理思路值得学习。
<hr>
继续来看前面的代码
```java
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);
<div class="se-preview-section-delimiter"></div>
这部分代码将initializers排序后赋值给sortedList,sortedList为该集合ServletContextInitializerBeans核心属性,遍历集合时则遍历的为
sortedList
@Override
public Iterator<ServletContextInitializer> iterator() {
return this.sortedList.iterator();
} //迭代时遍历sortedList
@Override
public int size() {
return this.sortedList.size();
}
<div class="se-preview-section-delimiter"></div>
至此处理完成ServletContextInitializerBeans,回到前面的
for (ServletContextInitializer beans : getServletContextInitializerBeans()) { //核心方法
beans.onStartup(servletContext); //servlet、filter和listen都会注册到ServletContext上
}
<div class="se-preview-section-delimiter"></div>
调用onStartup方法
针对FilterRegistrationBean执行
public void onStartup(ServletContext servletContext) throws ServletException {
Filter filter = getFilter();
Assert.notNull(filter, "Filter must not be null");
String name = getOrDeduceName(filter);
if (!isEnabled()) {
this.logger.info("Filter " + name + " was not registered (disabled)");
return;
}
FilterRegistration.Dynamic added = servletContext.addFilter(name, filter); //动态添加filter
if (added == null) {
this.logger.info("Filter " + name + " was not registered "
+ "(possibly already registered?)");
return;
}
configure(added); //filter映射到/*
}
<div class="se-preview-section-delimiter"></div>
通过FilterRegistration.Dynamic动态添加filter
ServletRegistrationBean,ServletListenerRegistrationBean代码逻辑和FilterRegistrationBean逻辑类似。
又要回到TomcatEmbeddedServletContainerFactory#getEmbeddedServletContainer中getTomcatEmbeddedServletContainer(tomcat);
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
Tomcat tomcat) {
return new TomcatEmbeddedServletContainer(tomcat, getPort() >= 0);
}
<div class="se-preview-section-delimiter"></div>
执行initialize方法
private synchronized void initialize() throws EmbeddedServletContainerException {
TomcatEmbeddedServletContainer.logger
.info("Tomcat initialized with port(s): " + getPortsDescription(false));
try {
addInstanceIdToEngineName();
// Remove service connectors to that protocol binding doesn‘t happen yet
removeServiceConnectors();
// Start the server to trigger initialization listeners
this.tomcat.start();
// We can re-throw failure exception directly in the main thread
rethrowDeferredStartupExceptions();
Context context = findContext();
try {
ContextBindings.bindClassLoader(context, getNamingToken(context),
getClass().getClassLoader());
}
catch (NamingException ex) {
// Naming is not enabled. Continue
}
// Unlike Jetty, all Tomcat threads are daemon threads. We create a
// blocking non-daemon to stop immediate shutdown
startDaemonAwaitThread(); //tomcat需要调用tomcat.getServer().await()阻塞
}
catch (Exception ex) {
throw new EmbeddedServletContainerException("Unable to start embedded Tomcat",
ex);
}
}
调用this.tomcat.start()开启tomcat,然后通过startDaemonAwaitThread执行this.tomcat.getServer().await()阻塞当前线程。
至此内嵌tomcat分析完毕.
ok ~ it’s work ! more about is here
spring boot实战(第十五篇)嵌入tomcat源码分析
原文:http://blog.csdn.net/liaokailin/article/details/52269786