使用Spring Mvc WebApplicationInitializer、ApplicationContextInitializer和ContextLoaderListener

问题描述 投票:0回答:1

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

我在 WebApplicationInitializer 实现中注册 Spring 调度程序 servlet。 加载 Spring ApplicationContext 配置文件。 Spring 配置文件管理的逻辑是在 ApplicationContextInitializer 实现中实现的。而且效果很好。

以下是原始文件的完整示例: Web应用程序初始化器

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

SpringMvcExampleProfiles初始化器

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");
    }
}

基础设施上下文配置

@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

我可以做什么来解决这个问题?请问有什么想法吗?

这是完整更新的 Web 初始值设定项类:

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);
    }
}
java spring spring-mvc configuration
1个回答
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);
}
© www.soinside.com 2019 - 2024. All rights reserved.