web-dev-qa-db-fra.com

getServletConfigClasses () vs getRootConfigClasses () lors de l'extension de AbstractAnnotationConfigDispatcherServletInitializer

Quelle est la différence entre getServletConfigClasses() vs getRootConfigClasses() lors de l'extension AbstractAnnotationConfigDispatcherServletInitializer. J'ai lu beaucoup de sources depuis ce matin mais je n'ai pas encore compris clairement les différences:

Veuillez regarder ces deux configurations:

1).

public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

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

ConServlet.class fait référence à

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

WebConfig.class fait référence à

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

Je vois les deux ConServlet & WebConfig (plus ou moins) faire les mêmes choses que l'initialisation de la vue:

Mais pourquoi :

  • ConServlet est retourné dans getRootConfigClasses()
  • tandis que WebConfig est retourné dans getServletConfigClasses()

J'ai lu la documentation

les deux getRootConfigClasses () & getServletConfigClasses () est pour

Spécifiez les classes @Configuration et/ou @Component à fournir à .. (leurs différences)

  • le contexte de l'application racine pour getRootConfigClasses()
  • le contexte d'application du servlet du répartiteur pourgetServletConfigClasses()

mais pourquoi alors ConServlet & WebConfig faisant les mêmes choses (comme initialiser la vue), c'est peut-être moi qui l'ai mal compris. Quels sont en fait le contexte racine et les servlets de répartiteur (je connais celui-ci) dans le terme/exemple simple

Merci!

50

Un peu sur ApplicationContext Hiérarchies


ApplicationContext de Spring offre la possibilité de charger plusieurs contextes (hiérarchiques), permettant à chacun de se concentrer sur une couche particulière, telle que la couche Web d'une application ou des services de niveau intermédiaire.

L'un des exemples canoniques d'utilisation de la hiérarchie ApplicationContext est lorsque nous avons plusieurs DispatcherServlet dans une application Web et que nous allons partager certains des beans communs tels que datasources entre leur. De cette façon, nous pouvons définir une racine ApplicationContext qui contient tous les beans communs et plusieurs WebApplicationContexts qui héritent des beans communs du contexte racine.

Dans le framework Web MVC, chaque DispatcherServlet a son propre WebApplicationContext, qui hérite de tous les beans déjà définis dans la racine WebApplicationContext. Ces beans hérités peuvent être remplacés dans la portée spécifique au servlet, et vous pouvez définir de nouveaux beans spécifiques à la portée locaux à une instance Servlet donnée.

Typical context hierarchy in Spring Web MVC
Hiérarchie de contexte typique dans Spring Web MVC (Spring Documentation)

Si vous vivez dans un seul monde DispatherServlet, il est également possible d'avoir un seul contexte racine pour ce scénario:

enter image description here
Contexte racine unique dans Spring Web MVC (documentation Spring)

Parler est bon marché, montrez-moi le code!


Supposons que nous développons une application Web et que nous allons utiliser Spring MVC, Spring Security et Spring Data JPA. Pour ce scénario simple, nous aurions au moins trois fichiers de configuration différents. Un WebConfig qui contient toutes nos configurations Web, telles que ViewResolvers, Controllers, ArgumentResolvers, etc. Quelque chose comme ceci:

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

Ici, je définis un ViewResolver pour résoudre mes vieux jsps simples, les mauvaises décisions de vie, en gros. Nous aurions besoin d'un RepositoryConfig, qui contient toutes les fonctionnalités d'accès aux données telles que DataSource, EntityManagerFactory, TransactionManager, etc. Ce serait probablement comme suit:

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

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() { ... }

    @Bean
    public PlatformTransactionManager transactionManager() { ... }
}

Et un SecurityConfig qui contient tous les trucs liés à la sécurité!

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

    @Override
    protected void configure(HttpSecurity http) throws Exception { ... }
}

Pour coller tous ces éléments ensemble, nous avons deux options. Tout d'abord, nous pouvons définir un ApplicationContext hiérarchique typique, en ajoutant RepositoryConfig et SecurityConfig dans le contexte racine et WebConfig dans leur contexte enfant:

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

Puisque nous avons ici un seul DispatcherServlet, nous pouvons ajouter le WebConfig au contexte racine et rendre le contexte de servlet vide:

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

Lectures complémentaires


Skaffman a fait un excellent travail pour expliquer les hiérarchies ApplicationContext dans ce réponse , ce qui est fortement recommandé. Vous pouvez également lire Spring Documentation .

92
Ali Dehghani

Les classes de configuration racine sont en fait utilisées pour créer des beans spécifiques à l'application et qui doivent être disponibles pour les filtres (car les filtres ne font pas partie du servlet).

Les classes de configuration de servlet sont en fait utilisées pour créer des beans spécifiques à DispatcherServlet tels que ViewResolvers, ArgumentResolvers, Interceptor, etc.

Les classes de configuration racine seront chargées en premier, puis les classes de configuration de servlet seront chargées.

Les classes de configuration racine seront le contexte parent et créeront une instace ApplicationContext. Où en tant que classes de configuration de servlet sera le contexte enfant du contexte parent et il créera une instance WebApplicationContext.

Dans votre configuration ConServlet, vous n'avez pas besoin de spécifier le @EnableWebMvc ainsi que le bean InternalResourceViewResolver car ils ne sont nécessaires qu'au WebConfig.

4
shazin