17

In a spring app , if two programmers develop two packages , annotating @Repository to the same class name , Spring will throw "IllegalStateException" :

Annotation-specified bean name 'mybean' for bean class [foobar.package1.mybean] conflicts with existing, non-compatible bean definition of same name and class [foobar.package2.mybean]

One solution is to add extra value in the @Repository , such as @Repository("package1.mybean") and @Repository("package2.mybean") , but I am looking for a more efficient solution , that can automatically ease such situation . I hope the solution can achieve these goals :

  1. Programmers could arbitrarily name their bean className in his package , regardless of name conflicting with other packages(programmers). So that programmer doesn't need to yell 'Hey , I am going to use bean name XXXXX , don't conflict with me'.

  2. No manually XML bean name assign.

  3. If the bean name can be automatically assigned to the class's full class name , that would be great.

Any ideas ? Thanks. (Spring 3)

smallufo
  • 11,516
  • 20
  • 73
  • 111

2 Answers2

16

Somewhere in your config, you've enabled classpath scanning, probably using

<context:component-scan>

You can specify a property called name-generator, which takes a bean that implements the BeanNameGenerator interface. Create your own implementation of that interface and provide a reference to it.

Michal Bachman
  • 2,661
  • 17
  • 22
  • Here is my simple implementation of a package named bean name generator: public class PackageBeanNameGenerator implements BeanNameGenerator { public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { String beanClassName = Introspector.decapitalize(definition.getBeanClassName()); logger.debug("Instantiating bean with name: " + beanClassName); return beanClassName; } } – Stephane Oct 23 '15 at 16:24
6

This is because it is using AnnotationBeanNameGenerator which simply put non-qualified name(class name) as the bean name, then caused conflict.

Two steps to resolve this:

1、You can implement your own bean name generation strategy which use fully-qualified name (package + class name) like below

public class UniqueNameGenerator extends AnnotationBeanNameGenerator {
    @Override
    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
        //use fully-qualified name as beanName
        String beanName = definition.getBeanClassName();
        return beanName;
    }
}

2、Add @ComponentScan(nameGenerator = UniqueNameGenerator.class) to configuration or Boot class if you are using SpringBoot

@Configuration
@ComponentScan(nameGenerator = UniqueNameGenerator.class)
public class Config {
}
Frank Zhang
  • 800
  • 11
  • 11
  • 5
    In newer versions of Spring instead of writing your own implementation, you can just use `FullyQualifiedAnnotationBeanNameGenerator` which is doing exactly the same thing. – BeshEater Feb 24 '21 at 13:17