your type test springboot scan example defining consider componentscan component bean java spring spring-mvc configuration component-scan

java - type - spring component autowired



getServletConfigClasses() vs getRootConfigClasses() al extender AbstractAnnotationConfigDispatcherServletInitializer (2)

Un poco en las jerarquías de ApplicationContext

ApplicationContext de Spring proporciona la capacidad de cargar contextos múltiples (jerárquicos), lo que permite que cada uno se enfoque en una capa en particular, como la capa web de una aplicación o los servicios de nivel medio.

Uno de los ejemplos canónicos de uso de ApplicationContext jerárquico es cuando tenemos varios DispatcherServlet en una aplicación web y vamos a compartir algunos de los beans comunes como las datasources entre ellos. De esta forma, podemos definir un ApplicationContext raíz que contiene todos los beans comunes y múltiples WebApplicationContext que heredan los beans comunes del contexto raíz.

En el marco de Web MVC, cada DispatcherServlet tiene su propio WebApplicationContext , que hereda todos los beans ya definidos en la raíz WebApplicationContext . Estos beans heredados pueden anularse en el ámbito específico del servlet, y puede definir nuevos beans específicos del ámbito local para una instancia de Servlet determinada.


Jerarquía de contexto típica en Spring Web MVC (Spring Documentation)

Si vive en un solo mundo de DispatherServlet , también es posible tener solo un contexto raíz para este escenario:


Contexto raíz único en Spring Web MVC (Documentación de primavera)

¡Hablar es fácil. Enséñame el código!

Supongamos que vamos a desarrollar una aplicación web y vamos a utilizar Spring MVC, Spring Security y Spring Data JPA. Para este escenario simple, tendríamos al menos tres archivos de configuración diferentes. Una WebConfig que contiene todas nuestras configuraciones relacionadas con la web, como ViewResolver s, Controller s, ArgumentResolver s, etc. Algo como lo siguiente:

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

Aquí estoy definiendo un ViewResolver para resolver mi antiguo jsps, malas decisiones de vida, básicamente. Necesitaríamos un RepositoryConfig , que contiene todas las facilidades de acceso a datos tales como DataSource , EntityManagerFactory , TransactionManager , etc. Probablemente sería como seguir:

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

¡Y un SecurityConfig que contiene todas las cosas relacionadas con la seguridad!

@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 pegar todo esto, tenemos dos opciones. Primero, podemos definir un ApplicationContext jerárquico típico, agregando RepositoryConfig y SecurityConfig en el contexto raíz y WebConfig en su contexto secundario:

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 tenemos un solo DispatcherServlet aquí, podemos agregar WebConfig al contexto raíz y hacer que el contexto del servlet esté vacío:

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[] { "/" }; } }

Otras lecturas

Skaffman hizo un gran trabajo al explicar las jerarquías de ApplicationContext en esta answer , que es muy recomendable. Además, puedes leer la documentación de Spring .

¿Cuál es la diferencia entre getServletConfigClasses() frente a getRootConfigClasses() al extender AbstractAnnotationConfigDispatcherServletInitializer ? He estado leyendo muchas fuentes desde esta mañana, pero aún no tengo una comprensión clara de las diferencias:

Por favor, mira estas dos configuraciones:

1).

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

ConServlet.class se ConServlet.class 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 }; } ..... }

la clase WebConfig.class se refiere 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; } }

Veo tanto ConServlet y WebConfig (más o menos) haciendo las mismas cosas como la vista de inicialización:

Pero por qué :

  • ConServlet se devuelve en getRootConfigClasses()
  • mientras que WebConfig se devuelve en getServletConfigClasses()

Leí la documentación

tanto getRootConfigClasses () como getServletConfigClasses () son para

Especifique las clases @Configuration y / o @Component que se proporcionarán a .. (sus diferencias)

  • el contexto de la aplicación raíz para getRootConfigClasses()
  • el contexto de la aplicación del servlet despachador para getServletConfigClasses()

pero ¿por qué entonces ConServlet & WebConfig haciendo las mismas cosas (como la vista de inicialización), tal vez yo soy el incomprendido. ¿Qué es realmente el contexto raíz y los servlets del despachador (lo sé) en el simple término / ejemplo

¡Gracias!


Las clases de configuración de raíz se usan realmente para crear beans que son específicos de la aplicación y que deben estar disponibles para los filtros (ya que los filtros no son parte del servlet).

Las clases de configuración de servlet se utilizan en realidad para crear beans que son específicos de DispatcherServlet, como ViewResolvers, ArgumentResolvers, Interceptor, etc.

Las clases de configuración raíz se cargarán primero y luego se cargarán las clases de configuración de servlet.

Las clases de configuración de raíz serán el contexto principal y creará un instance ApplicationContext . Donde las clases de configuración Servlet serán el contexto secundario del contexto primario y creará una instancia de WebApplicationContext .

En su Configuración de ConServlet , no necesita especificar el @EnableWebMvc el bean InternalResourceViewResolver ya que solo son necesarios en WebConfig .