Spring源码学习-SpringBoot原理解析

SpringBoot利用@EnableAutoConfiguration注解进行自动配置,通过Import导入配置类。Tomcat和SpringMVC的准备涉及DispatcherServlet的自动装配,该Servlet是SpringMVC的核心。在onRefresh()方法中创建WebServer,DispatcherServlet注册到Tomcat并初始化。整个流程在run方法中启动并管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员的第11小时

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值