[bs-52] Added support for SpringApplication in a ServletContextInitializer

WAR applications should extend SpringServletInitializer to take advantage
of Servlet 3.0 initialization and SpringApplication context loading features.

[#48386505] [bs-52] Support for running "traditional" webapps in place
This commit is contained in:
Dave Syer 2013-06-10 18:11:11 +01:00
parent 7bd1aeb514
commit 20cce0c69c
4 changed files with 105 additions and 63 deletions

View File

@ -391,9 +391,8 @@ public class SpringApplication {
* @param sources the sources to load
*/
protected void load(ApplicationContext context, Object[] sources) {
Assert.isInstanceOf(BeanDefinitionRegistry.class, context);
BeanDefinitionLoader loader = createBeanDefinitionLoader(
(BeanDefinitionRegistry) context, sources);
getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
@ -406,6 +405,17 @@ public class SpringApplication {
loader.load();
}
/**
* @param context the application context
* @return the BeanDefinitionRegistry if it can be determined
*/
private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
if (context instanceof BeanDefinitionRegistry) {
return (BeanDefinitionRegistry) context;
}
throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
}
/**
* Factory method used to create the {@link BeanDefinitionLoader}.
* @param registry the bean definition registry

View File

@ -127,16 +127,25 @@ public class EmbeddedWebApplicationContext extends GenericWebApplicationContext
}
private synchronized void createAndStartEmbeddedServletContainer() {
if (this.embeddedServletContainer == null) {
if (this.embeddedServletContainer == null && getServletContext() == null) {
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
this.embeddedServletContainer = containerFactory
.getEmbdeddedServletContainer(getServletContextInitializers());
WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory(),
getServletContext());
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(),
getServletContext());
initPropertySources();
} else if (getServletContext() != null) {
for (ServletContextInitializer initializer : getServletContextInitializers()) {
try {
initializer.onStartup(getServletContext());
} catch (ServletException e) {
throw new ApplicationContextException(
"Cannot initialize servlet context", e);
}
}
}
WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory(),
getServletContext());
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(),
getServletContext());
initPropertySources();
}
/**
@ -339,4 +348,5 @@ public class EmbeddedWebApplicationContext extends GenericWebApplicationContext
public EmbeddedServletContainer getEmbeddedServletContainer() {
return this.embeddedServletContainer;
}
}

View File

@ -1,55 +0,0 @@
package org.springframework.bootstrap.web;
import javax.servlet.Filter;
import org.springframework.util.ClassUtils;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.FrameworkServlet;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* <p>
* A handy opinionated {@link WebApplicationInitializer} for applications that only have
* one Spring servlet, and no more than a single filter (which itself is only enabled when
* Spring Security is detected). If your application is more complicated consider using
* one of the other WebApplicationInitializers.
* <p>
*
* <p>
* Note that a WebApplicationInitializer is only needed if you are building a war file and
* deploying it. If you prefer to run an embedded container (we do) then you won't need
* this at all.
* </p>
*
* @author Dave Syer
*
*/
public abstract class BootstrapServletInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
@Override
protected Filter[] getServletFilters() {
if (ClassUtils.isPresent(
"org.springframework.security.config.annotation.web.EnableWebSecurity",
null)) {
DelegatingFilterProxy filter = new DelegatingFilterProxy(
"springSecurityFilterChain");
filter.setContextAttribute(FrameworkServlet.SERVLET_CONTEXT_PREFIX
+ "dispatcher");
return new Filter[] { filter };
}
return new Filter[0];
}
}

View File

@ -0,0 +1,77 @@
package org.springframework.bootstrap.web;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.bootstrap.SpringApplication;
import org.springframework.bootstrap.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
/**
* <p>
* A handy opinionated {@link WebApplicationInitializer} for applications that only have
* one Spring servlet, and no more than a single filter (which itself is only enabled when
* Spring Security is detected). If your application is more complicated consider using
* one of the other WebApplicationInitializers.
* <p>
*
* <p>
* Note that a WebApplicationInitializer is only needed if you are building a war file and
* deploying it. If you prefer to run an embedded container (we do) then you won't need
* this at all.
* </p>
*
* @author Dave Syer
*
*/
public abstract class SpringServletInitializer implements WebApplicationInitializer {
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext rootAppContext = this
.createRootApplicationContext(servletContext);
if (rootAppContext != null) {
servletContext.addListener(new ContextLoaderListener(rootAppContext) {
@Override
public void contextInitialized(ServletContextEvent event) {
// no-op because the application context is already initialized
}
});
} else {
this.logger
.debug("No ContextLoaderListener registered, as "
+ "createRootApplicationContext() did not return an application context");
}
}
protected WebApplicationContext createRootApplicationContext(
ServletContext servletContext) {
ApplicationContext parent = null;
Object object = servletContext
.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
if (object != null && object instanceof ApplicationContext) {
this.logger.info("Root context already created (using as parent).");
parent = (ApplicationContext) object;
servletContext.setAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
}
SpringApplication application = new SpringApplication(
(Object[]) getConfigClasses());
AnnotationConfigEmbeddedWebApplicationContext context = new AnnotationConfigEmbeddedWebApplicationContext();
context.setParent(parent);
context.setServletContext(servletContext);
application.setApplicationContext(context);
return (WebApplicationContext) application.run();
}
protected abstract Class<?>[] getConfigClasses();
}