SpringBoot启动服务源码解析

        SpringBoot最重要的功能功能之一就是自动装配,他会去读取SpringFrameWork中autoConfiguration包下的spring.factories文件,然后将其中配置的AutoConfiguration通过规则匹配之后自动装配到Spring容器中(ServletWebServerFactoryAutoConfiguration),这个类作用就是,当我们点击SpringApplication.run方法的时候,底层会帮我们启动对应的服务(Tomcat,underTow,Jetty)中的一个

@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {

    	@Bean
	public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
		return new ServletWebServerFactoryCustomizer(serverProperties);
	}
}

      @EnableConfigurationProperties(ServerProperties.class):这个注解会去解析配置文件中server为前缀的字串,然后统一映射成ServerProperties类为我们使用,比如我们常见的server.port = 8080,这个port就是ServerProperties中的属性名

        @Import注解引入了四个类,我们先来看后面三个(Tomcat,Jetty,UnderTow),和Tomcat相关的内部类,就是定义了一个Bean,并且返回一个ServletWebServerFactory类型的对象,在中间的代码中我们可以自定义ConnectorCustomizers这些类,来设置启动的属性,比如,jetty和UnderTow也是一样的,这边拿Tomcat看一下;

	@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
	@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
    //MissingBean中说明了不允许存在其他的ServletWebServerFactory类型,如果存在,那么这边就不会生效,所以保证了服务的唯一
    static class EmbeddedTomcat {

//@Bean方法中的参数如果不加ObjectProvider,那么便会强依赖与他的入参,如果没有便会报错,
//如果加了ObjectProvider,那么在Spring容器中就算没有这些类型的参数,也会默认赋值一个空对象

		@Bean
		TomcatServletWebServerFactory tomcatServletWebServerFactory(
				ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
				ObjectProvider<TomcatContextCustomizer> contextCustomizers,
				ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
			TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
			factory.getTomcatConnectorCustomizers()
					.addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
			factory.getTomcatContextCustomizers()
					.addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
			factory.getTomcatProtocolHandlerCustomizers()
					.addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
			return factory;
		}

	}
  //可以通过自定义的方式来为设置Tomcat中的参数
    @Bean
    TomcatConnectorCustomizer getTomcatConnectorCustomizer(){
       return new TomcatConnectorCustomizer() {
            @Override
            public void customize(Connector connector) {
                connector.setPort(8081);
            }
        };
    }

            ConditionalOnMissingBean条件注解中说明了不允许存在其他的ServletWebServerFactory类型,如果存在,那么这边就不会生效,所以保证了服务的唯一。这个ServletWebServerFactory是个工厂,SpringBoot会通过调用其中的getWebServer方法来启动对应的服务(下面代码略有删减,看核心代码即可),我们上述可以通过server.port来为tomcat赋值,也可以通过自定义ConnectorCustomizer来修改参数,在customizeConnector方法中,可以看到有先后顺序,server.port在前,自定义的会覆盖server.port的操作(getPort()为什么会返回server.port最后会有解释)

	public WebServer getWebServer(ServletContextInitializer... initializers) {
		Tomcat tomcat = new Tomcat();
		Connector connector = new Connector(this.protocol);
        //这里面便会调用上面那张图片中的customize方法来为Tomcat赋值
		customizeConnector(connector);
		for (Connector additionalConnector : this.additionalTomcatConnectors) {
			tomcat.getService().addConnector(additionalConnector);
		}
		prepareContext(tomcat.getHost(), initializers);
		return getTomcatWebServer(tomcat);
	}


	protected void customizeConnector(Connector connector) {
        //server.port,配置文件中定义的端口
		int port = Math.max(getPort(), 0);
        //最后一张图有解析
		connector.setPort(port);
	    //我们自定义的连接对象
		for (TomcatConnectorCustomizer customizer : this.tomcatConnectorCustomizers) {
			customizer.customize(connector);
		}
	}

        最后再来看一下BeanPostProcessorsRegistrar,@import导入的第一个注解,他实现了ImportBeanDefinitionRegistrar接口,在Spring的启动过程中便会调用到registerBeanDefinition方法,他为我们注册了一个WebServerFactoryCustomizerBeanPostProcessor的BeanPostProcessor进去

		public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
				BeanDefinitionRegistry registry) {
		
			registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
					WebServerFactoryCustomizerBeanPostProcessor.class);

		}

        在其postProcessBeforeInitialization方法中,通过阅读代码得知,就是拿到Spring中的WebServerFactoryCustomizer,然后去执行里面的customize方法

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
   if (bean instanceof WebServerFactory) {
      postProcessBeforeInitialization((WebServerFactory) bean);
   }
   return bean;
}
        //最终会执行WebServerFactory中的customize方法
	private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
		LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
				.withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
				.invoke((customizer) -> customizer.customize(webServerFactory));
	}

        WebServerFactoryCustomizer在第一张图中我们能看到,Spring自定义了一个这样类型的Bean进去,所以我们直接解析ServletWebServerFactoryCustomizer.customize方法,里面的方法意思就是从ServerProperties中拿到对应的属性,然后塞到通过set方法注入到factory中,对应第三张图的getPort()方法就形成了闭环,吧ServerProperties文件中的属性都塞到了Tomcat/UnderTow/Jetty中

	public void customize(ConfigurableServletWebServerFactory factory) {
		PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
		map.from(this.serverProperties::getPort).to(factory::setPort);
		map.from(this.serverProperties::getAddress).to(factory::setAddress);
		map.from(this.serverProperties.getServlet()::getContextPath).to(factory::setContextPath);
		map.from(this.serverProperties.getServlet()::getApplicationDisplayName).to(factory::setDisplayName);
		map.from(this.serverProperties.getServlet()::isRegisterDefaultServlet).to(factory::setRegisterDefaultServlet);
		map.from(this.serverProperties.getServlet()::getSession).to(factory::setSession);
		map.from(this.serverProperties::getSsl).to(factory::setSsl);
		map.from(this.serverProperties.getServlet()::getJsp).to(factory::setJsp);
		map.from(this.serverProperties::getCompression).to(factory::setCompression);
		map.from(this.serverProperties::getHttp2).to(factory::setHttp2);
		map.from(this.serverProperties::getServerHeader).to(factory::setServerHeader);
		map.from(this.serverProperties.getServlet()::getContextParameters).to(factory::setInitParameters);
		map.from(this.serverProperties.getShutdown()).to(factory::setShutdown);
	}

总结:

        通过得到WebServerFactory,然后通过工厂模式得到对应的服务并且启动,在启动的过程中,可以手动实现一些Customizer来设置参数,也可以通过配置文件的方式来设置参数,手动创建的会覆盖配置文件

			//得到对应的工厂
            //TomcatServletWebServerFactory
            //JettyServletWebServerFactory
            //UndertowServletWebServerFactory
            ServletWebServerFactory factory = getWebServerFactory();

			//根据工厂启动容器,tomcat/jetty/underTow
            this.webServer = factory.getWebServer(getSelfInitializer());

        只允许启动一个服务

	//只允许存在一个,也就是只能启动一个服务
    protected ServletWebServerFactory getWebServerFactory() {
		// Use bean names so that we don't consider the hierarchy
		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));
		}
		return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
	}

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值