IoC 如何实现/ Spring IOC 体系结构 / IoC 容器的初始化 /IoC容器高级特性/ lazy-init延迟加载/FactoryBean和BeanFactory BeanPostFac

Spring框架最核心的思想之一就是 控制反转(IOC - Inversion Of Control)

IOC最常见的一种方式叫作 依赖注入(DI - Dependency Injection)

  • 控制了什么:我们一般会直接在程序内部通过new关键字进行创建对象,是程序主动去创建对象,而IOC是由一个专门的容器来统一创建并管理这些对象。

  • 理解反转:需要依赖所在容器来创建及注入依赖的对象。反转了什么呢?获得依赖对象的过程被反转,对象的创建和销毁不再全部由程序控制,而由Spring容器来控制。

IoC 如何实现

1)扫描注解或者配置文件,拿到Bean依赖服务实现的具体类名。
2)使用反射机制,基于雷鸣实例化对应对象的实例。
3)将对象实例,注入到需要依赖的地方。(构造器,或者 setter 方法 )

Spring IOC 体系结构

Spring提供了 IoC容器 来管理和容纳我们所开发出的各种各样的Bean,并且我们可以从中获取各种发布在Spring IoC 容器里的Bean,并且通过描述可以得到它。
在这里插入图片描述

Spring IoC 容器的初始化

Bean的定义和初始化,在Spring IoC 容器中是两个步骤:先定义(BeanDefinition),然后初始化和依赖注入。

Bean的定义分为以下3步:
1)Resouce定位:
Spring IoC 容器根据开发者的配置,扫描资源,进行定位。在 Spring 的开发中,通过XML配置或者注解都是常见的方式,定位的内容是由开发者提供的。

2)BeanDefinition载入:
当Resoure定位到信息后,保存到Bean定义(BeanDefinition)中,此时并不会创建Bean的实例。

3)BeanDefinition注册:
这个过程,就是将 BeanDefinition 的信息发布到 Spring IoC 容器中。注意:此时依然没有Bean对应的实例。

完成了以上三个步骤,Bean 就在 Spring IoC 容器中被定义了(创建了 Bean 对象的定义类 BeanDefinition,将 Bean 元素的信息设置到 BeanDefinition 中作为记录),而 没有被初始化,更没有完成依赖注入,也就是没有注入到其配置的资源给Bean,此时,它还不能完全被使用。当依赖注入时,才利用这些记录信息,创建和实例化具体的Bean对象。

Spring IoC容器高级特性

IoC高级特性

IoC容器对bean配置文件加载、解析、注册,实例化bean和依赖注入都是容器的基本功能

lazy-init延迟加载

Spring 根节点 节点提供了一个配置参数 default-lazy-init 默认为false。也就是说,默认时候是不进行延迟加载的,这样的话,在 Spring 容器初始化的时候,就会对bean进行注入。如果设置为true,那整个<beans>下面的节点默认进行延迟加载。

下的节点也有一个配置参数lazy-init,默认情况下为default 也就是上面的设置的default-lazy-init。如果在这里设置了的话,优先级比default-lazy-init高,指定Bean延迟加载。

FactoryBean和BeanFactory

我们根据Bean的ID,从BeanFactory中获取的对象,实际上是FactoryBean接口getObject()方法返回的对象。

FactoryBean源码:

 //工厂Bean,用于产生其他对象  
 public interface FactoryBean<T> {  
   //获取容器管理的对象实例  
    T getObject() throws Exception;  
    //获取Bean工厂创建的对象的类型  
    Class<?> getObjectType();  
    //Bean工厂创建的对象是否是单态模式,如果是单态模式,则整个容器中只有一个实例  
   //对象,每次请求都返回同一个实例对象  
    boolean isSingleton();  
} 
  • BeanFactory是bean工厂,Spring IoC最顶层的接口,作用是管理bean,即定位、配置对象、实例化和建立对象之间的依赖,getObject()方法由实现类调用,来创建bean实例化
    FactoryBean接口的作用,就是让我们可以封装自己定制的实例化逻辑。(如果想用工厂模式来实例化)然后让Spring进行统一管理。
    具体方式就是,我们写一个实现类,实现FactoryBean的方法,那么我们就可以在getObject()方法里实现我们的自定义实例化逻辑。

  • FactoryBean工厂bean,作用是产生其它bean实例,提供工厂方法,返回其它bean实例,一般Spring容器担任工厂角色

