使用Spring Mvc WebApplicationInitializer,ApplicationContextInitializer和ContextLoaderListener

时间:2013-11-29 03:28:02

标签: java spring spring-mvc configuration

我使用基于java的Spring Mvc配置。

我在WebApplicationInitializer实现中注册了Spring调度程序servlet。 加载Spring ApplicationContext配置文件。 Spring概要管理的逻辑在ApplicationContextInitializer实现中实现。它工作得很好。

以下是原始文件的完整示例: 的 WebApplicationInitializer

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<?>... 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);
    }
}

SpringMvcExampleProfilesInitializer

public class SpringMvcExampleProfilesInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    @Override
    public void initialize(ConfigurableApplicationContext ctx) {
        ConfigurableEnvironment environment = ctx.getEnvironment();
        List<String> profiles = new ArrayList<String>(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<String> getProfiles() {
        return Lists.newArrayList("file_based", "test_data");
    }
}

InfrastructureContextConfiguration

@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;
    }

然后我将Spring Security上下文配置添加到应用程序中。要使用它,必须加载DelegatingFilterProxy。我已经更新了配置:

添加了新方法,并在onStartup

中调用了该方法
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);
}

现在,当我尝试请求任何网址时,我收到错误:

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)

好的,我添加了以下内容:

        private static final Class<?>[] configurationClasses = new Class<?>[]{
                WebMvcContextConfiguration.class, InfrastructureContextConfiguration.class};
    ...

private void registerListener(ServletContext servletContext) {
    WebApplicationContext rootContext = createContext(configurationClasses);
    servletContext.addListener(new ContextLoaderListener(rootContext));
}

从以下方式调用它:

@Override
 public void onStartup(ServletContext servletContext) throws ServletException {
    registerListener(servletContext);
    registerDispatcherServlet(servletContext);
    registerHiddenHttpMethodFilter(servletContext);
    registerSpringSecurityFilterChain(servletContext);
}

错误已经消失。

但是现在没有加载所有依赖于Spring配置文件的bean。添加ContextLoaderListener已经破坏了SpringMvcExampleProfilesInitializer逻辑。

No qualifying bean of type [javax.sql.DataSource] found for dependency

我该怎么做才能解决它?有什么想法吗?

以下是完整更新的网络初始化程序类:

public class SpringMvcExampleWebApplicationInitializer implements WebApplicationInitializer {

    private static final String DISPATCHER_SERVLET_NAME = "dispatcher";

    private static final Class<?>[] configurationClasses = new Class<?>[]{
            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<?>... 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);
    }
}

1 个答案:

答案 0 :(得分:0)

正如M.Deinum建议我将配置文件的初始值设置为ServletContext,而不是将其设置为DispatcherServlet。这是更新的配置:

@Override
 public void onStartup(ServletContext servletContext) throws ServletException {
    configureServletContext( servletContext );
    registerListener(servletContext);
    registerDispatcherServlet(servletContext);
    ...
}

private void configureServletContext(ServletContext servletContext) {
    String initializerClasses = servletContext.getInitParameter(ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM);
    String profilesInitClassName = SpringMvcExampleProfilesInitializer.class.getName();
    if (StringUtils.hasText(initializerClasses)) {
        initializerClasses += " " + profilesInitClassName;
    }
    else {
        initializerClasses = profilesInitClassName;
    }
    servletContext.setInitParameter(ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM, initializerClasses);
}