Spring源码学习-SpringBoot原理解析

目录

    • SpringBoot
      • 启动注解
        • @EnableAutoConfiguration
          • @AutoConfigurationPackage
          • @Import(AutoConfigurationImportSelector.class)
      • Tomcat和SpringMVC组件的准备过程
        • DispatcherServlet自动装配示例
        • @ServletWebServerFactoryAutoConfiguration
          • ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar
          • 三种不同服务器
        • 什么时机创建Web服务
        • DispatcherServlet注册到Tomcat
      • run方法

SpringBoot

启动注解

@EnableAutoConfiguration

@AutoConfigurationPackage

他通过Import的方式导进来了组件AutoConfigurationPackages.Registrar.class,他指定了我们以后要扫描哪些包下的所有组件,以后观察AutoConfigurationPackages的BeanDefinition怎么创建对象处理的,就知道我们自己写的controller何时进去

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

		@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
			register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
		}

		@Override
		public Set<Object> determineImports(AnnotationMetadata metadata) {
			return Collections.singleton(new PackageImports(metadata));
		}

	}
@Import(AutoConfigurationImportSelector.class)
  1. SpringFactoriesLoader.loadFactoryNames():去类路径下找META-INF/spring.factories文件(这个就属于SpringBoot定义的类似于SPI的机制)
  2. 找到所有@EnableAutoConfiguration全类名对应的配置的值
  • SpringBoot在这里写好了所有的它能够支持的全场景自动配置类,并且全部导入进来
  • 配置类就是给容器放组件(@Bean),接下来就是Spring自己去管理容器了
  • 注意这里会对所有的配置类(大概130多个)进行一次筛选和过滤,只留下当前项目需要的(通过看pom引进来没有jar包之类的手段等)

Tomcat和SpringMVC组件的准备过程

总体讲SpringBoot就是根据上面方式,通过WebMVC的配置类去自己创建了一个DispatcherServlet,随后注册到了Tomcat里面,之前的博客文章讲过,DispatcherServlet会通过生命周期初始化九大组件,在通过Tomcat启动的钩子会初始化父子容器,将整个的容器启动起来,DispatcherServlet这个Spring家自定义的Servlet对于SpringMVC和Spring来讲就是一切的起始和入口

DispatcherServlet自动装配示例

@Configuration(proxyBeanMethods = false)
	@Conditional(DefaultDispatcherServletCondition.class)
	@ConditionalOnClass(ServletRegistration.class)
	@EnableConfigurationProperties(WebMvcProperties.class)
	protected static class DispatcherServletConfiguration {

		@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;
		}

	}

@ServletWebServerFactoryAutoConfiguration

ServletWeb服务器的配置类,他必须在DispatcherServlet之前初始化完毕

ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar

web服务器工厂定制化的后置增强器

三种不同服务器

同时导入了三种不同的内嵌式的服务器,EmbeddedTomcatEmbeddedJetty,EmbeddedUndertow(默认的就是Tomcat生效)
给tomcat放入TomcatServletWebServerFactory,让我们产生并启动服务器

我们自己也可以拿到Web服务器的一些东西进行自己的自定义操作

什么时机创建Web服务

  • SpringBoot创建AnnotationConfigServletWebServerApplicationContext类型的IOC容器,他在容器十二大步的onRefresh()刷新的时候去创建WebServer,在这里拿到前面的web服务器工厂调用创建服务器的方法
  • 创建Tomcat,封装到TomcatWebServer,然后tomcat创建对象就会进行启动
  • 定制configureContext(context,initializersToUse[ServletContextInitializer])
   @Override
	protected void onRefresh() {
		super.onRefresh();
		try {
			createWebServer();
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start web server", ex);
		}
	}
	
	private void createWebServer() {
		WebServer webServer = this.webServer;
		ServletContext servletContext = getServletContext();
		if (webServer == null && servletContext == null) {
			StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
			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();
	}

DispatcherServlet注册到Tomcat

  • tomcat启动的时候,要把所有的ServletContextInitializer加载进来进行处理,把DispatcherServlet配置好,并给容器放好DispatcherServletRegistrationBean(实现了ServletContextInitializer接口).
  • tomcat启动以后每一个RegistrationBean就注册进去了,DispatcherServlet就开始执行整个初始化流程,以后就是SpringMVC的初始化流程(不过父子容器中的很多步骤已经执行过了,只需要执行剩下的操作)
	@Configuration(proxyBeanMethods = false)
	@Conditional(DispatcherServletRegistrationCondition.class)
	@ConditionalOnClass(ServletRegistration.class)
	@EnableConfigurationProperties(WebMvcProperties.class)
	@Import(DispatcherServletConfiguration.class)
	protected static class DispatcherServletRegistrationConfiguration {

		@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
		@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
		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;
		}

	}

run方法

这里的主流程就是通过run方法去创建IOC容器,然后开始容器刷新,过程中就会通过之前的配置类创建启动Tomcat的web服务(在onRefresh方法启动tomcat),然后DispatcherServlet初始化到容器中在注册进入tomcat,之后DispatcherServlet开始初始化,继续调用容器刷新的后续步骤

public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			context.setApplicationStartup(this.applicationStartup);
			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

你可能感兴趣的:(Spring源码解读,springBoot,spring,学习,spring,boot)