Note that there are some explanatory texts on larger screens.

plurals
  1. POUsing Spring Mvc WebApplicationInitializer, ApplicationContextInitializer and ContextLoaderListener
    text
    copied!<p>I use java-based Spring Mvc configuration. </p> <p>I register the Spring dispatcher servlet in the WebApplicationInitializer implementation. Load Spring ApplicationContext configuration files. Logic of Spring profiles management is implemented in the ApplicationContextInitializer implementation. And it worked fine. </p> <p>Here are full examples of the original files: <strong>WebApplicationInitializer</strong></p> <pre><code>public class SpringMvcExampleWebApplicationInitializer implements WebApplicationInitializer { private static final String DISPATCHER_SERVLET_NAME = "dispatcher"; @Override public void onStartup(ServletContext servletContext) throws ServletException { registerDispatcherServlet(servletContext); registerHiddenHttpMethodFilter(servletContext); } private void registerDispatcherServlet(final ServletContext servletContext) { WebApplicationContext dispatcherContext = createContext(WebMvcContextConfiguration.class, InfrastructureContextConfiguration.class); DispatcherServlet dispatcherServlet = new DispatcherServlet(dispatcherContext); dispatcherServlet.setContextInitializers(new SpringMvcExampleProfilesInitializer()); ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, dispatcherServlet); dispatcher.setLoadOnStartup(1); dispatcher.addMapping("/"); } private WebApplicationContext createContext(final Class&lt;?&gt;... annotatedClasses) { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.register(annotatedClasses); return context; } private void registerHiddenHttpMethodFilter(ServletContext servletContext) { FilterRegistration.Dynamic registration = servletContext.addFilter("hiddenHttpMethodFilter", HiddenHttpMethodFilter.class); registration.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD), false, DISPATCHER_SERVLET_NAME); } } </code></pre> <p><strong>SpringMvcExampleProfilesInitializer</strong></p> <pre><code>public class SpringMvcExampleProfilesInitializer implements ApplicationContextInitializer&lt;ConfigurableApplicationContext&gt; { @Override public void initialize(ConfigurableApplicationContext ctx) { ConfigurableEnvironment environment = ctx.getEnvironment(); List&lt;String&gt; profiles = new ArrayList&lt;String&gt;(getProfiles()); if( profiles == null || profiles.isEmpty() ) { throw new IllegalArgumentException("Profiles have not been configured"); } environment.setActiveProfiles(profiles.toArray( new String[0])); } //TODO add logic private Collection&lt;String&gt; getProfiles() { return Lists.newArrayList("file_based", "test_data"); } } </code></pre> <p><strong>InfrastructureContextConfiguration</strong></p> <pre><code>@Configuration @ComponentScan(basePackages = {"com.savdev.springmvcexample.repository", "com.savdev.springmvcexample.config"}) @EnableTransactionManagement @EnableJpaRepositories(basePackages = {"com.savdev.springmvcexample.repository"}) public class InfrastructureContextConfiguration { @Configuration @Profile(value = "file_based") @PropertySource("classpath:/db/config/file_based.properties") public static class FileBasedConfiguration { @Inject private Environment environment; @Bean public DataSource dataSource() { BasicDataSource dataSource = new org.apache.commons.dbcp.BasicDataSource(); dataSource.setDriverClassName(environment.getProperty("jdbc.driver")); dataSource.setUrl(environment.getProperty("jdbc.url")); dataSource.setUsername(environment.getProperty("jdbc.username")); dataSource.setPassword(environment.getProperty("jdbc.password")); return dataSource; } } @Bean public SpringLiquibase liquibase(DataSource dataSource) { SpringLiquibase liquibase = new SpringLiquibase(); liquibase.setDataSource(dataSource); liquibase.setChangeLog("classpath:/db/liquibase/changelog/db.changelog-master.xml"); liquibase.setDropFirst(true); return liquibase; } </code></pre> <p>Then I added Spring Security context configuration to the application. To use it the <code>DelegatingFilterProxy</code> have to be loaded. I\ve updated the configuration:</p> <p>Added new method and invoked it in the <code>onStartup</code>:</p> <pre><code>private void registerSpringSecurityFilterChain(ServletContext servletContext) { FilterRegistration.Dynamic springSecurityFilterChain = servletContext.addFilter( BeanIds.SPRING_SECURITY_FILTER_CHAIN, new DelegatingFilterProxy()); springSecurityFilterChain.addMappingForUrlPatterns(null, false, "/*"); } @Override public void onStartup(ServletContext servletContext) throws ServletException { ... registerDispatcherServlet(servletContext); ... registerSpringSecurityFilterChain(servletContext); } </code></pre> <p>Now when I try to request any url I'm getting the error:</p> <pre><code>message No WebApplicationContext found: no ContextLoaderListener registered? description The server encountered an internal error that prevented it from fulfilling this request. exception java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered? org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:251) </code></pre> <p>Ok, I added the following:</p> <pre><code> private static final Class&lt;?&gt;[] configurationClasses = new Class&lt;?&gt;[]{ WebMvcContextConfiguration.class, InfrastructureContextConfiguration.class}; ... private void registerListener(ServletContext servletContext) { WebApplicationContext rootContext = createContext(configurationClasses); servletContext.addListener(new ContextLoaderListener(rootContext)); } </code></pre> <p>And invoked it from:</p> <pre><code>@Override public void onStartup(ServletContext servletContext) throws ServletException { registerListener(servletContext); registerDispatcherServlet(servletContext); registerHiddenHttpMethodFilter(servletContext); registerSpringSecurityFilterChain(servletContext); } </code></pre> <p>The error has gone.</p> <p>But all beans that depend on Spring profile are not loaded now. Adding the <code>ContextLoaderListener</code> has broken the <code>SpringMvcExampleProfilesInitializer</code> logic.</p> <pre><code>No qualifying bean of type [javax.sql.DataSource] found for dependency </code></pre> <p>What can I do to resolve it? Any ideas, please?</p> <p>Here is the full updated web initializer class:</p> <pre><code>public class SpringMvcExampleWebApplicationInitializer implements WebApplicationInitializer { private static final String DISPATCHER_SERVLET_NAME = "dispatcher"; private static final Class&lt;?&gt;[] configurationClasses = new Class&lt;?&gt;[]{ WebMvcContextConfiguration.class, InfrastructureContextConfiguration.class}; @Override public void onStartup(ServletContext servletContext) throws ServletException { registerListener(servletContext); registerDispatcherServlet(servletContext); registerHiddenHttpMethodFilter(servletContext); registerSpringSecurityFilterChain(servletContext); } private void registerSpringSecurityFilterChain(ServletContext servletContext) { FilterRegistration.Dynamic springSecurityFilterChain = servletContext.addFilter( BeanIds.SPRING_SECURITY_FILTER_CHAIN, new DelegatingFilterProxy()); springSecurityFilterChain.addMappingForUrlPatterns(null, false, "/*"); } private void registerDispatcherServlet(final ServletContext servletContext) { WebApplicationContext dispatcherContext = createContext(WebMvcContextConfiguration.class, InfrastructureContextConfiguration.class); DispatcherServlet dispatcherServlet = new DispatcherServlet(dispatcherContext); dispatcherServlet.setContextInitializers(new SpringMvcExampleProfilesInitializer()); ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, dispatcherServlet); dispatcher.setLoadOnStartup(1); dispatcher.addMapping("/"); } private WebApplicationContext createContext(final Class&lt;?&gt;... annotatedClasses) { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.register(annotatedClasses); // context.refresh(); return context; } private void registerListener(ServletContext servletContext) { WebApplicationContext rootContext = createContext(configurationClasses); servletContext.addListener(new ContextLoaderListener(rootContext)); // servletContext.addListener(new RequestContextListener()); } private void registerHiddenHttpMethodFilter(ServletContext servletContext) { FilterRegistration.Dynamic registration = servletContext.addFilter("hiddenHttpMethodFilter", HiddenHttpMethodFilter.class); registration.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD), false, DISPATCHER_SERVLET_NAME); } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload