今天在将一个项目的SpringBoot从2.7.8升级到3.2.0后,启动项目时报错,提示在自动装配时发现有2个同名的类,无法自动注入!
***************************
APPLICATION FAILED TO START
***************************
Description:
Field JwtAuthenticationEntryPoint in com.vesoft.ep.configuration.SecurityConfiguration required a single bean, but 2 were found:
- com.vesoft.ep.utils.JwtAuthenticationEntryPoint: defined in file [D:\BaiduSyncdisk\Works\Idea\BDO\EnterpriseProfile_Backend\target\classes\com\vesoft\ep\utils\JwtAuthenticationEntryPoint.class]
- jwtAuthenticationEntryPoint: defined in file [D:\BaiduSyncdisk\Works\Idea\BDO\EnterpriseProfile_Backend\target\classes\com\vesoft\ep\utils\JwtAuthenticationEntryPoint.class]
发现同一个类被注入了2次,一次是以类全路径作为key(在入口扫描组件加过nameGenerator配置)注入的,key为com.vesoft.ep.utils.JwtAuthenticationEntryPoint,一次是以类名作为key注入的,key为jwtAuthenticationEntryPoint。查了半天也没找到是什么原因引起的,到底是升级导致的问题还是springboot新版本引起的问题。于是新建了一个springboot3.2的项目,在入口配置了组件扫描和nameGenerator。
@SpringBootApplication
@ComponentScan(nameGenerator = UniqueNameGenerator.class)
public class TestDemoApplication extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(TestDemoApplication.class, args);
}
}
发现同一个类还是被注入了2次,当时就感觉很诧异,于是在入口加一段代码,打印出所有Bean的名称看看:
@Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
};
}
打印后发现确实是注入了2次,查询了各种资料后发现不知道从哪个版本开始(反正2.7.8没这情况),入口使用@SpringBootApplication和@ComponentScan注解,如果@ComponentScan设置了nameGenerator的话就会被注入2次,会以自定义和默认方式各注入一次。有几种解决办法:
1、删除@SpringBootApplication注解,增加@EnableAutoConfiguration注解,启动后问题解决。不过会引发其他问题,比如运行test时会提示用到的组件没有注入
2、不要使用@ComponentScan注解,在@SpringBootApplication注解上设置nameGenerator和scanBasePackages
@SpringBootApplication(nameGenerator = UniqueNameGenerator.class, scanBasePackages = { "xxxxx" })
public class TestDemoApplication extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(TestDemoApplication.class, args);
}
}