Service无法注入

前言

//Service无法注入跑出异常
Field xxxService in com.xx.xx.service.impl.XxXServiceImpl required a bean of type 'com.xx.xx.service.XxxService' that could not be found.

这个错误其实就是这个Bean在Spring容器中找不到,发生这种错误时,常见的有两种情况:

  • @ComponentScan注解里的扫描路径没包含这个类

  • 使用的类的没加@Component注解

思考

为什么@ComponentScan扫描到了并且加了@Component注解就能注入到Spring容器中?

@ComponentScan扫描是做了什么?
过程大概是这样的:Spring通过扫描指定包下的类,解析这些类的信息,转化成为BeanDefinition,注册到beanDefinitionMap中。

那么这个过程的详情情况又是如何呢?

我们先来了解一下这个过程中涉及到的角色:

  • 1、BeanDefinition:Bean定义,内含Class的相关信息
  • 2、ConfigurationClassPostProcessor:配置类处理器,查找配置类,创建配置类解析器
  • 3、ConfigurationClassParser:配置类解析器,解析配置类,创建@ComponentScan注解解析器
  • 4、ComponentScanAnnotationParser@ComponentScan注解解析器,解析@ComponentScan注解,创建Bean定义扫描器
  • 5、ClassPathBeanDefinitionScanner:Bean定义扫描器,扫描指定包下的所有类,将符合的类转化为BeanDefinition
  • 6、BeanDefinitionRegistryBeanDefinition注册器,注册BeanDefinition
    在这里插入图片描述

1.配置类处理器

配置类处理器主要做了3件事

  • 1、查找配置类
  • 2、创建配置类解析器并调用
  • 3、加载配置类解析器所返回的@Import与@Bean注解的类

1.1查找配置类
你可能会有疑惑,配置类不是我们传入的吗?为什么还需要去查找配置类呢?

这是因为Spring整个调用链路十分复杂,不可能说把配置类往下层层传递,而是一开始时就将配置类注册到BeanDefinitonMap中了。

查找配置类大致有两个过程:

  • 1、从BeanFactory中获取到所有的BeanDefiniton信息
  • 2、判断BeanDefiniton是否为配置类

第一步很好解决,所有的BeanDefiniton是放在BeanFactoryBeanDefinitonMap中,直接从中获取就可以了。

而对于第二点,首先我们要知道什么是配置类?

在Spring中,有两种配置类:

  • 1、full类型:标识了@Configuration注解的类
  • 2、lite类型:标识了@Component @ComponentScan @Import @ImportResource @Bean注解的类(其中之一就行)

他们唯一的区别就在于:full类型的类会在后置处理步骤中进行动态代理

举个例子:

@Configuraiton
public class MyConfiguration{
  @Bean
  public Car car(){
      return new Car(wheel());
  }
  @Bean
  public Wheel wheel(){
      return new Wheel();
  }
}

问:Wheel对象在Spring启动时,被new了几次?

答案是一次,因为MyConfiguration对象实际上会被进行cglib动态代理,所以就算被this.的方式调用依旧会触发代理逻辑

注意:只有在这个情况下是这样,平常我们进行cglib代理时this调用依旧直接调用本类方法。

当查找出所有的配置类信息之后,紧接着就是创建配置类解析器,并将所有的配置类交由配置类解析器进行解析

1.2流程图
在这里插入图片描述
2.配置类解析器

配置类解析器的职责如下

  • 1、判断该类是否应该跳过解析
  • 2、解析内部类信息
  • 3、解析@PropertySources注解信息
  • 4、解析@ComponentScan注解信息
  • 5、解析@Import注解信息
  • 6、解析@Bean注解信息

2.1判断该类是否应该跳过解析

所谓判断类是否应该跳过解析,其实就是判断类是否标识了@Conditional注解并且是否满足该条件。如果标识了该注解并且不满足条件,那么则跳过解析步骤。

常见的@Profile,@ConditionalOnMissBean等都是由此控制。

2.2解析内部类信息

有时候我们的配置类里面有内部类,并且内部类也是个配置类,那么就需要用此方式进行解析。

2.3解析@ComponentScan注解信息

该步骤主要是利用@ComponentScan注解解析器进行解析@ComponentScan注解,从而获取到BeanDefinition列表,再判断这些BeanDefinition是否是个配置类,是则再次调用配置类解析器**进行递归解析。
在这里插入图片描述

3.@ComponentScan注解解析器

在该步骤中,Spring会将我们配置在@ComponentScan注解上的所有信息提取出来,存入到Bean定义扫描器中,再利用Bean定义扫描器得到符合条件的BeanDefiniton
在这里插入图片描述

excludeFilterincludeFilter用于扫描时判断class是否符合要求。

默认的excludeFilter:扫描时排除掉自己这个class

默认的includeFilter: 扫描时判断该class是否标识@Component注解

4.Bean定义扫描器

BeanDefinitionScanner主要做了三件事:

  • 1、扫描包路径下的类
  • 2、给BeanDefiniton设值
  • 3、使用BeanDefinition注册器将BeanDefiniton注册到容器中

4.1扫描包路径下的类

扫描包路径的步骤可以简单理解为遍历class文件的过程,遍历包下的每个class,判断该class是否满足条件标识了@Component注解,将满足条件的class转化为BeanDefiniton,此时BeanDefiniton只有metedata信息,还没有具体设值。

4.2给BeanDefiniton设值

如果我们在类上加了类似这些注解:@Lazy @Primary @DependsOn,那么就需要将这些注解转化为实际的属性设到BeanDefiniton中。
在这里插入图片描述

5.BeanDefinition注册器

BeanDefinitionRegistry的作用就是将BeanDefiniton放到BeanDefinitonMap

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值