Spring IoC容器之BeanFactory底层实现代码解析(一)
2018-03-31 21:25
609 查看
Spring IoC容器是一个提供IoC支持的轻量级容器,除了基本的IoC支持,它作为轻量级容器还提供了IoC之外的支持。如在Spring的IoC容器之上,Spring还提供了相应的AOP框架支持、企业级服务集成等服务。Spring的IoC容器和上节提到的IoC Service Provider 所提供的服务之间存在一定的交集。二者的关系如图:
注意:ApplicationContext间接继承自BeanFactory,所以说它是构建于BeanFactory之上的IoC容器。此外,你应该注意到了, ApplicationContext还继承了其他四个接口,图中少了一个Environment。
BeanFactory,顾名思义,就是生产Bean的工厂,作为Spring提供的基本的IoC容器,BeanFactory可以完成作为IoC Service Provider的所有职责,包括业务对象的注册和对象间依赖关系的绑定。
BeanFactory就像一个手机生产厂,你可以从其他的手机零件厂商或者你自己的零件生产部门取得汽车零件送入手机生产厂,最后只需要取出手机即可。而我们同样也是把所有的业务对象交给BeanFactory,然后直接从BeanFactory取得最终组装完成并且可用的对象,至于这个中间“生产过程”,你无需了解,这一切的一切都有BeanFactory帮你搞定!
BeanFactory只是一个接口,我们最终需要一个该接口的实现来进行实际的Bean的管理,DefaultListableBeanFactory就是这么一个比较通用的BeanFactory实现类。DefaultListableBeanFactory除了间接地实现了BeanFactory接口,还实现了BeanDefinitionRegistry接口,该接口才是在BeanFactory的实现中担当Bean注册管理的角色,基本上,BeanFactory接口只定义如何访问容器内管理的Bean的方法,各个BeanFactory具体实现类负责具体Bean的注册以及管理工作。BeanDefinitionRegistry接口定义抽象了Bean的注册逻辑。通常情况下,具体的BeanFactory实现类会实现这个接口来管理Bean的注册。
它们的关系如下图所示:
打个比方说,BeanDefinitionRegistry就像商店的货架,所有的商品都是放在货架上的,虽然我们买东西或者送货都是和商店(BeanFactory)打交道,但是货架才是商店存放商品的地方,所以货架相对于商店来说,就是它的BeanDefinitionRegisry。
每个受管的对象,在容器中都会有一个BeanDefinition的实例(instance)与之对应,该BeanDefinition的实例负责保存对象的所有必要信息,包括其对应的对象的class类型、是否是抽象类、构造方法参数以及其他属性。当客户端向BeanFactory请求相应的对象时,BeanFactory会通过这些信息为客户端返回一个完备可用的对象实例。
RootBeanDefinition和ChildBeanDefinition是BeanDefinition的两个主要实现类。
下面我们就用代码实现一个BeanFactory!
一: 我们需要创建一个Animal类,作为被注入对象。这里我们选用两个String类型作为Animal属性。
(注意切记Animal类不能包含没有构造器的类型的属性,后面会讲原因)
二:然后写我们的测试类:
注意事项
在被注入对象中的属性不能是没有构造器的对象,诸如我们常用的数值类型。因为我们使用的是间接实现了BeanDefinition接口的RootBeanDefinition,而该类的该构造器不支持没有构造器的类。
使用通过setter方法注入时,必须为被注入对象实现一个默认的构造器(也就是一个无参的构造器)
②然后把这些注册为BeanDefinition实例的对象注册到容器中,(BeanDefinitionRegistry定义抽象bean的注册逻辑),然后把相应的对象对应于相应的bean的名字。
③这里我们以setter方法为例讲解:首先我们实例化一个MutablePropertyValues对象,然后为它添加属性值,最后为被注入对象设置属性值,最后把返回的BeanDefinitionRegistry强制转换为BeanFactory。
④在测试方法中,我们首先需要实例化一个DefaultListableBeanFactory(因为BeanFactory只是一个接口,我们最终需要一个该接口的实现来进行实际的Bean的管理,DefaultListableBeanFactory就是这么一个比较通用的BeanFactory实现类),然后通过我们刚才写的方法bindViaCode()就得到BeanFactory,最后就可以获得我们的Animal对象了。
注意:ApplicationContext间接继承自BeanFactory,所以说它是构建于BeanFactory之上的IoC容器。此外,你应该注意到了, ApplicationContext还继承了其他四个接口,图中少了一个Environment。
BeanFactory,顾名思义,就是生产Bean的工厂,作为Spring提供的基本的IoC容器,BeanFactory可以完成作为IoC Service Provider的所有职责,包括业务对象的注册和对象间依赖关系的绑定。
BeanFactory就像一个手机生产厂,你可以从其他的手机零件厂商或者你自己的零件生产部门取得汽车零件送入手机生产厂,最后只需要取出手机即可。而我们同样也是把所有的业务对象交给BeanFactory,然后直接从BeanFactory取得最终组装完成并且可用的对象,至于这个中间“生产过程”,你无需了解,这一切的一切都有BeanFactory帮你搞定!
下面就让我们从理解原理到自己用代码实现一个BeanFactory!
先说说我们的原理:BeanFactory只是一个接口,我们最终需要一个该接口的实现来进行实际的Bean的管理,DefaultListableBeanFactory就是这么一个比较通用的BeanFactory实现类。DefaultListableBeanFactory除了间接地实现了BeanFactory接口,还实现了BeanDefinitionRegistry接口,该接口才是在BeanFactory的实现中担当Bean注册管理的角色,基本上,BeanFactory接口只定义如何访问容器内管理的Bean的方法,各个BeanFactory具体实现类负责具体Bean的注册以及管理工作。BeanDefinitionRegistry接口定义抽象了Bean的注册逻辑。通常情况下,具体的BeanFactory实现类会实现这个接口来管理Bean的注册。
它们的关系如下图所示:
打个比方说,BeanDefinitionRegistry就像商店的货架,所有的商品都是放在货架上的,虽然我们买东西或者送货都是和商店(BeanFactory)打交道,但是货架才是商店存放商品的地方,所以货架相对于商店来说,就是它的BeanDefinitionRegisry。
每个受管的对象,在容器中都会有一个BeanDefinition的实例(instance)与之对应,该BeanDefinition的实例负责保存对象的所有必要信息,包括其对应的对象的class类型、是否是抽象类、构造方法参数以及其他属性。当客户端向BeanFactory请求相应的对象时,BeanFactory会通过这些信息为客户端返回一个完备可用的对象实例。
RootBeanDefinition和ChildBeanDefinition是BeanDefinition的两个主要实现类。
下面我们就用代码实现一个BeanFactory!
一: 我们需要创建一个Animal类,作为被注入对象。这里我们选用两个String类型作为Animal属性。
(注意切记Animal类不能包含没有构造器的类型的属性,后面会讲原因)
package com.spring; /** * @author home-pc * @create2018 -03 -31 -19:23 */ public class Animal { private String age; private String name; public Animal(String age, String name) { this.age = age; this.name = name; } public Animal() { } @Override public String toString() { return "Animal{" + "age='" + age + '\'' + ", name='" + name + '\'' + '}'; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
二:然后写我们的测试类:
注意事项
在被注入对象中的属性不能是没有构造器的对象,诸如我们常用的数值类型。因为我们使用的是间接实现了BeanDefinition接口的RootBeanDefinition,而该类的该构造器不支持没有构造器的类。
使用通过setter方法注入时,必须为被注入对象实现一个默认的构造器(也就是一个无参的构造器)
先看代码,看不懂代码的,可以看给出的解析:
解析:
①在bindViaCode()方法中,首先我们需要为那些被Spring管理的对象(Animal、string)注册为一个BeanDefinition的实例,这里我们选用的引用是BeanDefinition接口的一个实现类AbstractBeanDefinition(是一个抽象类),实际对象是继承AbstractBeanDefinition类的RootBeanDefinition类,其中构造器选用的是传入类和一个boolean变量(是否是一个单例的对象),②然后把这些注册为BeanDefinition实例的对象注册到容器中,(BeanDefinitionRegistry定义抽象bean的注册逻辑),然后把相应的对象对应于相应的bean的名字。
③这里我们以setter方法为例讲解:首先我们实例化一个MutablePropertyValues对象,然后为它添加属性值,最后为被注入对象设置属性值,最后把返回的BeanDefinitionRegistry强制转换为BeanFactory。
④在测试方法中,我们首先需要实例化一个DefaultListableBeanFactory(因为BeanFactory只是一个接口,我们最终需要一个该接口的实现来进行实际的Bean的管理,DefaultListableBeanFactory就是这么一个比较通用的BeanFactory实现类),然后通过我们刚才写的方法bindViaCode()就得到BeanFactory,最后就可以获得我们的Animal对象了。
package com.spring; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.PropertyValue; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.config.ConstructorArgumentValues; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; /** * @author home-pc * @create2018 -03 -31 -19:12 */ public class SpringBeanFactory { public static void main(String[] args) { DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory(); BeanFactory container = SpringBeanFactory.bindViaCode(beanRegistry); Animal animal = (Animal) container.getBean("animal"); System.out.println(animal); } public static BeanFactory bindViaCode(BeanDefinitionRegistry registry){ AbstractBeanDefinition age = new RootBeanDefinition(String.class,true); AbstractBeanDefinition name = new RootBeanDefinition(String.class,true); AbstractBeanDefinition animal = new RootBeanDefinition(Animal.class,true); // 将bean注册到容器中 registry.registerBeanDefinition("age",age); registry.registerBeanDefinition("name",name); registry.registerBeanDefinition("animal",animal); // 指定依赖关系 // 通过构造方法注入方式 // 先new一个构造器参数值 // ConstructorArgumentValues argumentValues = new ConstructorArgumentValues(); //// 为构造器传入我们上面在BeanDefinition的实现类中保存的受管对象age和name的信息。 // argumentValues.addIndexedArgumentValue(0,age); // argumentValues.addIndexedArgumentValue(1,name); //// 为构造器传入我们上面在BeanDefinition的实现类中保存的受管对象animal设置构造器参数 // animal.setConstructorArgumentValues(argumentValues); // 通过setter方法注入方式(切记需要一个默认的构造器(无参构造器)) MutablePropertyValues propertyValues = new MutablePropertyValues(); propertyValues.addPropertyValue(ne ab59 w PropertyValue("age",age)); propertyValues.addPropertyValue(new PropertyValue("name",name)); animal.setPropertyValues(propertyValues); return (BeanFactory) registry; } }
相关文章推荐
- Spring源码学习之:模拟实现BeanFactory,从而说明IOC容器的大致原理
- spring ioc容器的学习笔记4---XmlBeanFactory ioc容器的简单设计原理解析
- Spring AOP实现机制(二)--ProxyFactoryBean---将Spring AOP和Spring IoC容器相结合
- Spring学习--实现 FactoryBean 接口在 Spring IOC 容器中配置 Bean
- 【Spring揭秘】------ 第四章学习 Spring的IoC容器之BeanFactory 01
- 菜鸟学SSH(十三)——Spring容器IOC解析及简单实现
- 1000行代码读懂Spring(一)- 实现一个基本的IoC容器
- spring beans源码解读之 ioc容器之始祖--DefaultListableBeanFactory
- 底层解惑-spring的IOC相关接口:BeanFactory与FactoryBean
- Spring 源码深入解析(1)之bean容器的基本实现(二)
- Spring源码解析之IoC容器系列的设计实现(IoC容器系列概况)
- 【Spring源码--IOC容器的实现】(五)Bean对象的创建
- Spring原理(一)IoC容器的初始化过程之BeanFactory
- spring源码初步学习-容器(BeanFactory)基本实现
- 好记性不如烂笔头83-spring3学习(4)-spring的BeanFactory(IoC容器)
- spring接口 BeanFactoryAware,动态获取IOC容器里面的对象(多例)
- Spring定时任务的实现方式--ScheduledExecutorService and ScheduledExecutorFactoryBean的简单源码解析以及使用
- Spring源码-IOC容器(四)-FactoryBean
- Spring源码学习IOC(4):IoC容器解析Bean定义资源并注册解析后的Bean
- 【SSH进阶之路】Spring的IOC逐层深入——源码解析之IoC的根本BeanFactory(五)