Spring源码分析(一)--BeanProcessor

一、何谓BeanProcessor

  BeanPostProcessor是SpringFramework里非常重要的核心接口之一,我先贴出一段源代码:

/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.springframework.beans.factory.config; import org.springframework.beans.BeansException; /**
* Factory hook that allows for custom modification of new bean instances,
* e.g. checking for marker interfaces or wrapping them with proxies.
*
* <p>ApplicationContexts can autodetect BeanPostProcessor beans in their
* bean definitions and apply them to any beans subsequently created.
* Plain bean factories allow for programmatic registration of post-processors,
* applying to all beans created through this factory.
*
* <p>Typically, post-processors that populate beans via marker interfaces
* or the like will implement {@link #postProcessBeforeInitialization},
* while post-processors that wrap beans with proxies will normally
* implement {@link #postProcessAfterInitialization}.
*
* @author Juergen Hoeller
* @since 10.10.2003
* @see InstantiationAwareBeanPostProcessor
* @see DestructionAwareBeanPostProcessor
* @see ConfigurableBeanFactory#addBeanPostProcessor
* @see BeanFactoryPostProcessor
*/
public interface BeanPostProcessor { /**
* Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
* or a custom init-method). The bean will already be populated with property values.
* The returned bean instance may be a wrapper around the original.
* @param bean the new bean instance
* @param beanName the name of the bean
* @return the bean instance to use, either the original or a wrapped one;
* if {@code null}, no subsequent BeanPostProcessors will be invoked
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
*/
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; /**
* Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
* or a custom init-method). The bean will already be populated with property values.
* The returned bean instance may be a wrapper around the original.
* <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
* instance and the objects created by the FactoryBean (as of Spring 2.0). The
* post-processor can decide whether to apply to either the FactoryBean or created
* objects or both through corresponding {@code bean instanceof FactoryBean} checks.
* <p>This callback will also be invoked after a short-circuiting triggered by a
* {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
* in contrast to all other BeanPostProcessor callbacks.
* @param bean the new bean instance
* @param beanName the name of the bean
* @return the bean instance to use, either the original or a wrapped one;
* if {@code null}, no subsequent BeanPostProcessors will be invoked
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
* @see org.springframework.beans.factory.FactoryBean
*/
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }

  在这里我先简单解释一下其注释的含义:

  这个接口允许我们自定义修改新bean的一个实例,比如说:检查它们的接口或者将他们包装成代理对象等,ApplicationContexts能自动察觉到我们在BeanProcessor里对对象作出的改变,并在后来创建该对象时应用其对应的改变。

  这两个方法分别对应IOC容器对对象初始化前的操作和对象初始化后的操作

  下面我们来演示一个例子:

  StudentEntity:

package org.hzgj.spring.study.entity;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; public class StudentEntity { private Integer id; private String name; private Map<String,String> memerories= new HashMap<>(); public Map<String, String> getMemerories() {
return memerories;
} public void setMemerories(Map<String, String> memerories) {
this.memerories = memerories;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public StudentEntity() {
// System.out.println("studentEntity initializer....");
} @Override
public String toString() {
return "StudentEntity{" +
"id=" + id +
", name='" + name + '\'' +
'}';
} private List<String> hobbies=new ArrayList<>(); public List<String> getHobbies() {
return hobbies;
} public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
}

  

  TestBeanPostProcessor:

package org.hzgj.spring.study.context;

import org.hzgj.spring.study.entity.StudentEntity;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor; public class TestBeanPostProcessor implements BeanPostProcessor { @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof StudentEntity) {
StudentEntity studentEntity = new StudentEntity();
studentEntity.setName(beanName);
return studentEntity;
}
return bean;
} @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof StudentEntity)
System.out.println(bean);
return bean;
}
}

  Main方法:

package org.hzgj.spring.study;

import org.hzgj.spring.study.entity.StudentEntity;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-config.xml");
StudentEntity studentEntity = applicationContext.getBean(StudentEntity.class);
System.out.println(studentEntity.getName()); }
}

  

  spring-config.xml关键代码:

    <bean id="studentEntity"  class="org.hzgj.spring.study.entity.StudentEntity" depends-on="studentServiceWithFactory">
<property name="hobbies" ref="hobbies">
</property>
<property name="memerories">
<map>
<entry key="glad" value="play"/>
<entry key="cry" value="cry"/>
</map>
</property>
<property name="name" value="admin"/>
</bean> <bean id="beanPostProcessor" class="org.hzgj.spring.study.context.TestBeanPostProcessor" />

  运行得到如下结果:

Spring源码分析(一)--BeanProcessor

  我们可以看到在配置文件里定义的bean属性已经发生改变

二、SpringFramework中BeanPostProcessor经典应用场景

1.初始化BeanPostProcessor的源码

根据 ClassPathXmlApplicationContext的构造方法,我们可以看到该类初始化的时候会调用refresh():

/**
* Create a new ClassPathXmlApplicationContext with the given parent,
* loading the definitions from the given XML files.
* @param configLocations array of resource locations
* @param refresh whether to automatically refresh the context,
* loading all bean definitions and creating all singletons.
* Alternatively, call refresh manually after further configuring the context.
* @param parent the parent context
* @throws BeansException if context creation failed
* @see #refresh()
*/
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException { super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}

那么紧接着在AbstractApplicationContext中找到refresh()方法:

@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh(); // Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory); // Initialize message source for this context.
initMessageSource(); // Initialize event multicaster for this context.
initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.
onRefresh(); // Check for listener beans and register them.
registerListeners(); // Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event.
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
} // Destroy already created singletons to avoid dangling resources.
destroyBeans(); // Reset 'active' flag.
cancelRefresh(ex); // Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

