spring系列之IOC

实战:

1、spring在bean初始化前中后需要加代码怎么办?

看这里:自定义MyPostProcessor类,并实现BeanPostProcessor接口,并重写postProcessBeforeInitialization方法和postProcessAfterInitialization方法即可实现,在bean装在前和装在后干一些小动作。在bean初始化中的时候干一些小动作就要在bean配置的xml文件的bean节点中配置对应的init-method="myInit"方法

看下边:

public class MyPostProcessor implements BeanPostProcessor {  

   @Override  

   public Object postProcessBeforeInitialization(Object bean, String beanName)

           throws BeansException {  

       System.out.println("对象" + beanName + "初始化前干的小动作");  

       return bean;  

   }  

   @Override  

   public Object postProcessAfterInitialization(Object bean, String beanName)  

           throws BeansException {  

       System.out.println("对象" + beanName + "初试化完成后干的小动作");  

       return bean;  

   }  

}  
<bean id="MyBean" class="xxx.MyBean" init-method="myInit"></bean>

配置了之后,在初始化的时候会执行TestBean中定义的myInit方法。

IOC原理:

1、(定位)现根据配置的bean文件的路径找到文件,并解析为document对象

XmlBeanDefinitionReader 类中的 doLoadBeanDefinition() 方法是从特定 XML 文件中实际载入
Bean 配置资源的方法,该方法在载入 Bean 配置资源之后将其转换为 Document 对象
 
 

2、(加载)下边开始解析具体的解析过程由 BeanDefinitionParserDelegate 实现BeanDefinitionParserDelegate 中定义了 Spring Bean 定义 XML 文件的各种元素具体的解析方法parseBeanDefinitions

当依赖注入时才 使用这些记录信息创建和实例化具体的 Bean 对象。(此处只是解析配置的bean)
接下来调用 registerBeanDefinitions() 启 动 Spring IOC 容 器 对 Bean 定 义 的 解 析 过 程。
 
经过对 Spring Bean 配置信息转换的 Document 对象中的元素层层解析,Spring IOC 现在已经将 XML
形式定义的 Bean 配置信息转换为 Spring IOC 所识别的数据结构—— BeanDefinition ,它是 Bean 配
置信息中配置的 POJO 对象在 Spring IOC 容器中的映射,我们可以通过 AbstractBeanDefinition 为
入口,看到了 IOC 容器进行索引、查询和操作。
通过 Spring IOC 容器对 Bean 配置资源的解析后,IOC 容器大致完成了管理 Bean 对象的准备工作,
即初始化过程,但是最为重要的依赖注入还没有发生,现在在 IOC 容器中 BeanDefinition 存储的只是
一些静态信息,接下来需要向容器注册 Bean 定义信息才能全部完成 IOC 容器的初始化过程

3、(注册)是由DefaultListableBeanFactory类的registerBeanDefinition(String beanName, BeanDefinition beanDefinition)方法注册到IOC容器里的。、

IOC容器就是一个map,key是beanName,value是Document解析成的BeanDefinition(BeanDefinition里存放了bean所有的定义信息)

/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);


synchronized (this.beanDefinitionMap) {
	this.beanDefinitionMap.put(beanName, beanDefinition);
	List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
	updatedDefinitions.addAll(this.beanDefinitionNames);
	updatedDefinitions.add(beanName);
	this.beanDefinitionNames = updatedDefinitions;
	if (this.manualSingletonNames.contains(beanName)) {
		Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
		updatedSingletons.remove(beanName);
		this.manualSingletonNames = updatedSingletons;
	}
}
至此,Bean 配置信息中配置的 Bean 被解析过后,已经注册到 IOC 容器中,被容器管理起来,真正完
成了 IOC 容器初始化所做的全部工作。现在 IOC 容器中已经建立了整个 Bean 的配置信息,这些
BeanDefinition 信息已经可以使用,并且可以被检索,IOC 容器的作用就是对这些注册的 Bean 定义信
息进行处理和维护。这些的注册的 Bean 定义信息是 IOC 容器控制反转的基础,正是有了这些注册的数
据,容器才可以进行依赖注入。
 

至此已经完成了IOC容器的初始化工作,bean的实例化是发生在注入阶段。

 

小结:

1、初始化的入口在容器实现中的 refresh()调用来完成。
2、对 Bean 定义载入 IOC 容器使用的方法是 loadBeanDefinition(), 其中的大致过程如下:通过 ResourceLoader 来完成资源文件位置的 定位 ,DefaultResourceLoader 是默认的实现,同时上下文本身就给出了 ResourceLoader 的实现,可以从类路径,文件系统,URL 等 方式来定为资源位置。如果是 XmlBeanFactory 作为 IOC 容器,那么需要为它指定 Bean 定义的资源, 也 就 是 说 Bean 定 义 文 件 时 通 过 抽 象 成 Resource 来 被 IOC 容 器 处 理 的 , 容 器 通 过BeanDefinitionReader 来 完 成 定 义 信 息 的 解 析 和 Bean 信 息 的 注 册 , 往 往 使 用 的 是 XmlBeanDefinitionReader 来 解 析 Bean 的 XML 定 义 文 件 - 实 际 的 处 理 过 程 是 委 托 给 BeanDefinitionParserDelegate 来完成的,从而 得到 bean 的定义信息 ,这些信息在 Spring 中使用 BeanDefinition 对象来表示-这个名字可以让我们想到loadBeanDefinition(),registerBeanDefinition() 这些相关方法。它们都是为处理 BeanDefinitin 服务的,容器解析得到 BeanDefinition 以后,需要把 它 在 IOC 容器中注册,这由 IOC 实现 BeanDefinitionRegistry 接口来实现 。注册过程就是在 IOC 容器 内部维护的一个 HashMap 来保存得到的 BeanDefinition 的过程。这个 HashMap 是 IOC 容器持有 Bean 信息的场所,以后对 Bean 的操作都是围绕这个 HashMap 来实现的。 然后我们就可以通过 BeanFactory 和 ApplicationContext 来享受到 Spring IOC 的服务了,在使用 IOC 容器的时候,我们注意到除了少量粘合代码,绝大多数以正确 IOC 风格编写的应用程序代码完全不用关 心如何到达工厂,因为容器将把这些对象与容器管理的其他对象钩在一起。基本的策略是把工厂放到已 知的地方,最好是放在对预期使用的上下文有意义的地方,以及代码将实际需要访问工厂的地方。Spring 本身提供了对声明式载入web应用程序用法的应用程序上下文,并将其存储在ServletContext中的框架 实现。
 

 

 

spring DI依赖注入相关


补充:以XML配置为例

1、根据application.xml文件定位到bean配置文件

2、AbstractApplicationContext的refresh()方法定义了bean定义(bean.xml文件)载入流程

3、refresh()方法中的obtainFreshBeanFactory()方法具体的启动容器载入bean配置信息

4、AbstractRefreshableApplicationContext中的refreshBeanFactory()方法先判断如果有容器存在则先销毁容器中的bean并关闭容器,然后再调用createBeanFactory(); 创建IOC容器,然后调用loadBeanDefinitions(beanFactory);方法加载bean定义文件

5、AbstractXmlApplicationContext中的loadBeanDefinitions(beanFactory);方法就是具体的载入bean定义的方法。

6、以Xml配置为例会调用AbstractBeanDefinitionReader类中的loadBeanDefinitions()方法加载bean定义资源。

7、具体的读取bean定义资源文件的是在XmlBeanDefinitionReader类中的doLoadBeanDefinitions()方法,最终会将bean定义资源文件转换成一个Document对象

下边开始加载解析出来的document对象的bean定义文件

8、XmlBeanDefinitionReader类中的registerBeanDefinitions()方法最终会调用DefaultBeanDefinitionDocumentReader类种的

doRegisterBeanDefinitions(Element root)方法去解析。真正解析bean配置资源标签的是parseBeanDefinitions()方法,最终将解析好的数据放在springIOC所认识的数据结构BeanDefinition对象里边。
至此,IOC 容器大致完成了管理 Bean 对象的准备工作, 但是最为重要的依赖注入还没有发生(依赖注入发生的两个时间:1、第一次调用getBean方法。2、在bean定义标签里指定lazy-init=false即不适用懒加载),现在在 IOC 容器中 BeanDefinition 存储的只是 一些静态信息,接下来需要向容器注册 Bean 定义信息才能全部完成 IOC 容器的初始化过程
 

9、将解析好的BeanDefinition向容器中注册:DefaultListableBeanFactory类中的 registerBeanDefinition(String beanName, BeanDefinition beanDefinition)方法就是注册的具体方法:最终会把BeanDefinition通过

synchronized (this.beanDefinitionMap) {
   this.beanDefinitionMap.put(beanName, beanDefinition);的方式将beanName和BeanDefinition放在一个ConcurrentHashMap中。

至此IOC容器已经初始化完毕,在IOC容器中已经建立了整个bean的配置信息,IOC 容器的作用就是对这些注册的 Bean 定义信 息进行处理和维护。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值