[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 containerpull/1/merge
parent
56865ab260
commit
ef5c8aa304
@ -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 @@
|
||||
/*
|
||||
* 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 @@
|
||||
/*
|
||||
* 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 @@
|
||||
/*
|
||||
* 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