Ответ 1
Бит на иерархиях ApplicationContext
Spring ApplicationContext
предоставляет возможность загрузки нескольких (иерархических) контекстов, позволяя каждому сосредоточиться на одном конкретном слое, таком как веб-уровень приложения или службы среднего уровня.
Один из канонических примеров использования иерархического ApplicationContext
- это когда у нас есть несколько DispatcherServlet
в веб-приложении, и мы собираемся поделиться некоторыми из общих компонентов, таких как datasources
между ними. Таким образом, мы можем определить корневой ApplicationContext
который содержит все общие компоненты и несколько WebApplicationContext
которые наследуют общие компоненты из корневого контекста.
В WebApplicationContext
Web MVC каждый DispatcherServlet
имеет свой собственный WebApplicationContext
, который наследует все компоненты, уже определенные в корневом WebApplicationContext
. Эти унаследованные бобы могут быть переопределены в области, зависящей от сервлета, и вы можете определить новые специфичные для конкретной области компоненты bean для данного экземпляра Servlet
.
Типичная иерархия контекстов в Spring Web MVC (Spring Documentation)
Если вы живете в одном мире DispatherServlet
, также возможно иметь только один корневой контекст для этого сценария:
Однокорневой контекст в 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.