Browse Source
* 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 containerpull/1/head
16 changed files with 494 additions and 93 deletions
@ -0,0 +1,89 @@
@@ -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; |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,72 @@
@@ -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); |
||||
|
||||
} |
||||
@ -0,0 +1,33 @@
@@ -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); |
||||
|
||||
} |
||||
@ -0,0 +1,121 @@
@@ -0,0 +1,121 @@
|
||||
/* |
||||
* 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 javax.servlet.Servlet; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.beans.BeansException; |
||||
import org.springframework.beans.factory.config.BeanPostProcessor; |
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnExpression; |
||||
import org.springframework.bootstrap.context.embedded.AnnotationConfigEmbeddedWebApplicationContext; |
||||
import org.springframework.bootstrap.context.embedded.ConfigurableEmbeddedServletContainerFactory; |
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerCustomizer; |
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerFactory; |
||||
import org.springframework.bootstrap.context.embedded.MockEmbeddedServletContainerFactory; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.stereotype.Component; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertNull; |
||||
import static org.mockito.Mockito.verify; |
||||
|
||||
/** |
||||
* @author Dave Syer |
||||
*/ |
||||
public class WebMvcAutoConfigurationTests { |
||||
|
||||
private AnnotationConfigEmbeddedWebApplicationContext context; |
||||
|
||||
@Test |
||||
public void createFromConfigClass() throws Exception { |
||||
this.context = new AnnotationConfigEmbeddedWebApplicationContext( |
||||
WebMvcAutoConfiguration.class, EmbeddedContainerConfiguration.class); |
||||
verifyContext(); |
||||
} |
||||
|
||||
@Test |
||||
public void containerHasNoServletContext() throws Exception { |
||||
this.context = new AnnotationConfigEmbeddedWebApplicationContext( |
||||
WebMvcAutoConfiguration.class, EmbeddedContainerConfiguration.class, |
||||
EnsureContainerHasNoServletContext.class); |
||||
verifyContext(); |
||||
} |
||||
|
||||
@Test |
||||
public void customizeContainerThroughCallback() throws Exception { |
||||
this.context = new AnnotationConfigEmbeddedWebApplicationContext( |
||||
WebMvcAutoConfiguration.class, EmbeddedContainerConfiguration.class, |
||||
EmbeddedContainerCustomizerConfiguration.class, |
||||
CallbackEmbeddedContainerCustomizer.class); |
||||
verifyContext(); |
||||
assertEquals(9000, getContainerFactory().getPort()); |
||||
} |
||||
|
||||
private void verifyContext() { |
||||
MockEmbeddedServletContainerFactory containerFactory = getContainerFactory(); |
||||
Servlet servlet = this.context.getBean(Servlet.class); |
||||
verify(containerFactory.getServletContext()).addServlet("dispatcherServlet", |
||||
servlet); |
||||
} |
||||
|
||||
private MockEmbeddedServletContainerFactory getContainerFactory() { |
||||
return this.context.getBean(MockEmbeddedServletContainerFactory.class); |
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnExpression("true") |
||||
public static class EmbeddedContainerConfiguration { |
||||
|
||||
@Bean |
||||
public EmbeddedServletContainerFactory containerFactory() { |
||||
return new MockEmbeddedServletContainerFactory(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Component |
||||
public static class EnsureContainerHasNoServletContext implements BeanPostProcessor { |
||||
|
||||
@Override |
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) |
||||
throws BeansException { |
||||
if (bean instanceof ConfigurableEmbeddedServletContainerFactory) { |
||||
MockEmbeddedServletContainerFactory containerFactory = (MockEmbeddedServletContainerFactory) bean; |
||||
assertNull(containerFactory.getServletContext()); |
||||
} |
||||
return bean; |
||||
} |
||||
|
||||
@Override |
||||
public Object postProcessAfterInitialization(Object bean, String beanName) { |
||||
return bean; |
||||
} |
||||
|
||||
} |
||||
|
||||
@Component |
||||
public static class CallbackEmbeddedContainerCustomizer implements |
||||
EmbeddedServletContainerCustomizer { |
||||
@Override |
||||
public void customize(ConfigurableEmbeddedServletContainerFactory factory) { |
||||
factory.setPort(9000); |
||||
} |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue