Talk is cheap,show you the code below

  1. Add @Import(EnglishCat.class) on the @SpringBootApplication main class,but the package of the EnglishCat class is not at the default scan package.
  2. Add @ImportResource({"classpath:spring/applicationContext.xml"}) also on the @SpringBootApplication main class
package com.meituan.mdp.module1;

import com.meituan.mdp.module2.EnglishCat;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;

@Import(EnglishCat.class)
@ImportResource({"classpath:spring/applicationContext.xml"})
@SpringBootApplication
public class ApplicationLoader {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(ApplicationLoader.class);
        application.setAdditionalProfiles("test");
        application.run(args);
    }
}
  1. The English Cat code as below,and the package is com.meituan.mdp.module2, and implements BeanNameAware, in order to see the bean name of the class has been registered to the Spring IOC container.
package com.meituan.mdp.module2;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;

@Configuration
public class EnglishCat implements BeanNameAware {

    String beanName;

    @PostConstruct
    public void sayHello() {
        System.out.println(this.beanName +":hello");
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }
}
  1. The code of spring/applicationContext.xml as below, only configures the component-scan,and the parameter base-package is com.meituan.mdp.module2, include the class of EnglishCat.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="com.meituan.mdp.module2"/>
</beans>

Now we run the sample, we can see Spring registers two beans with the class of EnglishCat. One is through the configuration class's registration. The other is through the <context:component-scan /> in the XML,configuration by the @ImportResource. And the bean name is not the same.

Spring @Import and component scan of the same class results in duplicate bean registration with different names

If <context:component-scan /> is replaced by @ComponentScan, the issue will gone, so I also read the source of Spring, to check the difference.

First: I found the registration of the Configuration class will check the list of Configuration in the code ConfigurationClassParser#configurationClasses, and the logic of @ComponentScan will add the Configuration class to ConfigurationClassParser#configurationClasses, but the process logic of <context:component-scan /> will not.

Second: When process the @Import(EnglishCat.class), the EnglishCat will be registered to the Spring container by a configuration Class whose bean name is Class#getName (spring source code is ConfigurationClassPostProcessor#importBeanNameGenerator), and register not judge the type.

In conclusion, no matter the order of processing @Import(EnglishCat.class) and spring/applicationContext.xml, the Spring container will register two beans of type EnglishCat,finally lead to some problem.

I don't know why the bean name of Imported configuration class is not the same with the component-scan (AnnotationBeanNameGenerator#buildDefaultBeanName)?

This code I have uploaded to GitHub in repository ioc-singleton-issue-sample1. You can clone and run to see this issue.

And if you use auto configuration of Spring-boot, you also will meet this issue, and I also write a sample, upload to GitHub in repository ioc-singleton-issue-sample2, you also can clone and run to see.

Expecting a reply! Thank you !!

Yours

Comment From: sbrannen

Thanks for getting in touch, but it feels like this is a question that would be better suited to Stack Overflow. As mentioned in the guidelines for contributing, we prefer to use the issue tracker only for bugs and enhancements. Feel free to update this issue with a link to the re-posted question (so that other people can find it) or add some more details if you feel this is a genuine bug.


The above is our standard policy for questions; however, the following should hopefully answer your question.

I don't know why the bean name of Imported configuration class is not the same with the component-scan (AnnotationBeanNameGenerator#buildDefaultBeanName)?

By default, components loaded via @Import and @ComponentScan/<context:component-scan /> have different BeanNameGenerator strategies applied to them, FullyQualifiedAnnotationBeanNameGenerator and AnnotationBeanNameGenerator respectively.

If you want englishCat to be the generated bean name and to avoid duplicate registration, you can add the following line to ApplicationLoader's main() method.

application.setBeanNameGenerator(AnnotationBeanNameGenerator.INSTANCE);

If you want com.meituan.mdp.module2.EnglishCat to be the generated bean name and to avoid duplicate registration, you can configure the component scanning in your XML file as follows.

<context:component-scan base-package="com.meituan.mdp.module2"
    name-generator="org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator" />

Both of these approaches will ensure that component scanning and @Import use the same BeanNameGenerator strategy.

In light of the above, I am closing this issue.