Вы переосмысливаете Spring IoC и путаете @Configuration
с ApplicationContext
(фактическим контейнером IoC).
@Configuration
обрабатывается в рамках уже существующего контейнера.И документы однажды заявленные:
@Import
представляет JavaConfig-эквивалент элемента XML-конфигурации <import/>
.Один класс конфигурации может импортировать любое количество других классов конфигурации, и их определения bean-компонентов будут обрабатываться так, как если бы они были определены локально.
То есть все импортированные и обнаруженные @Configurations загружаются в один и тот же контейнер.
После этого создаются все одиночные бины.Затем они соединяются вместе.
Внутри контейнера вы можете иметь несколько бинов одного типа, но не с одинаковым именем .В JavaConfig имя бина получается из имени метода фабрики или имени класса.В случае Service
есть только одно имя, service
, и, следовательно, только один компонент типа Service
.Если вы присмотритесь, вы увидите сообщение запуска по линии "Overriding bean definition for bean 'service' with a different definition: replacing [factoryBeanName=ConfigA; factoryMethodName=service; defined in ConfigA] with [factoryBeanName=ConfigB; factoryMethodName=service; defined in ConfigB]
"
Один-единственный service
подключается везде, где это необходимо (в commonProcess
, configA
и configB
).
В вашем конкретном случае вы можете решить эту проблему, передав Service
в CommonProcess.test()
, как в простой версии Java, и присвоив уникальное имя каждому Service
экземпляру (например, serviceA
).и serviceB
):
@FunctionalInterface
interface Service {
boolean test();
}
class CommonProcess {
public boolean test(Service service) {
return service.test();
}
}
@Configuration
class BaseConfig {
@Bean
CommonProcess commonProcess() {
return new CommonProcess();
}
}
@Configuration
class ConfigA {
@Bean
CommandLineRunner processA(@Named("serviceA") Service service) {
return new CommandLineRunner() {
@Autowired
private CommonProcess process;
@Override
public void run(String... args) throws Exception {
System.out.println(this.process.test(service));
}
};
}
@Bean
Service serviceA() {
return () -> false;
}
}
@Configuration
class ConfigB {
@Bean
CommandLineRunner processB(@Named("serviceB") Service service) {
return new CommandLineRunner() {
@Autowired
private CommonProcess process;
@Override
public void run(String... args) throws Exception {
System.out.println(this.process.test(service));
}
@Bean
Service serviceB() {
return () -> true;
}
};
}
@Autowired
ApplicationContext applicationContext;
@PostConstruct
public void printBeans() {
System.out.println(Arrays.asList(applicationContext.getBeanDefinitionNames()));
}
@Bean
Service serviceB() {
return () -> true;
}
}
@SpringBootConfiguration
@Import(value = { BaseConfig.class, ConfigA.class, ConfigB.class })
class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Я бы также посоветовал изучить область действия боба , особенно заводскую область применения.
И, наконец, Spring Boot поддерживает иерархия ApplicationContext , которая, по сути, позволяет создавать подпрограммы в одном исполняемом файле.Таким образом, ConfigA
и ConfigB
могут иметь свой экземпляр Service
с именем service
.Эта функциональность используется редко.
@SpringBootConfiguration
@Import(value = { BaseConfig.class })
class App {
public static void main(String[] args) {
SpringApplicationBuilder app = new SpringApplicationBuilder(App.class);
app.child(ConfigA.class).run(args);
app.child(ConfigB.class).run(args);
}
}