Spring IoC контейнер: Java конфигурация, композиция конфигураций на основе Java, внедрение зависимостей от импортированных определений @Bean
Пример в предыдущем посте работает, но он упрощен. В большинстве практических сценариев bean-компоненты зависят друг от друга в разных классах конфигурации. При использовании XML это не проблема, потому что компилятор не задействован, и вы можете объявить ref="someBean" и доверять Spring, чтобы решить эту проблему во время инициализации контейнера. При использовании классов @Configuration компилятор Java накладывает ограничения на модель конфигурации, так как ссылки на другие bean-компоненты должны иметь допустимый синтаксис Java.
К счастью, решить эту проблему просто. Метод @Bean может иметь произвольное количество параметров, описывающих зависимости bean-компонентов. Рассмотрим следующий более реальный сценарий с несколькими классами @Configuration, каждый из которых зависит от bean-компонентов, объявленных в других:
Java
@Configuration
public class ServiceConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
@Configuration
public class RepositoryConfig {
@Bean
public AccountRepository accountRepository(DataSource dataSource) {
return new JdbcAccountRepository(dataSource);
}
}
@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {
@Bean
public DataSource dataSource() {
// return new DataSource
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
// все подключается к классам конфигурации...
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
Kotlin
import org.springframework.beans.factory.getBean
@Configuration
class ServiceConfig {
@Bean
fun transferService(accountRepository: AccountRepository): TransferService {
return TransferServiceImpl(accountRepository)
}
}
@Configuration
class RepositoryConfig {
@Bean
fun accountRepository(dataSource: DataSource): AccountRepository {
return JdbcAccountRepository(dataSource)
}
}
@Configuration
@Import(ServiceConfig::class, RepositoryConfig::class)
class SystemTestConfig {
@Bean
fun dataSource(): DataSource {
// return new DataSource
}
}
fun main() {
val ctx = AnnotationConfigApplicationContext(SystemTestConfig::class.java)
// все подключается к классам конфигурации...
val transferService = ctx.getBean<TransferService>()
transferService.transfer(100.00, "A123", "C456")
}
Есть другой способ добиться такого же результата. Помните, что классы @Configuration - это, в конечном счете, всего лишь еще один компонент в контейнере: это означает, что они могут использовать преимущества внедрения @Autowired и @Value, а также другие функции, как и любой другой компонент.
Убедитесь, что зависимости, которые вы вводите таким образом, являются только простейшими. Классы @Configuration обрабатываются довольно рано во время инициализации контекста, и принудительное внедрение зависимости таким образом может привести к неожиданной ранней инициализации. По возможности используйте инъекцию на основе параметров, как в предыдущем примере.
Также будьте особенно осторожны с определениями BeanPostProcessor и BeanFactoryPostProcessor через @Bean. Обычно их следует объявлять как статические методы @Bean, не запускающие создание экземпляра содержащего их класса конфигурации. В противном случае @Autowired и @Value могут не работать с самим классом конфигурации, поскольку его можно создать как экземпляр компонента раньше, чем AutowiredAnnotationBeanPostProcessor.
В следующем примере показано, как один компонент может быть автоматически подключен к другому компоненту:
Java
@Configuration
public class ServiceConfig {
@Autowired
private AccountRepository accountRepository;
@Bean
public TransferService transferService() {
return new TransferServiceImpl(accountRepository);
}
}
@Configuration
public class RepositoryConfig {
private final DataSource dataSource;
public RepositoryConfig(DataSource dataSource) {
this.dataSource = dataSource;
}
@Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(dataSource);
}
}
@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {
@Bean
public DataSource dataSource() {
// return new DataSource
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
// все подключается к классам конфигурации...
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
Kotlin
import org.springframework.beans.factory.getBean
@Configuration
class ServiceConfig {
@Autowired
lateinit var accountRepository: AccountRepository
@Bean
fun transferService(): TransferService {
return TransferServiceImpl(accountRepository)
}
}
@Configuration
class RepositoryConfig(private val dataSource: DataSource) {
@Bean
fun accountRepository(): AccountRepository {
return JdbcAccountRepository(dataSource)
}
}
@Configuration
@Import(ServiceConfig::class, RepositoryConfig::class)
class SystemTestConfig {
@Bean
fun dataSource(): DataSource {
// return new DataSource
}
}
fun main() {
val ctx = AnnotationConfigApplicationContext(SystemTestConfig::class.java)
// все подключается к классам конфигурации...
val transferService = ctx.getBean<TransferService>()
transferService.transfer(100.00, "A123", "C456")
}
Внедрение конструктора в классы @Configuration поддерживается только в Spring Framework 4.3. Также обратите внимание, что нет необходимости указывать @Autowired, если целевой bean-компонент определяет только один конструктор.
Читайте также:
- Spring IoC контейнер: Java конфигурация, использование аннотации @Configuration, о внутренней работе конфигурации на основе Java
- Spring IoC контейнер: Java конфигурация, использование аннотации @Configuration, внедрение зависимостей между компонентами
- Spring IoC контейнер: Java конфигурация, композиция конфигураций на основе Java, использование аннотации @Import
Комментарии
Отправить комментарий