问题:项目中遇到了定义的类名相同,包名不同,springboot项目启动时报ConflictingBeanDefinitionException。
查下来问题产生的原因是bean被初始化到spring容器的时候,使用的key默认是截取类完整路径的最后一个 “.” 之后的名称,
如:java.lang.String 被截取出来的就是 String 。AnnotationBeanNameGenerator源码如下:
解决方案:自定义BeanNameGenerator并指定
package **;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.util.StringUtils;
public class MyBeanNameGenerator extends AnnotationBeanNameGenerator {
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
String beanClassName = definition.getBeanClassName();
return beanClassName;
}
}
@MapperScan(value = "com.ll.api.*.mapper", nameGenerator = MyBeanNameGenerator.class)
@SpringBootApplication
@Import({ MybatisPlusConfig.class })
@ComponentScan(basePackages = { "com.ll" }, nameGenerator = MyBeanNameGenerator.class)
public class MySpringbootApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(MySpringbootApplication.class, args);
}
}
这里又遇到了几个坑点,一并记录下:
1、@MapperScan mybatis的扫码mapper的注解也需要指定nameGenerator为自定义的MyBeanNameGenerator;
2、@MapperScan扫描的包路径要指定到mapper文件对应的路径,别把其它类所在的包扫描进来。
我原本使用 @MapperScan(value = “com.ll”, nameGenerator = MyBeanNameGenerator.class) 就出问题了,项目启动报错:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.ll.**' available: expected single matching bean but found 2: com.ll.MyService,com.ll.IMyService
原因应该是mybatis扫描mapper文件的时候好死不死把除@Mapper注解之外的bean也给加载到spring ioc容器中了,其中就包含了我们加了@Service注解的MyService类
3、如果项目中有一个接口类拥有多个实现类,在使用@Autowired直接注入的时候会报错。spring容器无法知道我们默认要用哪个。此问题两种解法,
一是给默认要加载的实现类加上 @Primary 注解,表示有多个实现类时优先使用该类。
二是使用@Qualifier注解,先在实现类的Service注解加上ID,如@Service(“employeeService1”),然后在要使用该接口类的地方使用
@Qualifier(“employeeService”)指明实现类ID
// 实现类:
@Service("myServiceImpl1")
public class MyServiceImpl1 implements IMyService {
}
// 使用到的地方:
@Controller
public class MyControl {
@Autowired
@Qualifier("myServiceImpl1")
IMyService myService;
@RequestMapping( ... )
public void doSomething(HttpServletRequest request, HttpServletResponse response {
//#略
}