getServletConfigClasses () vs getRootConfigClasses () ao estender o AbstractAnnotationConfigDispatcherServletInitializer

Qual é a diferença entre getServletConfigClasses() vs getRootConfigClasses() ao estender AbstractAnnotationConfigDispatcherServletInitializer . Eu tenho lido muitas fonts desde esta manhã, mas ainda não entendi claramente as diferenças:

Por favor, olhe para estas duas configurações:

1).

 public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class[] getRootConfigClasses() { return new Class[] { ConServlet.class }; } @Override protected Class[] getServletConfigClasses() { return null; } .... .... } 

O ConServlet.class está se referindo a

 @EnableWebMvc @Configuration @ComponentScan({ "com" }) @Import({ SecurityConfig.class }) public class ConServlet { @Bean public InternalResourceViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setViewClass(JstlView.class); viewResolver.setPrefix("/WEB-INF/pages/"); viewResolver.setSuffix(".jsp"); return viewResolver; } } 

2).

 public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class[] getRootConfigClasses() { return null; } @Override protected Class[] getServletConfigClasses() { return new Class[] { WebConfig.class }; } ..... } 

o WebConfig.class está se referindo a

 @Configuration @EnableWebMvc @ComponentScan(basePackages = { "....." }) public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**").addResourceLocations("/resources/"); } @Bean public ViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setViewClass(JstlView.class); viewResolver.setPrefix("/WEB-INF/views"); viewResolver.setSuffix(".jsp"); return viewResolver; } } 

Eu vejo tanto ConServlet e WebConfig (mais ou menos) fazendo as mesmas coisas como inicializando a visão:

Mas por que :

  • ConServlet é retornado em getRootConfigClasses()
  • enquanto WebConfig é retornado em getServletConfigClasses()

Eu li a documentação

getRootConfigClasses () e getServletConfigClasses () é para

Especifique as classs @Configuration e / ou @Component a serem fornecidas para .. (suas diferenças)

  • o contexto do aplicativo raiz para getRootConfigClasses()
  • o contexto do aplicativo de servlet do dispatcher para getServletConfigClasses()

mas por que, então, o ConServlet & WebConfig fazendo as mesmas coisas (como a visualização de boot), talvez eu tenha entendido errado. O que são realmente os servlets de contexto e dispatcher de raiz (eu conheço este) no termo / exemplo simples

Obrigado!

Um bit nas hierarquias do ApplicationContext


Spring ApplicationContext fornece a capacidade de carregar vários contextos (hierárquicos), permitindo que cada um seja focado em uma camada específica, como a camada web de um aplicativo ou serviços de camada intermediária.

Um dos exemplos canônicos do uso de ApplicationContext hierárquico é quando temos vários DispatcherServlet s em um aplicativo da Web e vamos compartilhar alguns dos beans comuns, como datasources entre eles. Dessa forma, podemos definir um ApplicationContext raiz que contém todos os beans comuns e vários WebApplicationContext s que herdam os beans comuns do contexto raiz.

Na estrutura Web MVC, cada DispatcherServlet possui seu próprio WebApplicationContext , que herda todos os beans já definidos no WebApplicationContext raiz. Esses beans herdados podem ser substituídos no escopo específico do servlet, e você pode definir novos beans específicos do escopo para uma determinada instância do Servlet .

Hierarquia de contexto típica no Spring Web MVC
Hierarquia de contexto típica no Spring Web MVC (Documentação Spring)

Se você está vivendo em um único mundo DispatherServlet , também é possível ter apenas um contexto raiz para este cenário:

insira a descrição da imagem aqui
Contexto raiz única no Spring Web MVC (Documentação Spring)

A conversa é barata, mostre-me o código!


Suponha que vamos desenvolver uma aplicação web e vamos usar o Spring MVC, o Spring Security e o Spring Data JPA. Para este cenário simples, teríamos pelo menos três arquivos de configuração diferentes. Um WebConfig que contém todas as nossas configurações relacionadas à web, como ViewResolver s, Controller s, ArgumentResolver s, etc. Algo como seguir:

 @EnableWebMvc @Configuration @ComponentScan(basePackages = "com.so.web") public class WebConfig extends WebMvcConfigurerAdapter { @Bean public InternalResourceViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/views/"); viewResolver.setSuffix(".jsp"); return viewResolver; } @Override public void configurePathMatch(PathMatchConfigurer configurer) { final boolean DO_NOT_USE_SUFFIX_PATTERN_MATCHING = false; configurer.setUseSuffixPatternMatch(DO_NOT_USE_SUFFIX_PATTERN_MATCHING); } } 

Aqui estou definindo um ViewResolver para resolver meus simples jsps antigos, decisões ruins sobre a vida, basicamente. Nós precisaríamos de um RepositoryConfig , que contém todos os resources de access a dados, como DataSource , EntityManagerFactory , TransactionManager , etc. Provavelmente seria como seguir:

 @Configuration @EnableTransactionManagement @EnableJpaRepositories(basePackages = "com.so.repository") public class RepositoryConfig { @Bean public DataSource dataSource() { ... } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { ... } @Bean public PlatformTransactionManager transactionManager() { ... } } 

E um SecurityConfig que contém todo o material relacionado à segurança!

 @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override @Autowired protected void configure(AuthenticationManagerBuilder auth) throws Exception { ... } @Override protected void configure(HttpSecurity http) throws Exception { ... } } 

Para colar tudo isso juntos, temos duas opções. Primeiro, podemos definir um ApplicationContext hierárquico típico, adicionando RepositoryConfig e SecurityConfig no contexto raiz e WebConfig em seu contexto filho:

 public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class[] getRootConfigClasses() { return new Class[] { RepositoryConfig.class, SecurityConfig.class }; } @Override protected Class[] getServletConfigClasses() { return new Class[] { WebConfig.class }; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } } 

Como temos um único DispatcherServlet aqui, podemos adicionar o WebConfig ao contexto raiz e tornar o contexto do servlet vazio:

 public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class[] getRootConfigClasses() { return new Class[] { RepositoryConfig.class, SecurityConfig.class, WebConfig.class }; } @Override protected Class[] getServletConfigClasses() { return null; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } } 

Leitura Adicional


Skaffman fez um ótimo trabalho explicando hierarquias ApplicationContext nesta resposta , o que é altamente recomendado. Além disso, você pode ler a documentação do Spring .

As classs de configuração raiz são realmente usadas para criar beans que são específicos do aplicativo e que precisam estar disponíveis para filtros (como os filtros não fazem parte do servlet).

As classs de configuração do servlet são realmente usadas para criar beans que são específicos do DispatcherServlet, como ViewResolvers, ArgumentResolvers, Interceptor, etc.

As Classes de Configuração Raiz serão carregadas primeiro e, em seguida, as Classes de Configuração do Servlet serão carregadas.

As Classes de Configuração Raiz serão o Contexto Pai e criarão uma instância do ApplicationContext . Onde, como Classes de Configuração de Servlet, será o Contexto Filho do Contexto Pai e ele criará uma instância de WebApplicationContext .

Na sua configuração ConServlet , você não precisa especificar o @EnableWebMvc , assim como o bean InternalResourceViewResolver pois eles são necessários apenas no WebConfig .