[bs-115] Add EmbeddedServletContainerCustomizer as a callback
* All instances are called before the container is started in a bean post processor * Users still have to be careful because the customizer is called very early in the ApplicationContext lifecycle (e.g. might have to do a lookup for some dependencies instead of @Autowired) [Fixes #49671463] User-hook for customizing embedded servlet container
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.autoconfigure.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.bootstrap.context.embedded.ConfigurableEmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerCustomizer;
|
||||
import org.springframework.bootstrap.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for
|
||||
* {@link JettyEmbeddedServletContainerFactory}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Servlet.class })
|
||||
public class EmbeddedContainerCustomizerConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private Set<EmbeddedServletContainerCustomizer> customizers = new HashSet<EmbeddedServletContainerCustomizer>();
|
||||
|
||||
@Bean
|
||||
public BeanPostProcessor embeddedContainerCustomizerBeanPostProcessor() {
|
||||
return new EmbeddedContainerCustomizerBeanPostProcessor(this.customizers);
|
||||
}
|
||||
|
||||
private static final class EmbeddedContainerCustomizerBeanPostProcessor implements
|
||||
BeanPostProcessor {
|
||||
|
||||
private List<EmbeddedServletContainerCustomizer> customizers;
|
||||
|
||||
public EmbeddedContainerCustomizerBeanPostProcessor(
|
||||
Set<EmbeddedServletContainerCustomizer> customizers) {
|
||||
final List<EmbeddedServletContainerCustomizer> list = new ArrayList<EmbeddedServletContainerCustomizer>(
|
||||
customizers);
|
||||
Collections.sort(list, new AnnotationAwareOrderComparator());
|
||||
this.customizers = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
if (bean instanceof ConfigurableEmbeddedServletContainerFactory) {
|
||||
ConfigurableEmbeddedServletContainerFactory factory = (ConfigurableEmbeddedServletContainerFactory) bean;
|
||||
for (EmbeddedServletContainerCustomizer customizer : this.customizers) {
|
||||
customizer.customize(factory);
|
||||
}
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,7 +36,7 @@ import org.springframework.util.Assert;
|
||||
* @since 4.0
|
||||
*/
|
||||
public abstract class AbstractEmbeddedServletContainerFactory implements
|
||||
EmbeddedServletContainerFactory {
|
||||
ConfigurableEmbeddedServletContainerFactory {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@@ -170,6 +170,7 @@ public abstract class AbstractEmbeddedServletContainerFactory implements
|
||||
* @see #setInitializers
|
||||
* @see #getInitializers
|
||||
*/
|
||||
@Override
|
||||
public void addInitializers(ServletContextInitializer... initializers) {
|
||||
Assert.notNull(initializers, "Initializers must not be null");
|
||||
this.initializers.addAll(Arrays.asList(initializers));
|
||||
@@ -181,6 +182,7 @@ public abstract class AbstractEmbeddedServletContainerFactory implements
|
||||
* parameters.
|
||||
* @return the initializers
|
||||
*/
|
||||
@Override
|
||||
public List<ServletContextInitializer> getInitializers() {
|
||||
return this.initializers;
|
||||
}
|
||||
@@ -190,6 +192,7 @@ public abstract class AbstractEmbeddedServletContainerFactory implements
|
||||
* files.
|
||||
* @param documentRoot the document root or {@code null} if not required
|
||||
*/
|
||||
@Override
|
||||
public void setDocumentRoot(File documentRoot) {
|
||||
this.documentRoot = documentRoot;
|
||||
}
|
||||
@@ -198,6 +201,7 @@ public abstract class AbstractEmbeddedServletContainerFactory implements
|
||||
* Returns the document root which will be used by the web context to serve static
|
||||
* files.
|
||||
*/
|
||||
@Override
|
||||
public File getDocumentRoot() {
|
||||
return this.documentRoot;
|
||||
}
|
||||
@@ -206,6 +210,7 @@ public abstract class AbstractEmbeddedServletContainerFactory implements
|
||||
* Sets the error pages that will be used when handling exceptions.
|
||||
* @param errorPages the error pages
|
||||
*/
|
||||
@Override
|
||||
public void setErrorPages(Set<ErrorPage> errorPages) {
|
||||
Assert.notNull(errorPages, "ErrorPages must not be null");
|
||||
this.errorPages = new LinkedHashSet<ErrorPage>(errorPages);
|
||||
@@ -215,6 +220,7 @@ public abstract class AbstractEmbeddedServletContainerFactory implements
|
||||
* Adds error pages that will be used when handling exceptions.
|
||||
* @param errorPages the error pages
|
||||
*/
|
||||
@Override
|
||||
public void addErrorPages(ErrorPage... errorPages) {
|
||||
Assert.notNull(this.initializers, "ErrorPages must not be null");
|
||||
this.errorPages.addAll(Arrays.asList(errorPages));
|
||||
@@ -224,6 +230,7 @@ public abstract class AbstractEmbeddedServletContainerFactory implements
|
||||
* Returns a mutable set of {@link ErrorPage}s that will be used when handling
|
||||
* exceptions.
|
||||
*/
|
||||
@Override
|
||||
public Set<ErrorPage> getErrorPages() {
|
||||
return this.errorPages;
|
||||
}
|
||||
@@ -233,6 +240,7 @@ public abstract class AbstractEmbeddedServletContainerFactory implements
|
||||
* files from the {@link #setDocumentRoot(File) document root} will be served.
|
||||
* @param registerDefaultServlet if the default servlet should be registered
|
||||
*/
|
||||
@Override
|
||||
public void setRegisterDefaultServlet(boolean registerDefaultServlet) {
|
||||
this.registerDefaultServlet = registerDefaultServlet;
|
||||
}
|
||||
@@ -243,7 +251,8 @@ public abstract class AbstractEmbeddedServletContainerFactory implements
|
||||
*
|
||||
* @return true if the JSP servlet is to be registered
|
||||
*/
|
||||
protected boolean getRegisterJspServlet() {
|
||||
@Override
|
||||
public boolean isRegisterJspServlet() {
|
||||
return this.registerJspServlet;
|
||||
}
|
||||
|
||||
@@ -253,6 +262,7 @@ public abstract class AbstractEmbeddedServletContainerFactory implements
|
||||
* will be served.
|
||||
* @param registerJspServlet if the JSP servlet should be registered
|
||||
*/
|
||||
@Override
|
||||
public void setRegisterJspServlet(boolean registerJspServlet) {
|
||||
this.registerJspServlet = registerJspServlet;
|
||||
}
|
||||
@@ -262,7 +272,8 @@ public abstract class AbstractEmbeddedServletContainerFactory implements
|
||||
*
|
||||
* @return true if the default servlet is to be registered
|
||||
*/
|
||||
protected boolean getRegisterDefaultServlet() {
|
||||
@Override
|
||||
public boolean isRegisterDefaultServlet() {
|
||||
return this.registerDefaultServlet;
|
||||
}
|
||||
|
||||
@@ -275,6 +286,7 @@ public abstract class AbstractEmbeddedServletContainerFactory implements
|
||||
*
|
||||
* @param jspServletClassName the class name for the JSP servlet if used
|
||||
*/
|
||||
@Override
|
||||
public void setJspServletClassName(String jspServletClassName) {
|
||||
this.jspServletClassName = jspServletClassName;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.bootstrap.context.embedded;
|
||||
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
@@ -55,6 +56,10 @@ public class AnnotationConfigEmbeddedWebApplicationContext extends
|
||||
|
||||
private final ClassPathBeanDefinitionScanner scanner;
|
||||
|
||||
private Class<?>[] annotatedClasses;
|
||||
|
||||
private String[] basePackages;
|
||||
|
||||
/**
|
||||
* Create a new {@link AnnotationConfigEmbeddedWebApplicationContext} that needs to be
|
||||
* populated through {@link #register} calls and then manually {@linkplain #refresh
|
||||
@@ -149,9 +154,9 @@ public class AnnotationConfigEmbeddedWebApplicationContext extends
|
||||
* @see #refresh()
|
||||
*/
|
||||
public void register(Class<?>... annotatedClasses) {
|
||||
this.annotatedClasses = annotatedClasses;
|
||||
Assert.notEmpty(annotatedClasses,
|
||||
"At least one annotated class must be specified");
|
||||
this.reader.register(annotatedClasses);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,8 +167,8 @@ public class AnnotationConfigEmbeddedWebApplicationContext extends
|
||||
* @see #refresh()
|
||||
*/
|
||||
public void scan(String... basePackages) {
|
||||
this.basePackages = basePackages;
|
||||
Assert.notEmpty(basePackages, "At least one base package must be specified");
|
||||
this.scanner.scan(basePackages);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -172,4 +177,15 @@ public class AnnotationConfigEmbeddedWebApplicationContext extends
|
||||
super.prepareRefresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||
super.postProcessBeanFactory(beanFactory);
|
||||
if (this.basePackages != null && this.basePackages.length > 0) {
|
||||
this.scanner.scan(this.basePackages);
|
||||
}
|
||||
if (this.annotatedClasses != null && this.annotatedClasses.length > 0) {
|
||||
this.reader.register(this.annotatedClasses);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.bootstrap.context.embedded;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.InetAddress;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Simple interface that represents customizations to an
|
||||
* {@link EmbeddedServletContainerFactory}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @see EmbeddedServletContainerFactory
|
||||
*/
|
||||
public interface ConfigurableEmbeddedServletContainerFactory extends
|
||||
EmbeddedServletContainerFactory {
|
||||
|
||||
void setContextPath(String contextPath);
|
||||
|
||||
String getContextPath();
|
||||
|
||||
void setPort(int port);
|
||||
|
||||
int getPort();
|
||||
|
||||
void setAddress(InetAddress address);
|
||||
|
||||
InetAddress getAddress();
|
||||
|
||||
void setInitializers(List<? extends ServletContextInitializer> initializers);
|
||||
|
||||
void setJspServletClassName(String jspServletClassName);
|
||||
|
||||
boolean isRegisterDefaultServlet();
|
||||
|
||||
void setRegisterJspServlet(boolean registerJspServlet);
|
||||
|
||||
boolean isRegisterJspServlet();
|
||||
|
||||
void setRegisterDefaultServlet(boolean registerDefaultServlet);
|
||||
|
||||
Set<ErrorPage> getErrorPages();
|
||||
|
||||
void addErrorPages(ErrorPage... errorPages);
|
||||
|
||||
void setErrorPages(Set<ErrorPage> errorPages);
|
||||
|
||||
File getDocumentRoot();
|
||||
|
||||
void setDocumentRoot(File documentRoot);
|
||||
|
||||
List<ServletContextInitializer> getInitializers();
|
||||
|
||||
void addInitializers(ServletContextInitializer... initializers);
|
||||
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
package org.springframework.bootstrap.context.embedded;
|
||||
|
||||
/**
|
||||
* Simple interface that represents a fully configure embedded servlet container (for
|
||||
* Simple interface that represents a fully configured embedded servlet container (for
|
||||
* example Tomcat or Jetty). Allows the container to be {@link #stop() stopped}.
|
||||
*
|
||||
* <p>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.context.embedded;
|
||||
|
||||
/**
|
||||
* Strategy interface for customizing auto-configured embedded servlet containers. Any
|
||||
* beans of this type will get a callback with the container factory before the container
|
||||
* itself is started, so you can set the port, address, error pages etc. Beware: will be
|
||||
* called from a BeanPostProcessor (so very early in the ApplicationContext lifecycle), so
|
||||
* it might be safer to lookup dependencies lazily in the enclosing BeanFactory rather
|
||||
* than injecting them with <code>@Autowired</code>.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public interface EmbeddedServletContainerCustomizer {
|
||||
|
||||
void customize(ConfigurableEmbeddedServletContainerFactory factory);
|
||||
|
||||
}
|
||||
@@ -110,10 +110,10 @@ public class JettyEmbeddedServletContainerFactory extends
|
||||
this.context.setContextPath(StringUtils.hasLength(contextPath) ? contextPath
|
||||
: "/");
|
||||
configureDocumentRoot(this.context);
|
||||
if (getRegisterDefaultServlet()) {
|
||||
if (isRegisterDefaultServlet()) {
|
||||
addDefaultServlet(this.context);
|
||||
}
|
||||
if (getRegisterJspServlet()
|
||||
if (isRegisterJspServlet()
|
||||
&& ClassUtils.isPresent(getJspServletClassName(), getClass()
|
||||
.getClassLoader())) {
|
||||
addJspServlet(this.context);
|
||||
|
||||
@@ -144,10 +144,10 @@ public class TomcatEmbeddedServletContainerFactory extends
|
||||
if (this.resourceLoader != null) {
|
||||
context.setParentClassLoader(this.resourceLoader.getClassLoader());
|
||||
}
|
||||
if (getRegisterDefaultServlet()) {
|
||||
if (isRegisterDefaultServlet()) {
|
||||
addDefaultServlet(context);
|
||||
}
|
||||
if (getRegisterJspServlet()
|
||||
if (isRegisterJspServlet()
|
||||
&& ClassUtils.isPresent(getJspServletClassName(), getClass()
|
||||
.getClassLoader())) {
|
||||
addJspServlet(context);
|
||||
|
||||
@@ -4,6 +4,7 @@ org.springframework.bootstrap.autoconfigure.data.JpaRepositoriesAutoConfiguratio
|
||||
org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseAutoConfiguration,\
|
||||
org.springframework.bootstrap.autoconfigure.batch.BatchAutoConfiguration,\
|
||||
org.springframework.bootstrap.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
|
||||
org.springframework.bootstrap.autoconfigure.web.EmbeddedContainerCustomizerConfiguration,\
|
||||
org.springframework.bootstrap.autoconfigure.web.EmbeddedJettyAutoConfiguration,\
|
||||
org.springframework.bootstrap.autoconfigure.web.EmbeddedTomcatAutoConfiguration,\
|
||||
org.springframework.bootstrap.autoconfigure.web.WebMvcAutoConfiguration
|
||||
|
||||
Reference in New Issue
Block a user