Allow early ServletRequest Autowiring

Update `EmbeddedWebApplicationContext` so that Servlet related
resolvable dependencies are registered in `postProcessBeanFactory`.

This allows a `ServletReqest` to be autowired into an early initialized
bean and brings parity with WAR based deployments.

Closes gh-14990
This commit is contained in:
Phillip Webb 2018-11-14 18:15:21 -08:00
parent fb85d0acc1
commit b60da5f85d
2 changed files with 54 additions and 9 deletions

View File

@ -114,6 +114,7 @@ public class EmbeddedWebApplicationContext extends GenericWebApplicationContext
beanFactory.addBeanPostProcessor(
new WebApplicationContextServletContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
registerWebApplicationScopes(null);
}
@Override
@ -217,19 +218,22 @@ public class EmbeddedWebApplicationContext extends GenericWebApplicationContext
private void selfInitialize(ServletContext servletContext) throws ServletException {
prepareEmbeddedWebApplicationContext(servletContext);
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(
beanFactory);
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory,
getServletContext());
existingScopes.restore();
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory,
getServletContext());
registerWebApplicationScopes(servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(),
servletContext);
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}
private void registerWebApplicationScopes(ServletContext servletContext) {
ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(
getBeanFactory());
WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory(),
servletContext);
existingScopes.restore();
}
/**
* Returns {@link ServletContextInitializer}s that should be used with the embedded
* Servlet context. By default this method will first attempt to find

View File

@ -41,12 +41,15 @@ import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.Scope;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
@ -466,7 +469,8 @@ public class EmbeddedWebApplicationContextTests {
}
@Test
public void doesNotReplaceExistingScopes() throws Exception { // gh-2082
public void doesNotReplaceExistingScopes() throws Exception {
// gh-2082
Scope scope = mock(Scope.class);
ConfigurableListableBeanFactory factory = this.context.getBeanFactory();
factory.registerScope(WebApplicationContext.SCOPE_REQUEST, scope);
@ -482,6 +486,29 @@ public class EmbeddedWebApplicationContextTests {
.isSameAs(scope);
}
@Test
public void servletRequestCanBeInjectedEarly() throws Exception {
// gh-14990
addEmbeddedServletContainerFactoryBean();
RootBeanDefinition beanDefinition = new RootBeanDefinition(
WithAutowiredServletRequest.class);
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
this.context.registerBeanDefinition("withAutowiredServletRequest",
beanDefinition);
this.context.addBeanFactoryPostProcessor(new BeanFactoryPostProcessor() {
@Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
WithAutowiredServletRequest bean = beanFactory
.getBean(WithAutowiredServletRequest.class);
assertThat(bean.getRequest()).isNotNull();
}
});
this.context.refresh();
}
private void addEmbeddedServletContainerFactoryBean() {
this.context.registerBeanDefinition("embeddedServletContainerFactory",
new RootBeanDefinition(MockEmbeddedServletContainerFactory.class));
@ -534,4 +561,18 @@ public class EmbeddedWebApplicationContextTests {
}
protected static class WithAutowiredServletRequest {
private final ServletRequest request;
public WithAutowiredServletRequest(ServletRequest request) {
this.request = request;
}
public ServletRequest getRequest() {
return this.request;
}
}
}