那么在这里Spring会进行一系列的初始化操作,我们请留意registerBeanPostProcessors(beanFactory);这句代码,追踪一下我们可以看到在该方法里注册Processor:

public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); // Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); // Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
} // First, register the BeanPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); // Next, register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors); // Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); // Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors); // Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

2.@Autowired实现的代码跟踪

Spring源码分析(一)--BeanProcessor

注意AutowiredAnnotationBeanPostProcessor最终也是BeanPostProcessor的实现类,具体类的描述我就不再这里阐述了,大家可自行查看源码

3、SpringBoot中的定制化内嵌web容器

Spring源码分析(一)--BeanProcessor

这个EmbeddedServletContainerCustomizerBeanPostProcessor直接实现的就是BeanPostProcessor,该类下请关注如下方法:

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof ConfigurableEmbeddedServletContainer) {
postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
}
return bean;
}
private void postProcessBeforeInitialization(
ConfigurableEmbeddedServletContainer bean) {
for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {
customizer.customize(bean);
}
}
private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {
if (this.customizers == null) {
// Look up does not include the parent context
this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
this.beanFactory
.getBeansOfType(EmbeddedServletContainerCustomizer.class,
false, false)
.values());
Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
this.customizers = Collections.unmodifiableList(this.customizers);
}
return this.customizers;
}

这里面有一个接口:EmbeddedServletContainerCustomizer 该接口有个实现类 ServerProperties 熟悉springboot外部化配置原理的同胞们其实一看便知

