Spring IoC

前言 Spring所依赖的两个核心理念,一个是控制反转(IoC),另一个是面向切面编程(AOP),IoC是Spring的核心。
IoC是一种通过描述来生成或者获取对象的技术,在Spring中把每一个需要管理的对象成为Spring Bean,管理这些Bean的容器,被我们称为Spring IoC容器,IoC容器需要具备以下两个特点:

  • 通过描述管理Bean,包括发布和获取。
  • 通过描述完成Bean之间的依赖关系。
    IoC容器简介【Spring IoC】Spring IoC容器是一个管理Bean的容器,在Spring的定义中,所有的IoC容器都必须实现接口 BeanFactory,它是一个顶级的容器接口。
    BeanFactory 接口中定义了多个 getBean 方法,它们的意义就是在容器中获取Bean,其中允许我们按照类型或是名称来获取指定的Bean。
    默认情况下,Bean在容器中都是以单例存在的。
    由于 BeanFactory 接口还不够强大,于是Spring开发了一个更高级的接口 ApplicationContext,它是 BeanFactory 的子接口之一,它在 BeanFactory 的基础上扩展了消息国际化接口(MessageSource)、环境可配置接口(EnvironmentCapable)、应用事件发布接口(ApplicationEventPublisher)和资源模式解析接口(ResourcePatternResolver), 所以它的功能更加强大。
    Spring为我们实现了许多IoC容器,这里主要介绍基于注解的容器 AnnotationConfigApplicationContext
依赖注入 Bean之间的依赖关系,Spring的容器概念中,称之为依赖注入。
Bean的生命周期 Bean的生命周期大致上分为,Bean的定义,Bean的初始化,Bean的生存期和Bean的销毁。
Bean的定义的流程如下:
graph TD R1[例如ComponentScan注解所定义的扫描包] R2[将Bean的定义保存到BeanDefinition的实例中] R3[IoC容器装载Bean定义] F1[资源定位] F2[Bean定义] F3[发布Bean定义] R1 -.-> F1 R2 -.-> F2 R3 -.-> F3 F1 --> F2 F2 --> F3

Bean的之后三个流程的流程如下:
graph TD R1([接口BeanNameAware]) R2([接口BeanFactoryAware]) R3([接口ApplicationContextAware - 需要容器实现ApplicationContext接口才会被调用]) R4([接口BeanPostProcessor的预初始化方法 - 针对全部Bean生效]) R5([PostConstruct注解标注的方法]) R6([接口InitializingBean]) R7([接口BeanPostProcessor的后初始化方法 - 针对全部Bean生效]) R8([PostConstruct注解标注的方法]) R9([接口DisposableBean]) F1[初始化] F2[依赖注入] F3[setBeanName方法] F4[setBeanFactory方法] F5[setAppliationContext方法] F6[postProcessBeforeInitialization方法] F7[自定义初始化方法] F8[afterPropertiesSet方法] F9[postProcessAfterInitialization方法] F10{生存期} F11[自定义销毁方法] F12[destory方法]F1 --> F2 ---> F3 R1 -.-> F3 F3 ---> F4 R2 -.-> F4 ---> F5 R3 -.-> F5 F5 ---> F6 R4 -.-> F6 F6 ---> F7 R5 -.-> F7 F7 ---> F8 R6 -.-> F8 F8 ---> F9 R7 -.-> F9 F9 ---> F10 --> F11 R8 -.-> F11 F11 ---> F12 R9 -.-> F12

注解解析 @Configuration 代表被注解标记的类是一个Java的配置文件。
@Bean 代表被注解标记的方法返回的POJO装配到容器中。
  • name 定义容器中Bean的名称,如果没有配置,默认使用方法名作为Bean的名称。
  • initMethod 自定义初始化方法
  • destroyMethod 自定义销毁方法
@Component 代表被注解标记的类被装配到容器中
  • value 定义容器中Bean的名称,如果没有配置,默认使用类名首字母小写作为Bean的名称。
@ComponentScan 表明采用何种策略去装配Bean,该注解默认的扫描路径为标注注解的类所在包以及其子包
  • basePackages 指定需要扫描的包,可以使用正则表达式。
  • basePackageClasses 指定需要扫描的类。
  • includeFilters 满足过滤条件的Bean才扫描。
  • excludeFilters 排除过滤条件的Bean才扫描。
  • lazyInit 延迟初始化,默认为false
    @ComponentScan(basePackages = "com.springboot.xx.*", excludeFilters = {@Filter(classes = {UserService.class})}) // 该示例中,指定扫描com.springboot.xx下面的所有包,而排除了UserService的装配,即时该类标注了创建Bean的注解,Spring也不会将其装配到容器中。

    @SpringBootApplication 注解中也添加了@ComponentScan注解,我们可以使用它提供的 scanBasePackages scanBasePackageClasses 来配置扫描路径,其外,它还提供了 exclude excludeName 来通过名称或类型来排除自动配置类,如果这些属性满足不了你对装配的需求,可以额外使用@ComponentScan注解。
@Autowired 依赖注入注解,会根据类型找到对应的Bean进行注入,如果寻找的Bean不是唯一的,那么它会根据其属性名称和Bean的名称进行匹配,如果匹配成功,则使用该Bean,如果仍无法匹配,则抛出异常。该注解是一个默认必须找到对应Bean的注解。
  • required 如果不能确定注解标注属性一定存在并且允许这个属性为null的时候,可以将该值配置为 false
@Primary 装配优先权注解,当@Autowired找到两个相同类型的Bean时,会优先使用被@Primary标注的Bean,而不是抛出异常。
注意:当多个相同类型的Bean同时标注了@Primary,@Autowired仍会抛出异常。
@Qualifier 与@Autowired一同使用
  • value 指定注入的Bean的名称

    推荐阅读