Spring: Когда расширенный компонент не совместим с его предком?
Я получил два определенных компонента
Класс А
package a;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
class A extends OncePerRequestFilter {
Класс б
package b;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@Primary
class A extends a.A {
Используя эти два компонента в моем приложении Spring (boot 4.2.5), я получаю следующую ошибку:
...
nested exception is org.springframework.context.annotation.
ConflictingBeanDefinitionException:
Annotation-specified bean name 'a' for bean class [a.A] conflicts with existing,
non-compatible bean definition of same name and class [b.A]
Я ожидал (и хочу), что bA будет использоваться в пользу aA в качестве замены / переопределения.
Почему я получаю это сообщение об ошибке здесь? Как можно использовать Б.А. в качестве "Компонента А"?
Полное исключение / ошибка запуска sprint-boot:
Application startup failed","stack_trace":"o.s.c.a.ConflictingBeanDefinitionException:
Annotation-specified bean name 'httpAccessLogFilter' for bean class [b.A] conflicts with existing,
non-compatible bean definition of same name and class [a.A]
at o.s.c.a.ClassPathBeanDefinitionScanner.checkCandidate(ClassPathBeanDefinitionScanner.java:320)
at o.s.c.a.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:259)
at o.s.c.a.ComponentScanAnnotationParser.parse(ComponentScanAnnotationParser.java:137)
at o.s.c.a.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:268)
at o.s.c.a.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:232)
at o.s.c.a.ConfigurationClassParser.parse(ConfigurationClassParser.java:199)
at o.s.c.a.ConfigurationClassParser.parse(ConfigurationClassParser.java:168)
... 16 common frames omitted
Wrapped by: o.s.b.f.BeanDefinitionStoreException: Failed to parse configuration class [a.SpringBootApplication];
nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: A
nnotation-specified bean name 'a' for bean class [b.A] conflicts with existing, non-compatible bean definition of same name and class [a.A]
at o.s.c.a.ConfigurationClassParser.parse(ConfigurationClassParser.java:182)
at o.s.c.a.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:321)
at o.s.c.a.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:243)
at o.s.c.s.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:273)
at o.s.c.s.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:98)
at o.s.c.s.AbstractApplicationContext.invokeBeanFactoryPostProcessors(Abst...
1 ответ
Похоже, что те же бины из разных пакетов не поддерживаются.
"считает их совместимыми, когда существующее определение компонента поступает из того же источника или из источника без сканирования". ClassPathBeanDefinitionScanner:isCompatible
В Spring это еще обсуждается в их Issue-Tracker, см. SPR-14665 и SPR-10808.
Я получил некрасивое решение. Предок получает другое имя и комментируется как "ConditionalOnMissingBean".
Предок:
package a;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnMissingBean(name = "a")
class AncestorOfA extends OncePerRequestFilter {
Класс Б:
package b;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
class A extends a.AncestorOfA {
Таким образом, у меня есть компонент "ancestorOfA", если я не хочу реализовывать собственный. Если я хочу использовать собственную версию, у меня будет компонент "a", но не "ancestorOfA".
Очевидным недостатком является то, что дочерний компонент должен быть назван правильно.