/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.springframework.boot.autoconfigure.web; import java.io.File;
import java.net.InetAddress;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set; import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.SessionCookieConfig;
import javax.servlet.SessionTrackingMode; import io.undertow.Undertow.Builder;
import io.undertow.UndertowOptions;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.valves.AccessLogValve;
import org.apache.catalina.valves.ErrorReportValve;
import org.apache.catalina.valves.RemoteIpValve;
import org.apache.coyote.AbstractProtocol;
import org.apache.coyote.ProtocolHandler;
import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.eclipse.jetty.server.AbstractConnector;
import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.HandlerWrapper; import org.springframework.boot.autoconfigure.web.ServerProperties.Session.Cookie;
import org.springframework.boot.cloud.CloudPlatform;
import org.springframework.boot.context.embedded.Compression;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.InitParameterConfiguringServletContextInitializer;
import org.springframework.boot.context.embedded.JspServlet;
import org.springframework.boot.context.embedded.Ssl;
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.jetty.JettyServerCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.undertow.UndertowBuilderCustomizer;
import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils; /**
* {@link ConfigurationProperties} for a web server (e.g. port and path settings). Will be
* used to customize an {@link EmbeddedServletContainerFactory} when an
* {@link EmbeddedServletContainerCustomizerBeanPostProcessor} is active.
*
* @author Dave Syer
* @author Stephane Nicoll
* @author Andy Wilkinson
* @author Ivan Sopov
* @author Marcos Barbero
* @author Eddú Meléndez
* @author Quinten De Swaef
* @author Venil Noronha
* @author Aurélien Leboulanger
*/
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties
implements EmbeddedServletContainerCustomizer, EnvironmentAware, Ordered { /**
* Server HTTP port.
*/
private Integer port; /**
* Network address to which the server should bind to.
*/
private InetAddress address; /**
* Context path of the application.
*/
private String contextPath; /**
* Display name of the application.
*/
private String displayName = "application"; @NestedConfigurationProperty
private ErrorProperties error = new ErrorProperties(); /**
* Path of the main dispatcher servlet.
*/
private String servletPath = "/"; /**
* ServletContext parameters.
*/
private final Map<String, String> contextParameters = new HashMap<String, String>(); /**
* If X-Forwarded-* headers should be applied to the HttpRequest.
*/
private Boolean useForwardHeaders; /**
* Value to use for the Server response header (no header is sent if empty).
*/
private String serverHeader; /**
* Maximum size in bytes of the HTTP message header.
*/
private int maxHttpHeaderSize = 0; // bytes /**
* Maximum size in bytes of the HTTP post content.
*/
private int maxHttpPostSize = 0; // bytes /**
* Time in milliseconds that connectors will wait for another HTTP request before
* closing the connection. When not set, the connector's container-specific default
* will be used. Use a value of -1 to indicate no (i.e. infinite) timeout.
*/
private Integer connectionTimeout; private Session session = new Session(); @NestedConfigurationProperty
private Ssl ssl; @NestedConfigurationProperty
private Compression compression = new Compression(); @NestedConfigurationProperty
private JspServlet jspServlet; private final Tomcat tomcat = new Tomcat(); private final Jetty jetty = new Jetty(); private final Undertow undertow = new Undertow(); private Environment environment; @Override
public int getOrder() {
return 0;
} @Override
public void setEnvironment(Environment environment) {
this.environment = environment;
} @Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (getPort() != null) {
container.setPort(getPort());
}
if (getAddress() != null) {
container.setAddress(getAddress());
}
if (getContextPath() != null) {
container.setContextPath(getContextPath());
}
if (getDisplayName() != null) {
container.setDisplayName(getDisplayName());
}
if (getSession().getTimeout() != null) {
container.setSessionTimeout(getSession().getTimeout());
}
container.setPersistSession(getSession().isPersistent());
container.setSessionStoreDir(getSession().getStoreDir());
if (getSsl() != null) {
container.setSsl(getSsl());
}
if (getJspServlet() != null) {
container.setJspServlet(getJspServlet());
}
if (getCompression() != null) {
container.setCompression(getCompression());
}
container.setServerHeader(getServerHeader());
if (container instanceof TomcatEmbeddedServletContainerFactory) {
getTomcat().customizeTomcat(this,
(TomcatEmbeddedServletContainerFactory) container);
}
if (container instanceof JettyEmbeddedServletContainerFactory) {
getJetty().customizeJetty(this,
(JettyEmbeddedServletContainerFactory) container);
} if (container instanceof UndertowEmbeddedServletContainerFactory) {
getUndertow().customizeUndertow(this,
(UndertowEmbeddedServletContainerFactory) container);
}
container.addInitializers(new SessionConfiguringInitializer(this.session));
container.addInitializers(new InitParameterConfiguringServletContextInitializer(
getContextParameters()));
} public String getServletMapping() {
if (this.servletPath.equals("") || this.servletPath.equals("/")) {
return "/";
}
if (this.servletPath.contains("*")) {
return this.servletPath;
}
if (this.servletPath.endsWith("/")) {
return this.servletPath + "*";
}
return this.servletPath + "/*";
} public String getPath(String path) {
String prefix = getServletPrefix();
if (!path.startsWith("/")) {
path = "/" + path;
}
return prefix + path;
} public String getServletPrefix() {
String result = this.servletPath;
if (result.contains("*")) {
result = result.substring(0, result.indexOf("*"));
}
if (result.endsWith("/")) {
result = result.substring(0, result.length() - 1);
}
return result;
} public String[] getPathsArray(Collection<String> paths) {
String[] result = new String[paths.size()];
int i = 0;
for (String path : paths) {
result[i++] = getPath(path);
}
return result;
} public String[] getPathsArray(String[] paths) {
String[] result = new String[paths.length];
int i = 0;
for (String path : paths) {
result[i++] = getPath(path);
}
return result;
} public void setLoader(String value) {
// no op to support Tomcat running as a traditional container (not embedded)
} public Integer getPort() {
return this.port;
} public void setPort(Integer port) {
this.port = port;
} public InetAddress getAddress() {
return this.address;
} public void setAddress(InetAddress address) {
this.address = address;
} public String getContextPath() {
return this.contextPath;
} public void setContextPath(String contextPath) {
this.contextPath = cleanContextPath(contextPath);
} private String cleanContextPath(String contextPath) {
if (StringUtils.hasText(contextPath) && contextPath.endsWith("/")) {
return contextPath.substring(0, contextPath.length() - 1);
}
return contextPath;
} public String getDisplayName() {
return this.displayName;
} public void setDisplayName(String displayName) {
this.displayName = displayName;
} public String getServletPath() {
return this.servletPath;
} public void setServletPath(String servletPath) {
Assert.notNull(servletPath, "ServletPath must not be null");
this.servletPath = servletPath;
} public Map<String, String> getContextParameters() {
return this.contextParameters;
} public Boolean isUseForwardHeaders() {
return this.useForwardHeaders;
} public void setUseForwardHeaders(Boolean useForwardHeaders) {
this.useForwardHeaders = useForwardHeaders;
} public String getServerHeader() {
return this.serverHeader;
} public void setServerHeader(String serverHeader) {
this.serverHeader = serverHeader;
} public int getMaxHttpHeaderSize() {
return this.maxHttpHeaderSize;
} public void setMaxHttpHeaderSize(int maxHttpHeaderSize) {
this.maxHttpHeaderSize = maxHttpHeaderSize;
} @Deprecated
@DeprecatedConfigurationProperty(reason = "Use dedicated property for each container.")
public int getMaxHttpPostSize() {
return this.maxHttpPostSize;
} @Deprecated
public void setMaxHttpPostSize(int maxHttpPostSize) {
this.maxHttpPostSize = maxHttpPostSize;
this.jetty.setMaxHttpPostSize(maxHttpPostSize);
this.tomcat.setMaxHttpPostSize(maxHttpPostSize);
this.undertow.setMaxHttpPostSize(maxHttpPostSize);
} protected final boolean getOrDeduceUseForwardHeaders() {
if (this.useForwardHeaders != null) {
return this.useForwardHeaders;
}
CloudPlatform platform = CloudPlatform.getActive(this.environment);
return (platform == null ? false : platform.isUsingForwardHeaders());
} public Integer getConnectionTimeout() {
return this.connectionTimeout;
} public void setConnectionTimeout(Integer connectionTimeout) {
this.connectionTimeout = connectionTimeout;
} public ErrorProperties getError() {
return this.error;
} public Session getSession() {
return this.session;
} public void setSession(Session session) {
this.session = session;
} public Ssl getSsl() {
return this.ssl;
} public void setSsl(Ssl ssl) {
this.ssl = ssl;
} public Compression getCompression() {
return this.compression;
} public JspServlet getJspServlet() {
return this.jspServlet;
} public void setJspServlet(JspServlet jspServlet) {
this.jspServlet = jspServlet;
} public Tomcat getTomcat() {
return this.tomcat;
} public Jetty getJetty() {
return this.jetty;
} public Undertow getUndertow() {
return this.undertow;
} public static class Session { /**
* Session timeout in seconds.
*/
private Integer timeout; /**
* Session tracking modes (one or more of the following: "cookie", "url", "ssl").
*/
private Set<SessionTrackingMode> trackingModes; /**
* Persist session data between restarts.
*/
private boolean persistent; /**
* Directory used to store session data.
*/
private File storeDir; private Cookie cookie = new Cookie(); public Cookie getCookie() {
return this.cookie;
} public Integer getTimeout() {
return this.timeout;
} public void setTimeout(Integer sessionTimeout) {
this.timeout = sessionTimeout;
} public Set<SessionTrackingMode> getTrackingModes() {
return this.trackingModes;
} public void setTrackingModes(Set<SessionTrackingMode> trackingModes) {
this.trackingModes = trackingModes;
} public boolean isPersistent() {
return this.persistent;
} public void setPersistent(boolean persistent) {
this.persistent = persistent;
} public File getStoreDir() {
return this.storeDir;
} public void setStoreDir(File storeDir) {
this.storeDir = storeDir;
} public static class Cookie { /**
* Session cookie name.
*/
private String name; /**
* Domain for the session cookie.
*/
private String domain; /**
* Path of the session cookie.
*/
private String path; /**
* Comment for the session cookie.
*/
private String comment; /**
* "HttpOnly" flag for the session cookie.
*/
private Boolean httpOnly; /**
* "Secure" flag for the session cookie.
*/
private Boolean secure; /**
* Maximum age of the session cookie in seconds.
*/
private Integer maxAge; public String getName() {
return this.name;
} public void setName(String name) {
this.name = name;
} public String getDomain() {
return this.domain;
} public void setDomain(String domain) {
this.domain = domain;
} public String getPath() {
return this.path;
} public void setPath(String path) {
this.path = path;
} public String getComment() {
return this.comment;
} public void setComment(String comment) {
this.comment = comment;
} public Boolean getHttpOnly() {
return this.httpOnly;
} public void setHttpOnly(Boolean httpOnly) {
this.httpOnly = httpOnly;
} public Boolean getSecure() {
return this.secure;
} public void setSecure(Boolean secure) {
this.secure = secure;
} public Integer getMaxAge() {
return this.maxAge;
} public void setMaxAge(Integer maxAge) {
this.maxAge = maxAge;
} } } public static class Tomcat { /**
* Access log configuration.
*/
private final Accesslog accesslog = new Accesslog(); /**
* Regular expression that matches proxies that are to be trusted.
*/
private String internalProxies = "10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" // 10/8
+ "192\\.168\\.\\d{1,3}\\.\\d{1,3}|" // 192.168/16
+ "169\\.254\\.\\d{1,3}\\.\\d{1,3}|" // 169.254/16
+ "127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" // 127/8
+ "172\\.1[6-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" // 172.16/12
+ "172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|"
+ "172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3}"; /**
* Header that holds the incoming protocol, usually named "X-Forwarded-Proto".
*/
private String protocolHeader; /**
* Value of the protocol header that indicates that the incoming request uses SSL.
*/
private String protocolHeaderHttpsValue = "https"; /**
* Name of the HTTP header used to override the original port value.
*/
private String portHeader = "X-Forwarded-Port"; /**
* Name of the http header from which the remote ip is extracted..
*/
private String remoteIpHeader; /**
* Tomcat base directory. If not specified a temporary directory will be used.
*/
private File basedir; /**
* Delay in seconds between the invocation of backgroundProcess methods.
*/
private int backgroundProcessorDelay = 30; // seconds /**
* Maximum amount of worker threads.
*/
private int maxThreads = 0; // Number of threads in protocol handler /**
* Minimum amount of worker threads.
*/
private int minSpareThreads = 0; // Minimum spare threads in protocol handler /**
* Maximum size in bytes of the HTTP post content.
*/
private int maxHttpPostSize = 0; // bytes /**
* Maximum size in bytes of the HTTP message header.
*/
private int maxHttpHeaderSize = 0; // bytes /**
* Whether requests to the context root should be redirected by appending a / to
* the path.
*/
private Boolean redirectContextRoot; /**
* Character encoding to use to decode the URI.
*/
private Charset uriEncoding; /**
* Maximum number of connections that the server will accept and process at any
* given time. Once the limit has been reached, the operating system may still
* accept connections based on the "acceptCount" property.
*/
private int maxConnections = 0; /**
* Maximum queue length for incoming connection requests when all possible request
* processing threads are in use.
*/
private int acceptCount = 0; /**
* Comma-separated list of additional patterns that match jars to ignore for TLD
* scanning. The special '?' and '*' characters can be used in the pattern to
* match one and only one character and zero or more characters respectively.
*/
private List<String> additionalTldSkipPatterns = new ArrayList<String>(); public int getMaxThreads() {
return this.maxThreads;
} public void setMaxThreads(int maxThreads) {
this.maxThreads = maxThreads;
} public int getMinSpareThreads() {
return this.minSpareThreads;
} public void setMinSpareThreads(int minSpareThreads) {
this.minSpareThreads = minSpareThreads;
} public int getMaxHttpPostSize() {
return this.maxHttpPostSize;
} public void setMaxHttpPostSize(int maxHttpPostSize) {
this.maxHttpPostSize = maxHttpPostSize;
} public Accesslog getAccesslog() {
return this.accesslog;
} public int getBackgroundProcessorDelay() {
return this.backgroundProcessorDelay;
} public void setBackgroundProcessorDelay(int backgroundProcessorDelay) {
this.backgroundProcessorDelay = backgroundProcessorDelay;
} public File getBasedir() {
return this.basedir;
} public void setBasedir(File basedir) {
this.basedir = basedir;
} public String getInternalProxies() {
return this.internalProxies;
} public void setInternalProxies(String internalProxies) {
this.internalProxies = internalProxies;
} public String getProtocolHeader() {
return this.protocolHeader;
} public void setProtocolHeader(String protocolHeader) {
this.protocolHeader = protocolHeader;
} public String getProtocolHeaderHttpsValue() {
return this.protocolHeaderHttpsValue;
} public void setProtocolHeaderHttpsValue(String protocolHeaderHttpsValue) {
this.protocolHeaderHttpsValue = protocolHeaderHttpsValue;
} public String getPortHeader() {
return this.portHeader;
} public void setPortHeader(String portHeader) {
this.portHeader = portHeader;
} public Boolean getRedirectContextRoot() {
return this.redirectContextRoot;
} public void setRedirectContextRoot(Boolean redirectContextRoot) {
this.redirectContextRoot = redirectContextRoot;
} public String getRemoteIpHeader() {
return this.remoteIpHeader;
} public void setRemoteIpHeader(String remoteIpHeader) {
this.remoteIpHeader = remoteIpHeader;
} public Charset getUriEncoding() {
return this.uriEncoding;
} public void setUriEncoding(Charset uriEncoding) {
this.uriEncoding = uriEncoding;
} public int getMaxConnections() {
return this.maxConnections;
} public void setMaxConnections(int maxConnections) {
this.maxConnections = maxConnections;
} public int getAcceptCount() {
return this.acceptCount;
} public void setAcceptCount(int acceptCount) {
this.acceptCount = acceptCount;
} public List<String> getAdditionalTldSkipPatterns() {
return this.additionalTldSkipPatterns;
} public void setAdditionalTldSkipPatterns(List<String> additionalTldSkipPatterns) {
this.additionalTldSkipPatterns = additionalTldSkipPatterns;
} void customizeTomcat(ServerProperties serverProperties,
TomcatEmbeddedServletContainerFactory factory) {
if (getBasedir() != null) {
factory.setBaseDirectory(getBasedir());
}
factory.setBackgroundProcessorDelay(Tomcat.this.backgroundProcessorDelay);
customizeRemoteIpValve(serverProperties, factory);
if (this.maxThreads > 0) {
customizeMaxThreads(factory);
}
if (this.minSpareThreads > 0) {
customi*Threads(factory);
}
int maxHttpHeaderSize = (serverProperties.getMaxHttpHeaderSize() > 0
? serverProperties.getMaxHttpHeaderSize() : this.maxHttpHeaderSize);
if (maxHttpHeaderSize > 0) {
customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize);
}
if (this.maxHttpPostSize != 0) {
customizeMaxHttpPostSize(factory, this.maxHttpPostSize);
}
if (this.accesslog.enabled) {
customizeAccessLog(factory);
}
if (getUriEncoding() != null) {
factory.setUriEncoding(getUriEncoding());
}
if (serverProperties.getConnectionTimeout() != null) {
customizeConnectionTimeout(factory,
serverProperties.getConnectionTimeout());
}
if (this.redirectContextRoot != null) {
customizeRedirectContextRoot(factory, this.redirectContextRoot);
}
if (this.maxConnections > 0) {
customizeMaxConnections(factory);
}
if (this.acceptCount > 0) {
customizeAcceptCount(factory);
}
if (!ObjectUtils.isEmpty(this.additionalTldSkipPatterns)) {
factory.getTldSkipPatterns().addAll(this.additionalTldSkipPatterns);
}
if (serverProperties.getError()
.getIncludeStacktrace() == ErrorProperties.IncludeStacktrace.NEVER) {
customizeErrorReportValve(factory);
}
} private void customizeErrorReportValve(
TomcatEmbeddedServletContainerFactory factory) {
factory.addContextCustomizers(new TomcatContextCustomizer() { @Override
public void customize(Context context) {
ErrorReportValve valve = new ErrorReportValve();
valve.setShowServerInfo(false);
valve.setShowReport(false);
context.getParent().getPipeline().addValve(valve);
} });
} private void customizeAcceptCount(TomcatEmbeddedServletContainerFactory factory) {
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { @Override
@SuppressWarnings("deprecation")
public void customize(Connector connector) {
ProtocolHandler handler = connector.getProtocolHandler();
if (handler instanceof AbstractProtocol) {
AbstractProtocol<?> protocol = (AbstractProtocol<?>) handler;
protocol.setBacklog(Tomcat.this.acceptCount);
}
} });
} private void customizeMaxConnections(
TomcatEmbeddedServletContainerFactory factory) {
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { @Override
public void customize(Connector connector) {
ProtocolHandler handler = connector.getProtocolHandler();
if (handler instanceof AbstractProtocol) {
AbstractProtocol<?> protocol = (AbstractProtocol<?>) handler;
protocol.setMaxConnections(Tomcat.this.maxConnections);
}
} });
} private void customizeConnectionTimeout(
TomcatEmbeddedServletContainerFactory factory,
final int connectionTimeout) {
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { @Override
public void customize(Connector connector) {
ProtocolHandler handler = connector.getProtocolHandler();
if (handler instanceof AbstractProtocol) {
AbstractProtocol<?> protocol = (AbstractProtocol<?>) handler;
protocol.setConnectionTimeout(connectionTimeout);
}
} });
} private void customizeRemoteIpValve(ServerProperties properties,
TomcatEmbeddedServletContainerFactory factory) {
String protocolHeader = getProtocolHeader();
String remoteIpHeader = getRemoteIpHeader();
// For back compatibility the valve is also enabled if protocol-header is set
if (StringUtils.hasText(protocolHeader) || StringUtils.hasText(remoteIpHeader)
|| properties.getOrDeduceUseForwardHeaders()) {
RemoteIpValve valve = new RemoteIpValve();
valve.setProtocolHeader(StringUtils.hasLength(protocolHeader)
? protocolHeader : "X-Forwarded-Proto");
if (StringUtils.hasLength(remoteIpHeader)) {
valve.setRemoteIpHeader(remoteIpHeader);
}
// The internal proxies default to a white list of "safe" internal IP
// addresses
valve.setInternalProxies(getInternalProxies());
valve.setPortHeader(getPortHeader());
valve.setProtocolHeaderHttpsValue(getProtocolHeaderHttpsValue());
// ... so it's safe to add this valve by default.
factory.addEngineValves(valve);
}
} @SuppressWarnings("rawtypes")
private void customizeMaxThreads(TomcatEmbeddedServletContainerFactory factory) {
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) { ProtocolHandler handler = connector.getProtocolHandler();
if (handler instanceof AbstractProtocol) {
AbstractProtocol protocol = (AbstractProtocol) handler;
protocol.setMaxThreads(Tomcat.this.maxThreads);
} }
});
} @SuppressWarnings("rawtypes")
private void customi*Threads(TomcatEmbeddedServletContainerFactory factory) {
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) { ProtocolHandler handler = connector.getProtocolHandler();
if (handler instanceof AbstractProtocol) {
AbstractProtocol protocol = (AbstractProtocol) handler;
protocol.setMinSpareThreads(Tomcat.this.minSpareThreads);
} }
});
} @SuppressWarnings("rawtypes")
private void customizeMaxHttpHeaderSize(
TomcatEmbeddedServletContainerFactory factory,
final int maxHttpHeaderSize) {
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { @Override
public void customize(Connector connector) {
ProtocolHandler handler = connector.getProtocolHandler();
if (handler instanceof AbstractHttp11Protocol) {
AbstractHttp11Protocol protocol = (AbstractHttp11Protocol) handler;
protocol.setMaxHttpHeaderSize(maxHttpHeaderSize);
}
} });
} private void customizeMaxHttpPostSize(
TomcatEmbeddedServletContainerFactory factory,
final int maxHttpPostSize) {
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { @Override
public void customize(Connector connector) {
connector.setMaxPostSize(maxHttpPostSize);
} });
} private void customizeAccessLog(TomcatEmbeddedServletContainerFactory factory) {
AccessLogValve valve = new AccessLogValve();
valve.setPattern(this.accesslog.getPattern());
valve.setDirectory(this.accesslog.getDirectory());
valve.setPrefix(this.accesslog.getPrefix());
valve.setSuffix(this.accesslog.getSuffix());
valve.setRenameOnRotate(this.accesslog.isRenameOnRotate());
valve.setRequestAttributesEnabled(
this.accesslog.isRequestAttributesEnabled());
valve.setRotatable(this.accesslog.isRotate());
valve.setBuffered(this.accesslog.isBuffered());
valve.setFileDateFormat(this.accesslog.getFileDateFormat());
factory.addEngineValves(valve);
} private void customizeRedirectContextRoot(
TomcatEmbeddedServletContainerFactory factory,
final boolean redirectContextRoot) {
factory.addContextCustomizers(new TomcatContextCustomizer() { @Override
public void customize(Context context) {
context.setMapperContextRootRedirectEnabled(redirectContextRoot);
} });
} public static class Accesslog { /**
* Enable access log.
*/
private boolean enabled = false; /**
* Format pattern for access logs.
*/
private String pattern = "common"; /**
* Directory in which log files are created. Can be relative to the tomcat
* base dir or absolute.
*/
private String directory = "logs"; /**
* Log file name prefix.
*/
protected String prefix = "access_log"; /**
* Log file name suffix.
*/
private String suffix = ".log"; /**
* Enable access log rotation.
*/
private boolean rotate = true; /**
* Defer inclusion of the date stamp in the file name until rotate time.
*/
private boolean renameOnRotate; /**
* Date format to place in log file name.
*/
private String fileDateFormat = ".yyyy-MM-dd"; /**
* Set request attributes for IP address, Hostname, protocol and port used for
* the request.
*/
private boolean requestAttributesEnabled; /**
* Buffer output such that it is only flushed periodically.
*/
private boolean buffered = true; public boolean isEnabled() {
return this.enabled;
} public void setEnabled(boolean enabled) {
this.enabled = enabled;
} public String getPattern() {
return this.pattern;
} public void setPattern(String pattern) {
this.pattern = pattern;
} public String getDirectory() {
return this.directory;
} public void setDirectory(String directory) {
this.directory = directory;
} public String getPrefix() {
return this.prefix;
} public void setPrefix(String prefix) {
this.prefix = prefix;
} public String getSuffix() {
return this.suffix;
} public void setSuffix(String suffix) {
this.suffix = suffix;
} public boolean isRotate() {
return this.rotate;
} public void setRotate(boolean rotate) {
this.rotate = rotate;
} public boolean isRenameOnRotate() {
return this.renameOnRotate;
} public void setRenameOnRotate(boolean renameOnRotate) {
this.renameOnRotate = renameOnRotate;
} public String getFileDateFormat() {
return this.fileDateFormat;
} public void setFileDateFormat(String fileDateFormat) {
this.fileDateFormat = fileDateFormat;
} public boolean isRequestAttributesEnabled() {
return this.requestAttributesEnabled;
} public void setRequestAttributesEnabled(boolean requestAttributesEnabled) {
this.requestAttributesEnabled = requestAttributesEnabled;
} public boolean isBuffered() {
return this.buffered;
} public void setBuffered(boolean buffered) {
this.buffered = buffered;
} } } public static class Jetty { /**
* Maximum size in bytes of the HTTP post or put content.
*/
private int maxHttpPostSize = 0; // bytes /**
* Number of acceptor threads to use.
*/
private Integer acceptors; /**
* Number of selector threads to use.
*/
private Integer selectors; public int getMaxHttpPostSize() {
return this.maxHttpPostSize;
} public void setMaxHttpPostSize(int maxHttpPostSize) {
this.maxHttpPostSize = maxHttpPostSize;
} public Integer getAcceptors() {
return this.acceptors;
} public void setAcceptors(Integer acceptors) {
this.acceptors = acceptors;
} public Integer getSelectors() {
return this.selectors;
} public void setSelectors(Integer selectors) {
this.selectors = selectors;
} void customizeJetty(final ServerProperties serverProperties,
JettyEmbeddedServletContainerFactory factory) {
factory.setUseForwardHeaders(serverProperties.getOrDeduceUseForwardHeaders());
if (this.acceptors != null) {
factory.setAcceptors(this.acceptors);
}
if (this.selectors != null) {
factory.setSelectors(this.selectors);
}
if (serverProperties.getMaxHttpHeaderSize() > 0) {
customizeMaxHttpHeaderSize(factory,
serverProperties.getMaxHttpHeaderSize());
}
if (this.maxHttpPostSize > 0) {
customizeMaxHttpPostSize(factory, this.maxHttpPostSize);
} if (serverProperties.getConnectionTimeout() != null) {
customizeConnectionTimeout(factory,
serverProperties.getConnectionTimeout());
}
} private void customizeConnectionTimeout(
JettyEmbeddedServletContainerFactory factory,
final int connectionTimeout) {
factory.addServerCustomizers(new JettyServerCustomizer() { @Override
public void customize(Server server) {
for (org.eclipse.jetty.server.Connector connector : server
.getConnectors()) {
if (connector instanceof AbstractConnector) {
((AbstractConnector) connector)
.setIdleTimeout(connectionTimeout);
}
}
} });
} private void customizeMaxHttpHeaderSize(
JettyEmbeddedServletContainerFactory factory,
final int maxHttpHeaderSize) {
factory.addServerCustomizers(new JettyServerCustomizer() { @Override
public void customize(Server server) {
for (org.eclipse.jetty.server.Connector connector : server
.getConnectors()) {
try {
for (ConnectionFactory connectionFactory : connector
.getConnectionFactories()) {
if (connectionFactory instanceof HttpConfiguration.ConnectionFactory) {
customize(
(HttpConfiguration.ConnectionFactory) connectionFactory);
}
}
}
catch (NoSuchMethodError ex) {
customizeOnJetty8(connector, maxHttpHeaderSize);
}
} } private void customize(HttpConfiguration.ConnectionFactory factory) {
HttpConfiguration configuration = factory.getHttpConfiguration();
configuration.setRequestHeaderSize(maxHttpHeaderSize);
configuration.setResponseHeaderSize(maxHttpHeaderSize);
} private void customizeOnJetty8(
org.eclipse.jetty.server.Connector connector,
int maxHttpHeaderSize) {
try {
connector.getClass().getMethod("setRequestHeaderSize", int.class)
.invoke(connector, maxHttpHeaderSize);
connector.getClass().getMethod("setResponseHeaderSize", int.class)
.invoke(connector, maxHttpHeaderSize);
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
} });
} private void customizeMaxHttpPostSize(
JettyEmbeddedServletContainerFactory factory, final int maxHttpPostSize) {
factory.addServerCustomizers(new JettyServerCustomizer() { @Override
public void customize(Server server) {
setHandlerMaxHttpPostSize(maxHttpPostSize, server.getHandlers());
} private void setHandlerMaxHttpPostSize(int maxHttpPostSize,
Handler... handlers) {
for (Handler handler : handlers) {
if (handler instanceof ContextHandler) {
((ContextHandler) handler)
.setMaxFormContentSize(maxHttpPostSize);
}
else if (handler instanceof HandlerWrapper) {
setHandlerMaxHttpPostSize(maxHttpPostSize,
((HandlerWrapper) handler).getHandler());
}
else if (handler instanceof HandlerCollection) {
setHandlerMaxHttpPostSize(maxHttpPostSize,
((HandlerCollection) handler).getHandlers());
}
}
} });
} } public static class Undertow { /**
* Maximum size in bytes of the HTTP post content.
*/
private long maxHttpPostSize = 0; // bytes /**
* Size of each buffer in bytes.
*/
private Integer bufferSize; /**
* Number of buffer per region.
*/
@Deprecated
private Integer buffersPerRegion; /**
* Number of I/O threads to create for the worker.
*/
private Integer ioThreads; /**
* Number of worker threads.
*/
private Integer workerThreads; /**
* Allocate buffers outside the Java heap.
*/
private Boolean directBuffers; private final Accesslog accesslog = new Accesslog(); public long getMaxHttpPostSize() {
return this.maxHttpPostSize;
} public void setMaxHttpPostSize(long maxHttpPostSize) {
this.maxHttpPostSize = maxHttpPostSize;
} public Integer getBufferSize() {
return this.bufferSize;
} public void setBufferSize(Integer bufferSize) {
this.bufferSize = bufferSize;
} @DeprecatedConfigurationProperty(reason = "The property is not used by Undertow. See https://issues.jboss.org/browse/UNDERTOW-587 for details")
public Integer getBuffersPerRegion() {
return this.buffersPerRegion;
} public void setBuffersPerRegion(Integer buffersPerRegion) {
this.buffersPerRegion = buffersPerRegion;
} public Integer getIoThreads() {
return this.ioThreads;
} public void setIoThreads(Integer ioThreads) {
this.ioThreads = ioThreads;
} public Integer getWorkerThreads() {
return this.workerThreads;
} public void setWorkerThreads(Integer workerThreads) {
this.workerThreads = workerThreads;
} public Boolean getDirectBuffers() {
return this.directBuffers;
} public void setDirectBuffers(Boolean directBuffers) {
this.directBuffers = directBuffers;
} public Accesslog getAccesslog() {
return this.accesslog;
} void customizeUndertow(final ServerProperties serverProperties,
UndertowEmbeddedServletContainerFactory factory) {
if (this.bufferSize != null) {
factory.setBufferSize(this.bufferSize);
}
if (this.ioThreads != null) {
factory.setIoThreads(this.ioThreads);
}
if (this.workerThreads != null) {
factory.setWorkerThreads(this.workerThreads);
}
if (this.directBuffers != null) {
factory.setDirectBuffers(this.directBuffers);
}
if (this.accesslog.enabled != null) {
factory.setAccessLogEnabled(this.accesslog.enabled);
}
factory.setAccessLogDirectory(this.accesslog.dir);
factory.setAccessLogPattern(this.accesslog.pattern);
factory.setAccessLogPrefix(this.accesslog.prefix);
factory.setAccessLogSuffix(this.accesslog.suffix);
factory.setAccessLogRotate(this.accesslog.rotate);
factory.setUseForwardHeaders(serverProperties.getOrDeduceUseForwardHeaders());
if (serverProperties.getMaxHttpHeaderSize() > 0) {
customizeMaxHttpHeaderSize(factory,
serverProperties.getMaxHttpHeaderSize());
}
if (this.maxHttpPostSize > 0) {
customizeMaxHttpPostSize(factory, this.maxHttpPostSize);
} if (serverProperties.getConnectionTimeout() != null) {
customizeConnectionTimeout(factory,
serverProperties.getConnectionTimeout());
}
} private void customizeConnectionTimeout(
UndertowEmbeddedServletContainerFactory factory,
final int connectionTimeout) {
factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {
@Override
public void customize(Builder builder) {
builder.setSocketOption(UndertowOptions.NO_REQUEST_TIMEOUT,
connectionTimeout);
}
});
} private void customizeMaxHttpHeaderSize(
UndertowEmbeddedServletContainerFactory factory,
final int maxHttpHeaderSize) {
factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { @Override
public void customize(Builder builder) {
builder.setServerOption(UndertowOptions.MAX_HEADER_SIZE,
maxHttpHeaderSize);
} });
} private void customizeMaxHttpPostSize(
UndertowEmbeddedServletContainerFactory factory,
final long maxHttpPostSize) {
factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { @Override
public void customize(Builder builder) {
builder.setServerOption(UndertowOptions.MAX_ENTITY_SIZE,
maxHttpPostSize);
} });
} public static class Accesslog { /**
* Enable access log.
*/
private Boolean enabled; /**
* Format pattern for access logs.
*/
private String pattern = "common"; /**
* Log file name prefix.
*/
protected String prefix = "access_log."; /**
* Log file name suffix.
*/
private String suffix = "log"; /**
* Undertow access log directory.
*/
private File dir = new File("logs"); /**
* Enable access log rotation.
*/
private boolean rotate = true; public Boolean getEnabled() {
return this.enabled;
} public void setEnabled(Boolean enabled) {
this.enabled = enabled;
} public String getPattern() {
return this.pattern;
} public void setPattern(String pattern) {
this.pattern = pattern;
} public String getPrefix() {
return this.prefix;
} public void setPrefix(String prefix) {
this.prefix = prefix;
} public String getSuffix() {
return this.suffix;
} public void setSuffix(String suffix) {
this.suffix = suffix;
} public File getDir() {
return this.dir;
} public void setDir(File dir) {
this.dir = dir;
} public boolean isRotate() {
return this.rotate;
} public void setRotate(boolean rotate) {
this.rotate = rotate;
} } } /**
* {@link ServletContextInitializer} to apply appropriate parts of the {@link Session}
* configuration.
*/
private static class SessionConfiguringInitializer
implements ServletContextInitializer { private final Session session; SessionConfiguringInitializer(Session session) {
this.session = session;
} @Override
public void onStartup(ServletContext servletContext) throws ServletException {
if (this.session.getTrackingModes() != null) {
servletContext.setSessionTrackingModes(this.session.getTrackingModes());
}
configureSessionCookie(servletContext.getSessionCookieConfig());
} private void configureSessionCookie(SessionCookieConfig config) {
Cookie cookie = this.session.getCookie();
if (cookie.getName() != null) {
config.setName(cookie.getName());
}
if (cookie.getDomain() != null) {
config.setDomain(cookie.getDomain());
}
if (cookie.getPath() != null) {
config.setPath(cookie.getPath());
}
if (cookie.getComment() != null) {
config.setComment(cookie.getComment());
}
if (cookie.getHttpOnly() != null) {
config.setHttpOnly(cookie.getHttpOnly());
}
if (cookie.getSecure() != null) {
config.setSecure(cookie.getSecure());
}
if (cookie.getMaxAge() != null) {
config.setMaxAge(cookie.getMaxAge());
}
} } }
在这个类里我们可以找到customizeTomcat方法,大家自行看看喽,类图如下:

Spring源码分析(一)--BeanProcessor


  

上一篇:poj12月其他题解(未完)


下一篇:POJ 2987 - Firing - [最大权闭合子图]