SpringBoot tomcat定制化实现原理

SpringBoot Tomcat 定制化实现原理

SpringBoot Tomcat 配置定制化,可以通过两种方式:

  1. Springboot 默认提供属性配置,比如server.tomcat.XXX
  2. 通过编程方式实现Tomcat 属性配置,通过编程方式有两种方法
    1. 实现TomcatConnectorCustomizer/TomcatContextCustomizer/TomcatProtocolHandlerCustomizer
    2. 实现WebServerFactoryCustomizer,并实现Ordered接口

SpringBoot 默认提供Tomcat属性配置

springbootTomcat 常用配置如下:

属性属性默认值属性说明
basedir默认为临时目录tomcat 运行目录–建议覆盖默认配置
threads.max默认为200tomcat 最大线程数
threads.minSpare默认为10tomcat 最小线程数
uriEncoding默认为UTF8URI编码格式
maxConnections默认为8192tomcat 最大连接数
acceptCount默认为100接请求的最大队列长度
connectionTimeout默认为6秒连接超时时间

编程方式实现Tomcat属性配置

通过TomcatXXXCustomizer来实现

@Configuration(proxyBeanMethods = false)
public class MyTomcatConnector implements TomcatConnectorCustomizer {
    @Override
    public void customize(Connector connector) {
        connector.setPort(9090);
        System.out.println("connector设置为9090" );
    }
}

通过WebServerFactoryCustomizer来实现

/**
 * 添加AJP支持
 */
@Configuration
@Order(3)
public class MyWebServerFactoryCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory>, ApplicationContextAware {
    private ApplicationContext context;

    @Override
    public void customize(TomcatServletWebServerFactory factory) {

        if (context instanceof WebServerApplicationContext) {
            TomcatWebServer webServer = ((TomcatWebServer) ((WebServerApplicationContext) context).getWebServer());
            //webServer.getTomcat().setPort(9091);
        }
        factory.setPort(9091);
        System.out.println("connector设置为9091");
        Connector ajp = new Connector("AJP/1.3");
        ajp.setPort(8085);
        ajp.setSecure(false);
        ajp.setScheme("http");
        AjpNioProtocol ajpNioProtocol = (AjpNioProtocol) ajp.getProtocolHandler();
        ajpNioProtocol.setSecretRequired(false);
        factory.addAdditionalTomcatConnectors(ajp);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }
}

探讨下两种配置方式的优先级问题

Springboot 默认提供属性配置< WebServerFactoryCustomizer(order>0) < TomcatXXXCustomizer


  • 默认WebServerFactoryCustomizer优先级低于TomcatXXXCustomizer,就是TomcatXXXCustomizer会覆盖WebServerFactoryCustomizer的属性配置。
  • WebServerFactoryCustomizer 基于WebServerFactoryCustomizerBeanPostProcessor来实现属性赋值
  • SpringBoot提供tomcat属性配置基于TomcatWebServerFactoryCustomizer来实现,默认优先级为0

源码解析

TomcatXXXCustomizer

  • 收集TomcatXXXCustomizer的bean-ServletWebServerFactoryConfiguration
		@Bean 
		//收集TomcatXXXCustomizer的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;
		}
  • 调用TomcatXXXCustomizer来自于org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getWebServer
	@Override
	public WebServer getWebServer(ServletContextInitializer... initializers) {
		if (this.disableMBeanRegistry) {
			Registry.disableRegistry();
		}
		Tomcat tomcat = new Tomcat();
		File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
		tomcat.setBaseDir(baseDir.getAbsolutePath());
		Connector connector = new Connector(this.protocol);
		connector.setThrowOnFailure(true);
		tomcat.getService().addConnector(connector);
		customizeConnector(connector);
		tomcat.setConnector(connector);
		tomcat.getHost().setAutoDeploy(false);
		configureEngine(tomcat.getEngine());
		for (Connector additionalConnector : this.additionalTomcatConnectors) {
			tomcat.getService().addConnector(additionalConnector);
		}
		prepareContext(tomcat.getHost(), initializers);
		return getTomcatWebServer(tomcat);
	}

WebServerFactoryCustomizer

public class WebServerFactoryCustomizerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {

	private ListableBeanFactory beanFactory;

	private List<WebServerFactoryCustomizer<?>> customizers;

	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		Assert.isInstanceOf(ListableBeanFactory.class, beanFactory,
				"WebServerCustomizerBeanPostProcessor can only be used with a ListableBeanFactory");
		this.beanFactory = (ListableBeanFactory) beanFactory;
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		
		if (bean instanceof WebServerFactory) {
			//关键点
			postProcessBeforeInitialization((WebServerFactory) bean);
		}
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@SuppressWarnings("unchecked")
	private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
		LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
				.withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
				.invoke((customizer) -> customizer.customize(webServerFactory));
	}

	private Collection<WebServerFactoryCustomizer<?>> getCustomizers() {
		if (this.customizers == null) {
			// Look up does not include the parent context
			this.customizers = new ArrayList<>(getWebServerFactoryCustomizerBeans());
			this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);
			this.customizers = Collections.unmodifiableList(this.customizers);
		}
		return this.customizers;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	//获取spring 容器里面所有的WebServerFactoryCustomizer bean,如果没有实例化进行实例化
	private Collection<WebServerFactoryCustomizer<?>> getWebServerFactoryCustomizerBeans() {
		return (Collection) this.beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values();
	}

}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值