繁体   English   中英

使用 Spring Mvc WebApplicationInitializer、ApplicationContextInitializer 和 ContextLoaderListener

[英]Using Spring Mvc WebApplicationInitializer, ApplicationContextInitializer and ContextLoaderListener

我使用基于 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");
    }
}

基础设施上下文配置

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

现在,当我尝试请求任何 url 时,我得到了错误:

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 profile 的所有 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);
    }
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM