1、问题背景(问题已解决)
2、===============下面开始讲问题=====================
3、本人也没有对这个问题停止过脚步,也经过了如下几个分析过程:
4、解决方法
背景:整合公司基础框架时出现的这个问题,想让这个文档成为这种问题的终结者。
先说一下问题,这个问题可能有人遇到过:
Field service in BaseController required a single bean, but 2 were found:
- DicServiceImpl: defined in file [DicServiceImpl.class]
- TestServiceImpl: defined in file [TestServiceImpl.class]
初步分析为项目加载时出现了注入冲突,也就是无法通过ByType和ByName获得唯一的Bean
在BaseController中注入的service出现了重复情况,在下文中可以看到两个实现类都继承了BaseController,所以都注入了service这个Bean。但我上一个项目如法炮制却没有出现在这样的问题,泛型失效了?
项目架构是Springboot,JDK 1.8.0.191,泛型,maven复合项目结构,Application.java的配置有必要介绍下:
@EnableConfigurationProperties
@EnableTransactionManagement
@SpringBootApplication
@ComponentScan({"A","B","C","D"}) // 确定A、B、C、D包-包含了下文中所有的代码
public class Application extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.run(args);
}
}
下面的代码块是基础架构的去除了业务代码的一部分,,以便于各位了解问题的大致情况
@Controller
public class TestController extends BaseController{
}
@Controller
public class DicController extends BaseController {
}
// ==上面controller对应的父类
public abstract class BaseController , D extends BaseMapper, T extends BasePojo> {
@Autowired
protected S service;
}
@Service
public class TestServiceImpl extends BaseServiceImpl implements TestService {
}
@Service
public class DicServiceImpl extends BaseServiceImpl implements DicService{
}
// ==上面service对应的父类
public abstract class BaseServiceImpl,
T extends BasePojo> {
@Autowired
protected D mapper;
}
public interface TestMapper extends BaseMapper{
}
public interface DicMapper extends BaseMapper{
}
// ==上面的mapper对应的父类
public interface BaseMapper {
}
1、通过console的提示给实现类加上了@Primary(不推荐),或者在@Autowired自动注入的地方加上了@Qualifier指定,
问题虽然得到了解决,但是根据我上一个项目的经验,并没有在项目中使用这些注解依然能够正常运行,唯一的不同就是上个项目没分模块package,而且不区分service的父类和实现类,这就是为什么要追究问题的原因。
2、排除了Application.java中的包扫描配置未扫描到的问题
3、在spring获取上下文的地方打印出了所有的Bean,没有发现有重名的Bean
4、在@Service旁,指定Bean的name->@Service(testServiceOnly),无效。
到目前为止还是存在这样的疑惑,这么好的框架不应该让我每个都加注解才能不冲突吧!
5、既然所有依据控制台的解决方案都无效,我开始根据朋友们的意见检查项目,最后找到了解决方法。
下面是控制台加载整个项目的日志,和控制台循环输出的上下文中的bean:
20:32:41.803 [main] INFO com.jade.web.Application - Starting Application on tujiawei with PID 20288 (*\classes started by 10985 in jgzl-web)
20:32:41.822 [main] DEBUG com.jade.web.Application - Running with Spring Boot v2.1.3.RELEASE, Spring v5.1.5.RELEASE
20:32:41.822 [main] INFO com.jade.web.Application - The following profiles are active: dev
20:32:45.422 [main] INFO org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$18a5e7ad] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
20:32:46.315 [main] INFO org.springframework.boot.web.embedded.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http)
20:32:46.352 [main] INFO org.apache.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-0.0.0.0-8080"]
20:32:46.367 [main] INFO org.apache.catalina.core.StandardService - Starting service [Tomcat]
20:32:46.368 [main] INFO org.apache.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.16]
20:32:46.391 [main] INFO org.apache.catalina.core.AprLifecycleListener - The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [D:\jre1.8_191\bin;]
20:32:46.668 [main] INFO org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
20:32:46.668 [main] INFO org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 4704 ms
20:32:46.867 [main] INFO com.jade.core.common.SpringContextHolder - ===========================设置applicationContextorg.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@34d4860f, started on Thu Jul 18 20:32:41 CST 2019
ApplicationContext ac = SpringContextHolder.getApplicationContext();
String[] names = ac.getBeanDefinitionNames();
for (String name : names) {
System.out.println(">>>>>>" + name);
}
System.out.println("------\nBean 总计:" + ac.getBeanDefinitionCount());
result:
>>>>>>localeCharsetMappingsCustomizer
>>>>>>org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
>>>>>>multipartConfigElement
>>>>>>multipartResolver
等300+个bean
------
Bean 总计: 354
检查所有继承了BaseController的类,看是否指定了泛型,如果没有指定泛型,那么这些类将会被注入同一个beantype
而BaseController中的@Autowired,将无法通过byType获取唯一的bean。所以导致此问题的产生。
==这种自动注入的原理是来自Spring4.0的新特性——泛型依赖注入==