Loading

SpringBoot : server.tomcat.connection-timeout配置解析

server.tomcat.connection-timeout配置解析

SpringBoot版本:2.2.2.RELEASE

SpringBoot Application properties文档

/**
* Amount of time the connector will wait, after accepting a connection, for the
* request URI line to be presented.
*/ 	
  • serveraccept()一个连接之后,连接等待下一个请求出现的时间

文档中这个解释,实际的意思还是不够明确,也没有说明默认值


Tomcat文档

The number of milliseconds this Connector will wait, after accepting a connection, for the request URI line to be presented. Use a value of -1 to indicate no (i.e. infinite) timeout. The default value is 60000 (i.e. 60 seconds) but note that the standard server.xml that ships with Tomcat sets this to 20000 (i.e. 20 seconds). Unless disableUploadTimeout is set to false, this timeout will also be used when reading the request body (if any).
  • 说明了默认值是60000ms
  • 如果使用的是server.xml,则为20000ms

SpringBoot中可能也为60000ms通过SpringBoot-Tomcat启动源码确认

server:
  tomcat:
    connection-timeout: 17s
  • customize()处理自定义的配置
//org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer#customize
@Override
public void customize(ConfigurableTomcatWebServerFactory factory) {
	......
    propertyMapper.from(properties::getConnectionTimeout).whenNonNull()
        .to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
    propertyMapper.from(tomcatProperties::getConnectionTimeout).whenNonNull()
        .to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
    ......
}

//org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer#customizeConnectionTimeout
private void customizeConnectionTimeout(ConfigurableTomcatWebServerFactory factory, Duration connectionTimeout) {
    factory.addConnectorCustomizers((connector) -> {
        ProtocolHandler handler = connector.getProtocolHandler();
        if (handler instanceof AbstractProtocol) {
            AbstractProtocol<?> protocol = (AbstractProtocol<?>) handler;
            //通过AbstractProtocol来设置
            protocol.setConnectionTimeout((int) connectionTimeout.toMillis());
        }
    });
}

//org.apache.coyote.AbstractProtocol#setConnectionTimeout
public void setConnectionTimeout(int timeout) {
    endpoint.setConnectionTimeout(timeout);
}

//org.apache.tomcat.util.net.AbstractEndpoint#setConnectionTimeout
public void setConnectionTimeout(int soTimeout) { socketProperties.setSoTimeout(soTimeout); }

//org.apache.tomcat.util.net.SocketProperties#setSoTimeout
public void setSoTimeout(int soTimeout) {
    this.soTimeout = Integer.valueOf(soTimeout);
}

/**
* SO_TIMEOUT option. default is 20000.
*/
protected Integer soTimeout = Integer.valueOf(20000);

SO_TIMEOUT

Enable/disable SO_TIMEOUT with the specified timeout, in milliseconds. With this option set to a non-zero timeout, a read() call on the InputStream associated with this Socket will block for only this amount of time. If the timeout expires, a java.net.SocketTimeoutException is raised, though the Socket is still valid. The option must be enabled prior to entering the blocking operation to have effect. The timeout must be > 0. A timeout of zero is interpreted as an infinite timeout.

确定默认值

  • refresh()入口
//org.springframework.context.support.AbstractApplicationContext#refresh
@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			......
			try {
				....       
				onRefresh();
                ....
			}
		}
	}

//org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
@Override
protected void onRefresh() {
    super.onRefresh();
    try {
        createWebServer();
    }
    catch (Throwable ex) {
        throw new ApplicationContextException("Unable to start web server", ex);
   
    }
}

//org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#createWebServer
private void createWebServer() {
    WebServer webServer = this.webServer;
    ServletContext servletContext = getServletContext();
    if (webServer == null && servletContext == null) {
        ServletWebServerFactory factory = getWebServerFactory();
        this.webServer = factory.getWebServer(getSelfInitializer());
    }
    else if (servletContext != null) {
        try {
            getSelfInitializer().onStartup(servletContext);
        }
        catch (ServletException ex) {
            throw new ApplicationContextException("Cannot initialize servlet context", ex);
        }
    }
    initPropertySources();
}

//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);
}
  • Connector
//org.apache.catalina.connector.Connector#Connector(java.lang.String)
public Connector(String protocol) {
        boolean aprConnector = AprLifecycleListener.isAprAvailable() &&
                AprLifecycleListener.getUseAprConnector();

        if ("HTTP/1.1".equals(protocol) || protocol == null) {
            if (aprConnector) {
                protocolHandlerClassName = "org.apache.coyote.http11.Http11AprProtocol";
            } else {
                protocolHandlerClassName = "org.apache.coyote.http11.Http11NioProtocol";
            }
        }
		.......

        // Instantiate protocol handler
        ProtocolHandler p = null;
        try {
            Class<?> clazz = Class.forName(protocolHandlerClassName);
            //实例化Http11NioProtocol对象
            p = (ProtocolHandler) clazz.getConstructor().newInstance();
        }
    	.......
    }

//org.apache.coyote.http11.Http11NioProtocol#Http11NioProtocol
public Http11NioProtocol() {
    //默认初始化一个NioEndpoint, 其中SocketProperties的soTimeout默认是20000ms
    super(new NioEndpoint());
}

public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;

//org.apache.coyote.http11.AbstractHttp11Protocol#AbstractHttp11Protocol
public AbstractHttp11Protocol(AbstractEndpoint<S,?> endpoint) {
    super(endpoint);
	//Constants.DEFAULT_CONNECTION_TIMEOUT为60000
    setConnectionTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
    ConnectionHandler<S> cHandler = new ConnectionHandler<>(this);
    setHandler(cHandler);
    getEndpoint().setHandler(cHandler);
}

//org.apache.coyote.AbstractProtocol#setConnectionTimeout
public void setConnectionTimeout(int timeout) {
    //覆盖
    endpoint.setConnectionTimeout(timeout);
}
  • 默认为60000ms

总结

  • server.tomcat.connection-timeoutsocket调用read()等待读取的时间,如果在设置的时间内没有请求,则会主动断开连接
  • SpringBoot嵌入Tomcat默认为60000ms

参考

posted @ 2022-01-11 15:48  FynnWang  阅读(15182)  评论(1编辑  收藏  举报