BeanPostFactory后置处理器

BeanPostProcessor 接口作用:

如果我们想在Spring容器中,完成Bean实例化,配置,以及其他初始化方法前后,加一些自定义处理逻辑。那就要自己定义BeanPostProcessor 实现类,然后注册到 Spring IoC 容器中。
此处注意:BeanPostProcessor的作用范围是整个Spring容器

源码如下:

package org.springframework.beans.factory.config;  
import org.springframework.beans.BeansException;  
public interface BeanPostProcessor {  
        //实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
        Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;  
        //实例化、依赖注入、初始化完毕时执行  
        Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;  
} 

这两个回调的入口都是和容器管理的Bean的生命周期事件紧密相关,可以为用户提供在 Spring IoC 容器初始化Bean过程中自定义的处理操作。
由API可以看出:
1)后置处理器的postProcessorBeforeInitailization方法,是在容器实例化Bean(实例化和初始化的区别:实例化是为Bean对象在内存中开辟空间,初始化是完成对依赖属性的注入,通过setter等方式),完成依赖的注入之后;显示的调用初始化方法之前调用(afterPropertiesSet和init-method之前)。
2)后置处理器的postProcessorAfterInitailization方法是在bean实例化、依赖注入及自定义初始化方法之后调用。

调用顺序简单示意如下:

--> Spring IOC容器实例化Bean
--> 调用BeanPostProcessor的postProcessBeforeInitialization方法
--> 调用bean实例的初始化方法
--> 调用BeanPostProcessor的postProcessAfterInitialization方法

具体使用方式:

//自定义后置处理器
public class MyPostProcessor implements BeanPostProcessor {
    //do something

    @Override
    Object postProcessBeforeInitialization(...){...}

    @Override
    Object postProcessAfterInitialization(...){...}
}

//然后将自定义的后置处理器配置到xml文件中
<!-- Spring后置处理器 -->
<bean id="myPostProcessor" class="com.test.spring.MyPostProcessor "/>

如果要定义多个BeanPostProcessor实现类,在xml中依次注册即可,默认情况下Spring会依据后置处理器的顺序依次调用。

<bean id="postProcessor" class="com.test.spring.PostProcessor"/>
<bean id="postProcessorB" class="com.test.spring.PostProcessorB"/>

Bean的构造方法,BeanPostProcessor 和 InitializingBean @PostConstruct @PreDestory 的执行关系。在Bean的生命周期中细讲。

@Autowire注解实现

注解相当于一种声明,通过反射去取对应的值。一般使用该注解的对象都是我们自己定义的Bean对象,Spring在初始化这些对象时都是默认调用该类的无参构造方法。因此对于@Autowire注解的属性,Spring会解析出并调用相应的构造方法:

  • 从构造方法缓存中查询其构造方法
  • 若缓存不存在,则根据反射获取所有构造方法
  • 遍历所有构造方法,查询器是否含有@Autowrie属性
  • 判断Autowire注解中指定了required属性(判断是否强依赖),若存在required就使用默认构造方法
  • 返回指定的构造方法

接下来是开始初始化,bean的自动装配发生在容器对bean的依赖注入过程中根据注解对属性注入

  • 第一次调用getBean()进行依赖注入时,完成依赖bean的初始化和注入
  • 将依赖bean的属性引用设置到被依赖的bean属性上
  • 将依赖bean的名称和被依赖bean的名称存储在IoC容器的集合中

文章持续更新:欢迎各位小伙伴关注我的公众号:菜丸的程序屋。希望将我的不足之处给予指点,谢谢大家。喜欢Java,热衷学习的小伙伴可以加我微信: CaiWan_Y
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值