springboot/maven复合项目出现Field service in controller required a single bean, but 2 were found

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<TestServiceImpl, TestMapper, Test>{
}
@Controller
public class DicController extends BaseController<DicServiceImpl, DicMapper, Dic> {
}

// ==上面controller对应的父类
public abstract class BaseController <S extends BaseServiceImpl<D,T>, D extends BaseMapper<T>, T extends BasePojo<T>> {
    @Autowired
    protected S service;
}

@Service
public class TestServiceImpl extends BaseServiceImpl<TestMapper, Test> implements TestService {
}
@Service
public class DicServiceImpl extends BaseServiceImpl<DicMapper, Dic> implements DicService{
}

// ==上面service对应的父类
public abstract class BaseServiceImpl<D extends BaseMapper<T>, 
                                                        T extends BasePojo<T>> {
    @Autowired
    protected D mapper;
}

public interface TestMapper extends BaseMapper<Test>{
}
public interface DicMapper extends BaseMapper<Dic>{
}

// ==上面的mapper对应的父类
public interface BaseMapper<T> {
}



我没有对这个问题停止过脚步,大概回忆起如下几个分析过程

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的新特性——泛型依赖注入==

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值