扩展AbstractAnnotationConfigDispatcherServletInitializer时的getServletConfigClasses()vs getRootConfigClasses()

Pla*_*one 53 java configuration spring spring-mvc component-scan

扩展时getServletConfigClasses()vs 之间有什么区别.我从今天早上开始阅读了很多资料,但我还没有对差异有任何明确的了解:getRootConfigClasses()AbstractAnnotationConfigDispatcherServletInitializer

请看看这两个配置:

1).

public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

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

ConServlet.class是指的

@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;
    }   
}
Run Code Online (Sandbox Code Playgroud)

2).

public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebConfig.class }; 
    }
    .....
}
Run Code Online (Sandbox Code Playgroud)

WebConfig.class是指的

@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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我看到ConServletWebConfig(或多或少)都在做同样的事情,比如初始化视图:

但为什么 :

  • ConServlet返回getRootConfigClasses()
  • WebConfig返回getServletConfigClasses()

我看了文档

getRootConfigClasses() &getServletConfigClasses() 是用于

指定要提供给的@Configuration和/或@Component类..(他们的差异)

  • 根应用上下文getRootConfigClasses()
  • 调度程序servlet应用程序上下文 getServletConfigClasses()

但为什么然后ConServletWebConfig 做同样的事情(比如初始化视图),也许我就是那个误解它的人.在简单的术语/示例中,实际上是根上下文和调度程序servlet(我知道这个)

谢谢!

Ali*_*ani 97

上有点ApplicationContext层次

Spring ApplicationContext提供了加载多个(分层)上下文的功能,允许每个上下文集中在一个特定的层上,例如应用程序的Web层或中间层服务.

使用层次结构的规范示例之一ApplicationContext是当我们DispatcherServlet在Web应用程序中有多个s时,我们将分享一些常见的bean,例如它们datasources之间.这样,我们可以定义一个ApplicationContext包含所有公共bean 的根,以及WebApplicationContext从根上下文继承公共bean的多个bean.

在Web MVC框架中,每个框架DispatcherServlet都有自己的框架,WebApplicationContext它继承了根中已经定义的所有bean WebApplicationContext.可以在特定于servlet的作用域中重写这些继承的bean,并且可以在给定Servlet实例的本地定义新的作用域特定bean .

Spring Web MVC中的典型上下文层次结构
Spring Web MVC中的典型上下文层次结构(Spring文档)

如果您生活在一个单一的DispatherServlet世界中,那么此方案也可能只有一个根上下文:

在此输入图像描述
Spring Web MVC中的单根上下文(Spring文档)

说话很便宜,给我看看代码!

假设我们正在开发一个Web应用程序,我们将使用Spring MVC,Spring Security和Spring Data JPA.对于这个简单的场景,我们至少会有三个不同的配置文件.一个WebConfig包含所有的web相关的配置,如ViewResolverS,ControllerS,ArgumentResolverS,等喜欢的东西如下:

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我正在定义一个ViewResolver解决我的原始jsps,糟糕的人生决定,基本上.我们需要一个RepositoryConfig,它包含了所有的数据访问设施,如DataSource,EntityManagerFactory,TransactionManager,等它可能会像下面:

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

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

    @Bean
    public PlatformTransactionManager transactionManager() { ... }
}
Run Code Online (Sandbox Code Playgroud)

并且SecurityConfig包含所有安全相关的东西!

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

    @Override
    protected void configure(HttpSecurity http) throws Exception { ... }
}
Run Code Online (Sandbox Code Playgroud)

为了将所有这些粘合在一起,我们有两种选择.首先,我们可以ApplicationContext通过添加RepositoryConfigSecurityConfig在根上下文WebConfig及其子上下文中定义典型的层次结构:

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[] { "/" };
    }
}
Run Code Online (Sandbox Code Playgroud)

由于我们在DispatcherServlet这里只有一个,我们可以添加WebConfig到根上下文并使servlet上下文为空:

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[] { "/" };
    }
}
Run Code Online (Sandbox Code Playgroud)

进一步阅读

Skaffman在解释ApplicationContext这个答案的层次结构方面做得很好,强烈建议这样做.另外,您可以阅读Spring文档.

  • 好的,我会在接下来的两天里尝试学习/吸收你的答案(从明天开始),谢谢,现在我会赞成它. (3认同)
  • 一个很好的答案.有一点值得指出的是,[`@ ComponentScan`](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html)就是它还会选择[`@Configuration`](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html)类,因为它们也是组件可以导致bean在两个上下文中加载两次.出于这个原因,我总是明确地从`@ ComponentScan`中排除`@Configuration`,这提供了更多的受控配置. (2认同)

sha*_*zin 5

根配置类实际上用于创建特定于应用程序且需要可用于过滤器的Bean(因为过滤器不是Servlet的一部分)。

Servlet配置类实际上用于创建DispatcherServlet特定的Bean,例如ViewResolvers,ArgumentResolvers,Interceptor等。

根配置类将首先被​​加载,然后Servlet配置类将被加载。

根配置类将是父上下文,它将创建一个ApplicationContext实例。其中,作为Servlet Config类的是父上下文的子上下文,它将创建一个WebApplicationContext实例。

在你的ConServlet配置,你并不需要指定@EnableWebMvc为好InternalResourceViewResolver,因为它们是在只需豆WebConfig