2013-11-29 4 views
0

Я использую конфигурацию Spring Mvc на основе Java.Использование Spring Mvc WebApplicationInitializer, ApplicationContextInitializer и ContextLoaderListener

Я регистрирую сервлет диспетчера весов в реализации WebApplicationInitializer. Загрузить файлы конфигурации Spring SpringContext. Логика управления профилями 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); 
} 

Теперь, когда я пытаюсь запросить любой 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); 
} 

Ошибка исчезла.

Но все бобы, которые зависят от профиля пружины, теперь не загружаются. Добавление 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); 
    } 
} 
+0

Пожалуйста, ваш полный 'SpringMvcExampleProfilesInitializer' и указать, какой' @ Configuration' класс содержит профили и которые '@ Configuration' класс имеет' ApplicationContextInitializer'. –

+0

Ваша проблема заключается в том, что вы загружаете все дважды и что вы указываете только инициализатор на 'DispatcherServlet', а не на' ContextLoaderListener'. Вы должны разделить конфигурацию, где 'ContextLoaderListener' загружает общие вещи (сервисы, daos, инфраструктуру и т. Д.) и 'DispatcherServlet' только связанные с Интернетом вещи (контроллеры, viewresovlers и т. д.). –

+0

@SotiriosDelimanolis, я обновил вопрос – Alexandr

ответ

0

Как M.Deinum порекомендовал мне установить профили initialier к 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); 
} 
+0

На самом деле вам нужны оба. Тот, что находится в 'ServletContext', используется' ContextLoaderListener', тогда как другие используются 'DispatcherSevlet'. –

Смежные вопросы