• 记一次SpringBoot中Service层未注入排查


        同事自己在自己的电脑上写了一些小东西,遇到了请求时API层注入的Service为空问题。整体代码接口伪代码如下:

    1. public Interface ParentService{
    2. public String hello(String msg);
    3. }
    1. public abstract class ChildrenOneService implements ParentService{
    2. @Override
    3. public String hello(String msg){
    4. System.out.println("ChildrenOne say"+msg);
    5. }
    6. }
    1. public abstract class ChildrenTwoService implements ParentService{
    2. @Override
    3. public String hello(String msg){
    4. System.out.println("ChildrenTwo say"+msg);
    5. }
    6. }

     

    1. @RestController
    2. public class TestApi{
    3. @Resource(type = ChildrenOneService.class)
    4. private Parent childrenOneService;
    5. @Resource(type = ChildrenTwoService.class)
    6. private Parent childrenTwoService;
    7. @PostMapping("/test1")
    8. public String sayOne(String msg){
    9. childrenOneService.hello(msg);
    10. }
    11. @PostMapping("/test2")
    12. public String sayTwo(String msg){
    13. childrenTwoService.hello(msg);
    14. }
    15. }

          在执行过程中报空指针异常,打断点发现childrenOneService和childrenTwoService全部为空。直接在AbstractApplicationContext里的refresh方法里最后一行finishRefresh打断点查看beanFactory里的beanDefinitionMap里的bean是否存在。经过排查发现Map里没有这两个类型的Bean。

         第一步:怀疑是Application.java的ComponentScan没有扫描到。

              查看Application.java启动类,发现Application类上没有配置ComponentScan,那么SpringBoot默认扫描Application文件所在同级目录下的所有类。发现ChildrenOneService和ChildrenTwoService在Application文件所在的同级目录下。

        第二步:怀疑是ChildrenOneService和ChildrenTwoService不符合bean的规范。检查这两个类发现这两个类的类定义里使用了abstract关键字来修饰类名。

    1. protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
    2. AnnotationMetadata metadata = beanDefinition.getMetadata();
    3. return (metadata.isIndependent() && (metadata.isConcrete() ||
    4. (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
    5. }

    在springboot源码中发现加载时会判断是否时符合要求的组件,其中发现组件是抽象的且被Lookup注解才会被加载。所以在将ChildrenOneService和ChildrenTwoService类由抽象改为普通类后,注入成功了。

    改后(以ChildrenOneService为例):

    1. //去掉了abstract
    2. public class ChildrenOneService implements ParentService{
    3. @Override
    4. public String hello(String msg){
    5. System.out.println("ChildrenOne say"+msg);
    6. }
    7. }

  • 相关阅读:
    快速了解Spring Cache
    C++新特性笔记(1)
    SpringAOP源码解析之基础设施注册(一)
    SAP Business One二次开发:解锁潜力,实现定制化需求
    第十五届蓝桥杯模拟赛(第一期)
    状态模式详解
    数学建模如何创新
    操作系统MIT6.S081:Lab5->Lazy allocation
    算法-二叉树-简单-二叉树的遍历
    dolphinscheduler 3.0.1 数据源中心及使用
  • 原文地址:https://blog.csdn.net/xl649138628/article/details/133785053