zoukankan      html  css  js  c++  java
  • spring boot 加载web容器tomcat流程源码分析

    spring boot 加载web容器tomcat流程源码分析

    我本地的springboot版本是2.5.1,后面的分析都是基于这个版本

        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.5.1</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
      
    

    我们通过在pom文件中引入

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    

    来引入web容器,默认的web容器时tomcat。

    本文章主要描述spring boot加载web容器 tomcat的部分,为了避免文章知识点过于分散,其他相关的如bean的加载,tomcat内部流程等不做深入讨论。

    1、在springboot web工程中,全局上下文是AnnotationConfigServletWebApplicationContext

    下面的部分,我们具体来看下

    首先,我们的入口代码一般都是这样写的

        public static void main(String[] args) {
            SpringApplication.run(BootargsApplication.class,args);
        }
    
    

    跳转到run方法里面,依次会调用下面两个方法

    	public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    		return run(new Class<?>[] { primarySource }, args);
    	}
    
    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
       return new SpringApplication(primarySources).run(args);
    }
    

    首先会创建SpringApplication实例对象,跳转到SpringApplication的构造方法去看看,依次会调用如下方法

    	public SpringApplication(Class<?>... primarySources) {
    		this(null, primarySources);
    	}
    
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
       ......
       //本次不相关的代码全部省略掉,只保留相关代码
       //这里的 this.webApplicationType=WebApplicationType.SERVLET, 我们来分析下这个代码的具体的执行赋值
       this.webApplicationType = WebApplicationType.deduceFromClasspath();
       ......
    }
    

    继续跳转到WebApplicationType.deduceFromClasspath()去看看

    	//这个方法主要是在当前类路径下查找指定的class类是否存在,返回对饮枚举类型
    	static WebApplicationType deduceFromClasspath() {
    	// WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
    	
    	//我们通过pom文件引入spring-boot-starter-web,会简介引入spring-webmvc,上面这个类就在这个webmvc中,所以不会进入这个if分支
    		if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
    				&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
    			return WebApplicationType.REACTIVE;
    		}
    	//SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
    			"org.springframework.web.context.ConfigurableWebApplicationContext" }
    	//javax.servlet.Servlet这个类存在于tomcat-embed-core中
        //org.springframework.web.context.ConfigurableWebApplicationContext这个类存在于spring-web中
        //这两个jar都是由spring-boot-starter-web间接引入的,所以也不会走这个分支
    		for (String className : SERVLET_INDICATOR_CLASSES) {
    			if (!ClassUtils.isPresent(className, null)) {
    				return WebApplicationType.NONE;
    			}
    		}
    		//所以会从这里返回
    		return WebApplicationType.SERVLET;
    	}
    

    下面看下jar包的引入

    回到new SpringApplication(primarySources).run(args)的调用来看run方法的代码

    public ConfigurableApplicationContext run(String... args) {
    		.......
    		try {
    			......
    			//我们来看这个context的创建,context=new AnnotationConfigServletWebServerApplicationContext()下面来具体看这块的执行
    			context = createApplicationContext();
    		    ......
    		    //后续几个部分会来说明这个方法
    			refreshContext(context);
    			......
    		}
    		catch (Throwable ex) {
    			......
    		}
    
    		try {
    		.......
    		}
    		catch (Throwable ex) {
    		.......
    		}
    		return context;
    	}
    

    createApplicationContext()依次会调用如下方法

    	protected ConfigurableApplicationContext createApplicationContext() {
    		//这里的this.webApplicationType就是上面的WebApplicationType.SERVLET
    		return this.applicationContextFactory.create(this.webApplicationType);
    	}
    
    	//最终会调用到这个lambda表达式,入参就是上面的WebApplicationType.SERVLET
    	ApplicationContextFactory DEFAULT = (webApplicationType) -> {
    		try {
    			switch (webApplicationType) {
    			case SERVLET:
    				//会从这里返回
    				return new AnnotationConfigServletWebServerApplicationContext();
    			case REACTIVE:
    				return new AnnotationConfigReactiveWebServerApplicationContext();
    			default:
    				return new AnnotationConfigApplicationContext();
    			}
    		}
    		catch (Exception ex) {
    			throw new IllegalStateException("Unable create a default ApplicationContext instance, "
    					+ "you may need a custom ApplicationContextFactory", ex);
    		}
    	};
    

    到这里,我们的上下文context就已经创建出来了,这块代码也比较简单。就不多说什么了

    2、查找ServletWebServerFactory

    再次回到new SpringApplication(primarySources).run(args)的调用来看run方法的代码

    public ConfigurableApplicationContext run(String... args) {
    		.......
    		try {
    			......
    			//上面已经对context做过了讲解,context=new AnnotationConfigServletWebServerApplicationContext()
    			context = createApplicationContext();
    		    ......
    		    //下面来看这个方法
    			refreshContext(context);
    			......
    		}
    		catch (Throwable ex) {
    			......
    		}
    
    		try {
    		.......
    		}
    		catch (Throwable ex) {
    		.......
    		}
    		return context;
    	}
    

    点到refreshContext(context)

    	private void refreshContext(ConfigurableApplicationContext context) {
    		if (this.registerShutdownHook) {
    			shutdownHook.registerApplicationContext(context);
    		}
    		refresh(context);
    	}
    
    

    继续点到refresh(context)

    	protected void refresh(ConfigurableApplicationContext applicationContext) {
            //这里的applicationContext就是AnnotationConfigServletWebServerApplicationContext的对象,由于这个类没有refresh方法,会跳转到它的父类ServletWebServerApplicationContext的方法中去,我们继续点进去
    		applicationContext.refresh();
    	}
    

    点到ServletWebServerApplicationContext的refresh方法

    	public final void refresh() throws BeansException, IllegalStateException {
    		try {
                //继续跳转到父类AbstractApplicationContext方法
    			super.refresh();
    		}
    		catch (RuntimeException ex) {
    			WebServer webServer = this.webServer;
    			if (webServer != null) {
    				webServer.stop();
    			}
    			throw ex;
    		}
    	}
    

    打开AbstractApplicationContext的refresh方法

    //springboot 大部分的初始化工作是在这里完成的,不过这不是我们本地的重点,不相关的我们统统略过
    public void refresh() throws BeansException, IllegalStateException {
    		synchronized (this.startupShutdownMonitor) {
    			......
    			try {
    			......
    				//继续点到这个方法,这里又会跳转到ServletWebServerApplicationContext这个类的方法
    				onRefresh();
    			.....
    			}
    
    			catch (BeansException ex) {
    			.....
    			}
    
    			finally {
    			.....
    			}
    		}
    	}
    

    打开ServletWebServerApplicationContext的onRefresh方法

    	protected void onRefresh() {
    		super.onRefresh();
    		try {
    			//这里就是我们本次的重点,会在这里创建具体的web容器,我们点进去看看,还是ServletWebServerApplicationContext这个类的方法
    			createWebServer();
    		}
    		catch (Throwable ex) {
    			throw new ApplicationContextException("Unable to start web server", ex);
    		}
    	}
    

    打开ServletWebServerApplicationContext的createWebServer方法

    	private void createWebServer() {
    	
    		WebServer webServer = this.webServer;
    		ServletContext servletContext = getServletContext();
    		//第一次进来webServer servletContext都是null,会进到if分支里面
    		if (webServer  == null && servletContext == null) {
    		   //这里只是做个标记,不用关注,跳过
    			StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
    			//这里就会来查找ServletWebServerFactory,也就是web容器的工厂,具体看下getWebServerFactory()方法,还是ServletWebServerApplicationContext这个类的方法
    			ServletWebServerFactory factory = getWebServerFactory();
    			createWebServer.tag("factory", factory.getClass().toString());
    			this.webServer = factory.getWebServer(getSelfInitializer());
    			createWebServer.end();
    			getBeanFactory().registerSingleton("webServerGracefulShutdown",
    					new WebServerGracefulShutdownLifecycle(this.webServer));
    			getBeanFactory().registerSingleton("webServerStartStop",
    					new WebServerStartStopLifecycle(this, this.webServer));
    		}
    		else if (servletContext != null) {
    			try {
    				getSelfInitializer().onStartup(servletContext);
    			}
    			catch (ServletException ex) {
    				throw new ApplicationContextException("Cannot initialize servlet context", ex);
    			}
    		}
    		initPropertySources();
    	}
    

    打开ServletWebServerApplicationContext的getWebServerFactory方法

    	protected ServletWebServerFactory getWebServerFactory() {
    		// Use bean names so that we don't consider the hierarchy
    		//从beanFactory中查找ServletWebServerFactory类型的bean的定义,返回对应bean的名字
    		String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
    		if (beanNames.length == 0) {
    			throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing "
    					+ "ServletWebServerFactory bean.");
    		}
    		if (beanNames.length > 1) {
    			throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple "
    					+ "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
    		}
            //这里会从beanFactory中返回bean的名字为beanNames[0],类型为ServletWebServerFactory.class的bean对象,如果当前bean还未创建,则此时就会创建bean对象并返回	
    		return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
    	}
    

    从上面的代码并看不出来实际的ServletWebServerFactory对象具体是什么?下面带着大家一起简单过下这部分的加载,这里具体就是springboot 加载bean的流程了,这部分的逻辑比较多,本次就不具体展开。关于springboot 加载bean的流程计划后续专门再写一篇。

    springboot在启动过程中会在当前类路径下META-INF/spring.factories这个文件中,key=org.springframework.boot.autoconfigure.EnableAutoConfiguration的属性的作为bean的定义进行加载,在这过程中还会使用key=org.springframework.boot.autoconfigure.AutoConfigurationImportFilterfilter的属性作为过滤,配合META-INF/spring-autoconfigure-metadata.properties对这些类做一个过滤,剔除掉不符合的类(后续还会根据类上的注解判断是否要继续剔除)。

    当前这些主要在spring-boot-autoconfigure-2.5.1.jar这个文件中

    下面截取上面说的两部分,可以看到这里的过滤器就3个,具体不展开讨论了,自动导入的类就是下面的再加过滤去掉的

    # Auto Configuration Import Filters
    org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
    org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
    org.springframework.boot.autoconfigure.condition.OnClassCondition,\
    org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
    
    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    ......
    #下面这个会在创建servelt中使用,下部分我们再关注它
    org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
    #下面这个就是我们需要用到的
    org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
    ......
    org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
    ......
    
    

    我们看下上面的org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration这个类,这个类在web 场景下,不会被剔除。会被加载。我们看看这个类,我们只看头部就可以了

    这里我们看到类上有Import注解,会继续导入这几个类,

    ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
    ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
    ServletWebServerFactoryConfiguration.EmbeddedUndertow.class
    

    这三个都是本次相关的,它们都是ServletWebServerFactoryConfiguration的内部类,我们进去看看,类的结构都是一样的,我们就看下ServletWebServerFactoryConfiguration.EmbeddedTomcat类吧

    可以看到EmbeddedTomcat上面有ConditionalOnClass,ConditionalOnMissingBean这两个注解,

    简单说下,ConditionalOnClass是表示当前类路径下存在对应类是加载

    ConditionalOnMissingBean是表示当前beanFactory中没有对应类型bean定义的话加载

    多个条件都是and的关系,有一个条件不成立,就不会去进行后续处理。

    在这里EmbeddedTomcat类这两个条件是成立的,这时就会继续遍历当前类的所有方法,找到@Bean注解的方法,加载到beanFactory中去

    而EmbeddedJetty,EmbeddedUndertow两个类条件是不成立的,就不会进行后续执行,剔除掉了

    这里就会把EmbeddedTomcat.tomcatServletWebServerFactory这个方法进行加载,返回值是TomcatServletWebServerFactory类型,我们看下TomcatServletWebServerFactory类的继承图,可以看到它正好是继承了ServletWebServerFactory接口。

    再次打开ServletWebServerApplicationContext的getWebServerFactory方法

    	protected ServletWebServerFactory getWebServerFactory() {
    		.......
            //所以这里的逻辑实际上会执行ServletWebServerFactoryConfiguration.EmbeddedTomcat类的tomcatServletWebServerFactory方法,返回TomcatServletWebServerFactory对象,相关的属性注入等等这里就不讲述了            
    		return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
    	}
    

    到这里,整个ServletWebServerFactory的查找就完成了

    3、创建DispatcherServletRegistrationBean,DispatcherServlet

    再看看上面的META-INF/spring.factories文件

    # Auto Configuration Import Filters
    org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
    org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
    org.springframework.boot.autoconfigure.condition.OnClassCondition,\
    org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
    
    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    ......
    #现在我们重点来看这个类
    org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
    ......
    org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
    ......
    
    

    我们打开org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration这个类看看

    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
    @Configuration(proxyBeanMethods = false)
    //我们当前只关注这ConditionalOnWebApplication、ConditionalOnClass注解
    //ConditionalOnWebApplication是根据type来判断指定类是否存在
    //当前的type是 Type.SERVLET,是来查找org.springframework.web.context.support.GenericWebApplicationContext类是否存在,这个类存在于spring-web中,所以这个条件是true
    @ConditionalOnWebApplication(type = Type.SERVLET)
    //这个注解上面说过了 ,就是查找指定的类是否存在,这个是查找DispatcherServlet.class是否存在,这里也会返回true
    @ConditionalOnClass(DispatcherServlet.class)
    //上面两个条件都成立,就会执行后续的操作,去遍历内部类和方法
    @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
    public class DispatcherServletAutoConfiguration {
    
    	/**
    	 * The bean name for a DispatcherServlet that will be mapped to the root URL "/".
    	 */
    	public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";
    
    	/**
    	 * The bean name for a ServletRegistrationBean for the DispatcherServlet "/".
    	 */
    	public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";
    
    	@Configuration(proxyBeanMethods = false)
        //这里还是个条件,通过实现Condition接口,通过matches方法来判断
        //DefaultDispatcherServletCondition这个类就在当前这个文件里,matches判断的结果也是true
    	@Conditional(DefaultDispatcherServletCondition.class)
        //ServletRegistration.class这个类存在于tomcat-embed-core里面,这个结果也是true
    	@ConditionalOnClass(ServletRegistration.class)
        //上面两个条件成立,就会执行后续的操作,去遍历内部类和方法
    	@EnableConfigurationProperties(WebMvcProperties.class)
    	protected static class DispatcherServletConfiguration {
    
            //beanFactory会创建这个DispatcherServletbean的定义,bean的名字就是dispatcherServlet
    		@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
    		public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
    			DispatcherServlet dispatcherServlet = new DispatcherServlet();
    			dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
    			dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
    			dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
    			dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
    			dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
    			return dispatcherServlet;
    		}
    
    		@Bean
    		@ConditionalOnBean(MultipartResolver.class)
    		@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
    		public MultipartResolver multipartResolver(MultipartResolver resolver) {
    			// Detect if the user has created a MultipartResolver but named it incorrectly
    			return resolver;
    		}
    
    	}
    
    	@Configuration(proxyBeanMethods = false)
        //和上面的一样,不说了
    	@Conditional(DispatcherServletRegistrationCondition.class)
        //和上面的一样,不说了
    	@ConditionalOnClass(ServletRegistration.class)
    	@EnableConfigurationProperties(WebMvcProperties.class)
        //这里会要在查找DispatcherServletConfiguration.class,并执行加载bean定义的流程,这就是上面的类了
    	@Import(DispatcherServletConfiguration.class)
    	protected static class DispatcherServletRegistrationConfiguration {
    
    		@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
            //ConditionalOnBean查找是否存在指定bean的定义,这个方法要注入参数,需要这个类,当前这里就是上面的dispatcherServlet方法定义的,这里也是存在的
    		@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
            //DispatcherServlet dispatcherServlet这个就是dispatcherServlet这个方法定义的bean,在创建DispatcherServletRegistrationBean这个bean的时候,就会去查找dispatcherServlet是否存在,如果不存在,先创建dispatcherServlet这个bean,再创建DispatcherServletRegistrationBean
    		public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
    				WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
    			DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
    					webMvcProperties.getServlet().getPath());
    			registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
    			registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
    			multipartConfig.ifAvailable(registration::setMultipartConfig);
    			return registration;
    		}
    
    	}
      ......
    }
          
    

    上面就是创建DispatcherServlet,DispatcherServletRegistrationBean的过程了

    4、创建tomcat,加载Servlet.class,filter.class,监听器

    再次回到ServletWebServerApplicationContext的createWebServer方法

    	private void createWebServer() {
    		WebServer webServer = this.webServer;
    		ServletContext servletContext = getServletContext();
    		if (webServer == null && servletContext == null) {
    			StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
    			//上面我们已经看到了这里,factory是TomcatServletWebServerFactory类的一个实例对象
    			ServletWebServerFactory factory = getWebServerFactory();
                //这里还是做个标记,不用关注
                createWebServer.tag("factory", factory.getClass().toString());
                //这里就是具体创建tomcat了,这里的入参getSelfInitializer()是个lambda表达式,这个后续很重要
    			this.webServer = factory.getWebServer(getSelfInitializer());
    			createWebServer.end();
    			getBeanFactory().registerSingleton("webServerGracefulShutdown",
    					new WebServerGracefulShutdownLifecycle(this.webServer));
    			getBeanFactory().registerSingleton("webServerStartStop",
    					new WebServerStartStopLifecycle(this, this.webServer));
    		}
    		else if (servletContext != null) {
    			try {
    				getSelfInitializer().onStartup(servletContext);
    			}
    			catch (ServletException ex) {
    				throw new ApplicationContextException("Cannot initialize servlet context", ex);
    			}
    		}
    		initPropertySources();
    	}
    
    	private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
    		return this::selfInitialize;
    	}
    	//是创建webServer的参数
    	private void selfInitialize(ServletContext servletContext) throws ServletException {
    		prepareWebApplicationContext(servletContext);
    		registerApplicationScope(servletContext);
    		WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
    		for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
    			beans.onStartup(servletContext);
    		}
    	}
    

    factory.getWebServer(getSelfInitializer())会调用到TomcatServletWebServerFactory的getWebServer的方法

    	public WebServer getWebServer(ServletContextInitializer... initializers) {
            .......
    		//上面的入参会在这里传下去
    		prepareContext(tomcat.getHost(), initializers);
    		return getTomcatWebServer(tomcat);
    	}
    

    点进prepareContext(tomcat.getHost(), initializers)去看看

    
    	protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
    		......
    		ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
    		host.addChild(context);
    		//继续传下去
    		configureContext(context, initializersToUse);
    		postProcessContext(context);
    	}
    

    再点到configureContext(context, initializersToUse)这个调用去看看

    	protected void configureContext(Context context, ServletContextInitializer[] initializers) {
    		//会传递给TomcatStarter,作为构造参数,下面我们去这里看看
    		TomcatStarter starter = new TomcatStarter(initializers);
            ......
        }
    

    下面我们去看看TomcatStarter这个类是怎么使用这个initializers这个构造参数的。

    这个类不长
    class TomcatStarter implements ServletContainerInitializer {
        ......
    	TomcatStarter(ServletContextInitializer[] initializers) {
            //入参会作为它的成员属性
    		this.initializers = initializers;
    	}
    
    	@Override
    	public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {
    		try {
    			for (ServletContextInitializer initializer : this.initializers) {
                    //会在这里调用onStartup方法,这里的入参就是ApplicationContextFacade的对象,里面包装了ApplicationContext,里面再包装了TomcatEmbeddedContext,这要就和tomcat联系起来了,下面的截图就是servletContext的对象结构
    				initializer.onStartup(servletContext);
    			}
    		}
    		catch (Exception ex) {
    			......
    	}
    

    上面的initializer.onStartup(servletContext)会调用到ServletWebServerApplicationContext的selfInitialize方法

    	private void selfInitialize(ServletContext servletContext) throws ServletException {
            //这里是将ApplicationContextFacade设置到当前的servletContext上
    		prepareWebApplicationContext(servletContext);
            //这里是在beanFactory中注册application的scope
    		registerApplicationScope(servletContext);
            //这里还是注册上下文相关的bean
    		WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
            //我们重点来看这里getServletContextInitializerBeans()是定义个一个ServletContextInitializerBeans对象,我们点进去看看
    		for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
    			beans.onStartup(servletContext);
    		}
    	}
    
    	protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
    		//这里的getBeanFactory()就是全局的beanFactory
    		return new ServletContextInitializerBeans(getBeanFactory());
    	}
    
    
    	public ServletContextInitializerBeans(ListableBeanFactory beanFactory,
    			Class<? extends ServletContextInitializer>... initializerTypes) {
    		this.initializers = new LinkedMultiValueMap<>();
            //由于我们没有传initializerTypes这个参数,所以this.initializerTypes里面就只有ServletContextInitializer.class这个类
    		this.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes)
    				: Collections.singletonList(ServletContextInitializer.class);
            //这里主要是从beanFactory中查找this.initializerTypes类型,我们进去看看,就是下面这个方法了
    		addServletContextInitializerBeans(beanFactory);
    		addAdaptableBeans(beanFactory);
    		List<ServletContextInitializer> sortedInitializers = this.initializers.values().stream()
    				.flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))
    				.collect(Collectors.toList());
    		this.sortedList = Collections.unmodifiableList(sortedInitializers);
    		logMappings(this.initializers);
    	}
    
    	private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
    		for (Class<? extends ServletContextInitializer> initializerType : this.initializerTypes) {
                //默认情况下这里找到就只有上面第3部分的DispatcherServletRegistrationBean对应的bean
    			for (Entry<String, ? extends ServletContextInitializer> initializerBean : getOrderedBeansOfType(beanFactory,
    					initializerType)) {
                    //这里的key是bean的名字,value就是bean对象,在进去看看,就是下面这个方法
    				addServletContextInitializerBean(initializerBean.getKey(), initializerBean.getValue(), beanFactory);
    			}
    		}
    	}
    	private void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer,
    			ListableBeanFactory beanFactory) {
            //会走到这个分支
    		if (initializer instanceof ServletRegistrationBean) {
                //这里返回的servlet也还是第3部分DispatcherServlet对应的bean
    			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,
    					initializer);
    		}
    	}
    
    	private void addServletContextInitializerBean(Class<?> type, String beanName, ServletContextInitializer initializer,
    			ListableBeanFactory beanFactory, Object source) {
            //这里的initializers是个map,按照类型,bean对象进行加载,这里的type是javax.servlet.Servlet.class,value是上面的DispatcherServletRegistrationBean
    		this.initializers.add(type, initializer);
    		if (source != null) {
    			// Mark the underlying source as seen in case it wraps an existing bean
                //将DispatcherServlet对应的bean加到这里
    			this.seen.add(source);
    		}
    		if (logger.isTraceEnabled()) {
    			String resourceDescription = getResourceDescription(beanName, beanFactory);
    			int order = getOrder(initializer);
    			logger.trace("Added existing " + type.getSimpleName() + " initializer bean '" + beanName + "'; order="
    					+ order + ", resource=" + resourceDescription);
    		}
    	}
    
    

    再回到ServletContextInitializerBeans的构造方法,接着看后面的

    	public ServletContextInitializerBeans(ListableBeanFactory beanFactory,
    			Class<? extends ServletContextInitializer>... initializerTypes) {
    		...... //这里的内容上面已经看过了,我们现在看下面这句,点进去
    		addAdaptableBeans(beanFactory);
    		List<ServletContextInitializer> sortedInitializers = this.initializers.values().stream()
    				.flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))
    				.collect(Collectors.toList());
    		this.sortedList = Collections.unmodifiableList(sortedInitializers);
    		logMappings(this.initializers);
    	}
    
    
    	protected void addAdaptableBeans(ListableBeanFactory beanFactory) {
    		//这句不用关注
    		MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);
    		//这句不用关注
    		addAsRegistrationBean(beanFactory, Servlet.class, new ServletRegistrationBeanAdapter(multipartConfig));
    		//点到这里去看看
    		addAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter());
            
    		for (Class<?> listenerType : ServletListenerRegistrationBean.getSupportedTypes()) {
    			addAsRegistrationBean(beanFactory, EventListener.class, (Class<EventListener>) listenerType,
    					new ServletListenerRegistrationBeanAdapter());
    		}
    	}
    
    
    	
    	private <T, B extends T> void addAsRegistrationBean(ListableBeanFactory beanFactory, Class<T> type,
    			Class<B> beanType, RegistrationBeanAdapter<T> adapter) {
    		//这里的beanType是 Filter.class,下面这句就是从beanFactory中获取所有类型为Filter.class的bean
    		List<Map.Entry<String, B>> entries = getOrderedBeansOfType(beanFactory, beanType, this.seen);
    		for (Entry<String, B> entry : entries) {
    			String beanName = entry.getKey();
    			B bean = entry.getValue();
                //将bean放置到this.seen里面
    			if (this.seen.add(bean)) {
    				// One that we haven't already seen
                    //包装成RegistrationBean对象
    				RegistrationBean registration = adapter.createRegistrationBean(beanName, bean, entries.size());
    				int order = getOrder(bean);
    				registration.setOrder(order);
                    //同样放置到this.initializers里面
    				this.initializers.add(type, registration);
    				if (logger.isTraceEnabled()) {
    					logger.trace("Created " + type.getSimpleName() + " initializer for bean '" + beanName + "'; order="
    							+ order + ", resource=" + getResourceDescription(beanName, beanFactory));
    				}
    			}
    		}
    	}
    

    再回到上面的addAdaptableBeans方法,看后面的

    
    	protected void addAdaptableBeans(ListableBeanFactory beanFactory) {
    		......//这里刚才说过了
             //下面这部分不说了,这里基本和上面一样,不过处理的类型变成了ServletContextAttributeListener.class、ServletRequestListener.class、ServletRequestAttributeListener.class、HttpSessionAttributeListener.class、HttpSessionIdListener.class、HttpSessionListener.class、ServletContextListener.class这些类型
    		for (Class<?> listenerType : ServletListenerRegistrationBean.getSupportedTypes()) {
    			addAsRegistrationBean(beanFactory, EventListener.class, (Class<EventListener>) listenerType,
    					new ServletListenerRegistrationBeanAdapter());
    		}
    	}
    

    再回到ServletContextInitializerBeans的构造方法,接着看后面的

    	public ServletContextInitializerBeans(ListableBeanFactory beanFactory,
    			Class<? extends ServletContextInitializer>... initializerTypes) {
    		......//这里刚才都说过了,看下面
            //这里就是把上面所有获取到的相关的bean放置到this.sortedList中,下面我是我本地this.sortedList的截图
    		List<ServletContextInitializer> sortedInitializers = this.initializers.values().stream()
    				.flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))
    				.collect(Collectors.toList());
    		this.sortedList = Collections.unmodifiableList(sortedInitializers);
    		logMappings(this.initializers);
    	}
    

    这里ServletContextInitializerBeans的构造方法就完成了,再回过头去看看这个类的定义

    public class ServletContextInitializerBeans extends AbstractCollection<ServletContextInitializer>
    

    这个类继承了AbstractCollection类,那它就需要实现下面这个抽象方法

    public abstract Iterator<E> iterator();
    

    我们看看ServletContextInitializerBeans的iterator的方法

    @Override
    public Iterator<ServletContextInitializer> iterator() {
       return this.sortedList.iterator();
    }
    

    看到了吧,这就是返回上面的this.sortedList.iterator()

    我们再次回到ServletWebServerApplicationContext的selfInitialize方法

    private void selfInitialize(ServletContext servletContext) throws ServletException {
    	......//这里上面都说过了
    	//getServletContextInitializerBeans()这个方法就是构造了ServletContextInitializerBeans
    	//这里的for循环也是调用了ServletContextInitializerBeans的iterator的方法,实际上遍历的也就是上面的this.sortedList
    	for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
    		//这里就是把在beanFactory中查找到的Servlet.class,filter.class,监听器等等添加到tomcat容器中,我们就只进到servlet里面去看看
    		//进到DispatcherServletRegistrationBean里面去看看
    		beans.onStartup(servletContext);
    	}
    }
    
    	//这个方法在DispatcherServletRegistrationBean的父类RegistrationBean中
    	//所有的Servlet.class,filter.class,监听器都会走到这里
    	public final void onStartup(ServletContext servletContext) throws ServletException {
    		//这里是返回的表述,不关注
    		String description = getDescription();
    		if (!isEnabled()) {
    			logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
    			return;
    		}
    		//这里由不同的子类去实现,DispatcherServletRegistrationBean会调用到ServletRegistrationBean中
    		register(description, servletContext);
    	}
    
    	//这个方法是在ServletRegistrationBean这个类中
    	@Override
    	protected ServletRegistration.Dynamic addRegistration(String description, ServletContext servletContext) {
    		String name = getServletName();
    		//这里的servletContext上面的ApplicationContextFacade的对象,这里就会将DispatcherServlet的bean对象加载到TomcatEmbeddedContext中,后续所有的http请求最后都会流转到DispatcherServlet去进行具体的分发
    		return servletContext.addServlet(name, this.servlet);
    	}
    

    到这里Servlet.class,filter.class,监听器就全部加载到tomcat中去

    5、创建RequestMappingHandlerMapping

    再看看上面的META-INF/spring.factories文件

    # Auto Configuration Import Filters
    org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
    org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
    org.springframework.boot.autoconfigure.condition.OnClassCondition,\
    org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
    
    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    ......
    org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
    ......
    #现在我们重点来看这个类
    org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
    ......
    
    

    具体的加载和上面部分都类似,就不展开了,直接看我们需要的

    		//这里会创建RequestMappingHandlerMapping的bean
    		@Bean
    		@Primary
    		@Override
    		public RequestMappingHandlerMapping requestMappingHandlerMapping(
    				@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
    				@Qualifier("mvcConversionService") FormattingConversionService conversionService,
    				@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
    			// Must be @Primary for MvcUriComponentsBuilder to work
    			return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
    					resourceUrlProvider);
    
    

    看下这个类的继承图

    RequestMappingHandlerMapping实现了InitializingBean接口,会在bean对象创建后的invokeInitMethods方法中调用afterPropertiesSet方法,最终会调用的AbstractHandlerMethodMapping的afterPropertiesSet方法中

    	@Override
    	public void afterPropertiesSet() {
    		initHandlerMethods();
    	}
    
    	/**
    	 * Scan beans in the ApplicationContext, detect and register handler methods.
    	 * @see #getCandidateBeanNames()
    	 * @see #processCandidateBean
    	 * @see #handlerMethodsInitialized
    	 */
    	protected void initHandlerMethods() {
            //这里查找beanFactory中的所有bean进行遍历
    		for (String beanName : getCandidateBeanNames()) {
    			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
                    //点到这里去看看
    				processCandidateBean(beanName);
    			}
    		}
    		handlerMethodsInitialized(getHandlerMethods());
    	}
    
    	protected void processCandidateBean(String beanName) {
    		Class<?> beanType = null;
    		try {
    			//根据beanName获取对应bean的Class对象
    			beanType = obtainApplicationContext().getType(beanName);
    		}
    		catch (Throwable ex) {
    			// An unresolvable bean type, probably from a lazy bean - let's ignore it.
    			if (logger.isTraceEnabled()) {
    				logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
    			}
    		}
    		//判断类上是否有Controller.class,RequestMapping.class注解
    		if (beanType != null && isHandler(beanType)) {
    			//这里就会解析beanName上的所有方法进行遍历,查找有 RequestMapping.class注解的方法,创建RequestMappingInfo对象,放置到registry属性中(在AbstractHandlerMethodMapping)中,这样我们所有定义的controller中的http请求就会全部被扫描到
    			detectHandlerMethods(beanName);
    		}
    	}
    

    6、加载RequestMappingHandlerMapping到DispatcherServlet中

    在我们第一次请求的时候,会执行到DispatcherServlet的initStrategies方法,这个方法只会执行一次

    	protected void initStrategies(ApplicationContext context) {
    		......
    		这就会加载之前查找到的RequestMappingHandlerMapping中的我们定义的controller
    		initHandlerMappings(context);
    		......
    	}
    

    会调用到这里

    	private void initHandlerMappings(ApplicationContext context) {
    		this.handlerMappings = null;
    
    		if (this.detectAllHandlerMappings) {
    			// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
    			//这里会在beanFactory中查找所有HandlerMapping.class的bean,其中就包含我们第5部分的RequestMappingHandlerMapping
    			Map<String, HandlerMapping> matchingBeans =
    					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
    			if (!matchingBeans.isEmpty()) {
    			//将所有查找到的放置到handlerMappings中
    				this.handlerMappings = new ArrayList<>(matchingBeans.values());
    				// We keep HandlerMappings in sorted order.
    				AnnotationAwareOrderComparator.sort(this.handlerMappings);
    			}
    		}
    		......
    	}
    

    当我们浏览器请求的时候,最终会走到DispatcherServlet的doDispatch的方法,处理我们的请求并返回,简单看看

    	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    		......
    
    		try {
    			ModelAndView mv = null;
    			Exception dispatchException = null;
    
    			try {
    				processedRequest = checkMultipart(request);
    				multipartRequestParsed = (processedRequest != request);
    
    				// Determine handler for the current request.
                    //在这里,就会请求request的请求路径去查找实际要执行的controller的方法,点进去看看
    				mappedHandler = getHandler(processedRequest);
    				......
    	}
    
    
    	@Nullable
    	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    		if (this.handlerMappings != null) {
                //这其实就是根据遍历,查找对应的路径,这个this.handlerMappings就是就是在initHandlerMappings方法中赋值的
    			for (HandlerMapping mapping : this.handlerMappings) {
    				HandlerExecutionChain handler = mapping.getHandler(request);
    				if (handler != null) {
    					return handler;
    				}
    			}
    		}
    		return null;
    	}
    

    到这里,springboot 加载web容器的整个流程基本就算完成了,这块涉及的东西比较多,所以说的可能比较粗,大家见谅。

  • 相关阅读:
    Tomcat单机多实例部署
    通过Zabbix监控Tomcat单机多实例
    Swarm容器集群管理(超详细)
    15、基于consul+consul-template+registrator+nginx实现自动服务发现
    14、Docker监控方案(Prometheus+cAdvisor+Grafana)
    创建python虚拟环境
    Linux系统基础优化及常用命令
    Linux常用命令--用户管理,文件权限,打包命令等
    Linux--CentOS7使用firewalld打开关闭防火墙与端口
    vim
  • 原文地址:https://www.cnblogs.com/wbo112/p/14904986.html
Copyright © 2011-2022 走看看