Home > Mobile >  Why does Spring throw a ConflictingBeanDefinitionException for beans of different packages and even
Why does Spring throw a ConflictingBeanDefinitionException for beans of different packages and even

Time:12-21

I understand, that there can't be two beans of different classes with the same name - in theory at least, but I'm wondering, why the package of the classes is not factored in?

For example:

Two totally independent classes with no common interface.

com.company.application.foo.Bar

is for the DI framework the same as

com.company.application.bar.Bar

but the compiler will of course see the difference and complain if you try to assign one to another.

Even more confusing is, why would there arise conflicts if both beans are package-private - no private/public modifier, only visible within their package?

There can nowhere be a conflict by definition, yet Spring sees an issue and makes no difference and produces:

org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'myComponent' for bean class [com.company.bar.Bar] conflicts with existing, non-compatible bean definition of same name and class [com.company.foo.Bar]

Why was the decision made to only look at the name of the bean, not the full package path and name?

CodePudding user response:

I don't know the history of the bean name, but it comes a long way from when you defined the beans in XML.

However, there is a FullyQualifiedAnnotationBeanNameGenerator that you can use, and that will do what you requested.

This can be defined with @ComponentScan:

@SpringBootApplication
@ComponentScan(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
public class BeanNamesApplication {

CodePudding user response:

If you didn't specify a name explicitly, Spring derives a default name for the bean from the simple class name (that is, without package name). These names are stored in a single namespace (per context), so having beans defined from two classes with the same simple name will result in a name conflict. If you want to avoid that name conflict, you must explicitly name your bean (e.g. @Component("distinctNameForThisBean")).

See also Naming Autodetected Components for other alternatives, like:

If you run into naming conflicts due to multiple autodetected components having the same non-qualified class name (i.e., classes with identical names but residing in different packages), you may need to configure a BeanNameGenerator that defaults to the fully qualified class name for the generated bean name. As of Spring Framework 5.2.3, the FullyQualifiedAnnotationBeanNameGenerator located in package org.springframework.context.annotation can be used for such purposes.

If you're asking why Spring was designed that way, then your question is actually off-topic as that will more likely elicit opinions than factual answers.

  • Related