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

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

public Interface ParentService{
    public String hello(String msg);
}
public abstract class ChildrenOneService implements ParentService{

    @Override
    public String hello(String msg){
        System.out.println("ChildrenOne say"+msg);
    }

}
public abstract class ChildrenTwoService implements ParentService{

    @Override
    public String hello(String msg){
        System.out.println("ChildrenTwo say"+msg);
    }

}

 

@RestController
public class TestApi{
    @Resource(type = ChildrenOneService.class)
    private Parent childrenOneService;

    @Resource(type = ChildrenTwoService.class)
    private Parent childrenTwoService;
    
    @PostMapping("/test1")
    public String sayOne(String msg){
        childrenOneService.hello(msg);
    }

    @PostMapping("/test2")
    public String sayTwo(String msg){
        childrenTwoService.hello(msg);
    }

}

      在执行过程中报空指针异常,打断点发现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关键字来修饰类名。

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

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

改后(以ChildrenOneService为例):

//去掉了abstract
public class ChildrenOneService implements ParentService{

    @Override
    public String hello(String msg){
        System.out.println("ChildrenOne say"+msg);
    }

}

你可能感兴趣的:(spring,boot,java,后端)