Подтвердить что ты не робот

GetServletConfigClasses() vs getRootConfigClasses() при расширении AbstractAnnotationConfigDispatcherServletInitializer

В чем разница между 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;
    }
        ....
        ....    
        }

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

2).

public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

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

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

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

Я вижу, как ConServlet и WebConfig (более или менее) выполняют те же действия, что и инициализация вида:

Но почему:

  • ConServlet возвращается в getRootConfigClasses()
  • а WebConfig возвращается в getServletConfigClasses()

Я прочитал документацию

и getRootConfigClasses(), и getServletConfigClasses() для

Укажите классы @Configuration и/или @Component для предоставления.. (их отличия)

  • контекст корневого приложения для getRootConfigClasses()
  • контекст приложения сервлета диспетчера для getServletConfigClasses()

но почему тогда ConServlet и WebConfig делают то же самое (например, представление инициализации), возможно, я это неправильно понял. На самом деле это корневой контекст и сервлет-диспетчер (я знаю этот) в простом/примерном

Спасибо!

4b9b3361

Ответ 1

Бит на иерархиях ApplicationContext

Spring ApplicationContext предоставляет возможность загрузки нескольких (иерархических) контекстов, позволяя каждому сосредоточиться на одном конкретном слое, таком как веб-уровень приложения или службы среднего уровня.

Один из канонических примеров использования иерархического ApplicationContext - это когда у нас есть несколько DispatcherServlet в веб-приложении, и мы собираемся поделиться некоторыми из общих компонентов, таких как datasources между ними. Таким образом, мы можем определить корневой ApplicationContext который содержит все общие компоненты и несколько WebApplicationContext которые наследуют общие компоненты из корневого контекста.

В WebApplicationContext Web MVC каждый DispatcherServlet имеет свой собственный WebApplicationContext, который наследует все компоненты, уже определенные в корневом WebApplicationContext. Эти унаследованные бобы могут быть переопределены в области, зависящей от сервлета, и вы можете определить новые специфичные для конкретной области компоненты bean для данного экземпляра Servlet.

Typical context hierarchy in Spring Web MVC
Типичная иерархия контекстов в Spring Web MVC (Spring Documentation)

Если вы живете в одном мире DispatherServlet, также возможно иметь только один корневой контекст для этого сценария:

enter image description here
Однокорневой контекст в Spring Web MVC (Spring Documentation)

Обсуждение дешево, покажите мне код!

Предположим, мы разрабатываем веб-приложение, и мы будем использовать Spring MVC, Spring Security и Spring Data JPA. Для этого простого сценария у нас будет как минимум три разных файла конфигурации. WebConfig который содержит все наши веб-конфигурации, такие как ViewResolver s, Controller s, ArgumentResolver s и т.д. Что-то вроде следующего:

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

Здесь я определяю 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() { ... }
}

И 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 { ... }
}

Для склеивания всех этих элементов мы имеем два варианта. Во-первых, мы можем определить типичный иерархический ApplicationContext, добавив RepositoryConfig и SecurityConfig в корневом контексте и 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[] { "/" };
    }
}

Поскольку у нас есть один DispatcherServlet, мы можем добавить WebConfig в корневой контекст и сделать контекст сервлета пустым:

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

Дальнейшее чтение

Skaffman проделал большую работу по разъяснению ApplicationContext иерархий в этом ответе, который настоятельно рекомендуется. Кроме того, вы можете прочитать документацию Spring.

Ответ 2

Root Config Classes фактически используются для создания Beans, которые являются специфичными для приложения и которые должны быть доступны для фильтров (поскольку фильтры не являются частью сервлета).

Servlet Config Классы фактически используются для создания Beans, которые являются специфичными для DispatcherServlet, такими как ViewResolvers, ArgumentResolvers, Interceptor и т.д.

Сначала будут загружены классы корневой конфигурации, а затем загрузятся классы конфигурации сервлета.

Root Config Classs будет Parent Context, и он создаст ApplicationContext instace. Где в качестве классов конфигурации сервлета будет дочерний контекст родительского контекста, и он создаст экземпляр WebApplicationContext.

В вашей конфигурации ConServlet вам не нужно указывать @EnableWebMvc, а также InternalResourceViewResolver bean, поскольку они требуются только в WebConfig.