美文网首页
Spring深入 2.IOC设计原理与实现

Spring深入 2.IOC设计原理与实现

作者: 香沙小熊 | 来源:发表于2020-01-03 20:55 被阅读0次

知识点:

1、源码学习的目标
2、Bean的构建过程
3、BeanFactory与ApplicationContext区别

1、源码学习目标:

  1. Bean工厂是如何生产Bean的?
  2. Bean的依赖关系是由谁解来决的?
  3. Bean工厂和应用上文的区别?

2、Bean的构建过程

spring.xml 文件中保存了我们对Bean的描述配置,BeanFactory 会读取这些配置然后生成对应的Bean。这是我们对ioc 原理的一般理解。但在深入一些我们会有更多的问题?

  1. 配置信息最后是谁JAVA中哪个对象承载的?
  2. 这些承载对象是谁业读取XML文件并装载的?
  3. 这些承载对象又是保存在哪里?

BeanDefinition (Bean定义)
ioc 实现中 我们在xml 中描述的Bean信息最后 都将保存至BeanDefinition (定义)对象中,其中xml bean 与BeanDefinition 程一对一的关系。

image.png

由此可见,xml bean中设置的属性最后都会体现在BeanDefinition中。如:

XML-bean BeanDefinition
class beanClassName
scope scope
lazy-init lazyInit
constructor-arg ConstructorArgument
property MutablePropertyValues
factory-method factoryMethodName
destroy-method AbstractBeanDefinition.destroyMethodName
init-method AbstractBeanDefinition.initMethodName
autowire AbstractBeanDefinition.autowireMode
id
name
  • 演示查看 BeanDefinition 属性结构
image.png
BeanMetadataElement:用于传送配置源对象的超级接口
public interface BeanMetadataElement {
    //获取源对象,可能返回null
    Object getSource();
}
AttributeAccessor定义用于附加和访问元数据的通用的接口,来自任意对象
public interface AttributeAccessor {
 
    //设置属性的值
    void setAttribute(String name, Object value);
 
    //获得指定属性名称的值,如果不存在返回null
    Object getAttribute(String name);
 
    //删除指定的name的属性,如果不存在则返回null
    Object removeAttribute(String name);
 
    //判断指定的属性名称是否存在,注意属性名称必须是唯一的
    boolean hasAttribute(String name);
 
    //得到所有属性的名称
    String[] attributeNames();
 
}

BeanDefinitionRegistry(Bean注册器)
在上表中我们并没有看到 xml bean 中的 id 和name属性没有体现在定义中,原因是ID 其作为当前Bean的存储key注册到了BeanDefinitionRegistry 注册器中。name 作为别名key 注册到了 AliasRegistry 注册中心。其最后都是指向其对应的BeanDefinition。

  • 演示查看 BeanDefinitionRegistry属性结构
image.png

BeanDefinitionReader(Bean定义读取)
至此我们学习了 BeanDefinition 中存储了Xml Bean信息,而BeanDefinitionRegister 基于ID和name 保存了Bean的定义。接下要学习的是从xml Bean到BeanDefinition 然后在注册至BeanDefinitionRegister 整个过程。

image.png

上图中可以看出Bean的定义是由BeanDefinitionReader 从xml 中读取配置并构建出 BeanDefinitionReader,然后在基于别名注册到BeanDefinitionRegister中。

  • 查看BeanDefinitionReader结构
    image.png

方法说明:

  • loadBeanDefinitions(Resource resource)
    • 基于资源装载Bean定义并注册至注册器
  • int loadBeanDefinitions(String location)
    • 基于资源路径装载Bean定义并注册至注册器
  • BeanDefinitionRegistry getRegistry()
    • 获取注册器
  • ResourceLoader getResourceLoader()
    • 获取资源装载器
  • 基于示例演示BeanDefinitionReader装载过程
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd"
>
    <!--    指定构造函数构建-->
    <bean id="helloSpring" class="com.kpioneer.springdemo.HelloSpring" autowire="byType">

        <constructor-arg index="0" value="xionghu"/>
        <constructor-arg index="1" value="2"/>
    </bean>

    <bean class="com.kpioneer.springdemo.Hi"/>

    <bean id="MethodInject" class="com.kpioneer.springdemo.MethodInject">
        <lookup-method name="getHi"></lookup-method>
    </bean>

</beans>
public class BeanDefinitionReaderExample {
    public static void main(String[] args) {
        /**
         * 注册中心
         */
        BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
        /**
         * 创建资源读取器
         */
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
        /**
         * 资源读取器
         */
        DefaultResourceLoader loader = new DefaultResourceLoader();
        /**
         * 获取资源
         */
        Resource resource = loader.getResource("spring.xml");
        /**
         * 装载Bean的定义
         */
        reader.loadBeanDefinitions(resource);
        /**
         *  打印构建的Bean 名称
         */
        System.out.println(Arrays.toString(registry.getBeanDefinitionNames()));
    }
}

Beanfactory(bean 工厂)
有了Bean的定义就相当于有了产品的配方,接下来就是要把这个配方送到工厂进行生产了。在ioc当中Bean的构建是由BeanFactory 负责的。其结构如下:

image.png

方法说明:

  • getBean(String)
    • 基于ID或name 获取一个Bean
  • <T> T getBean(Class<T> requiredType)
    • 基于Bean的类别获取一个Bean(如果出现多个该类的实例,将会报错。但可以指定 primary=“true” 调整优先级来解决该错误 )
  • Object getBean(String name, Object... args)
    • 基于名称获取一个Bean,并覆盖默认的构造参数
  • boolean isTypeMatch(String name, Class<?> typeToMatch)
    • 指定Bean与指定Class 是否匹配

以上方法中重点要关注getBean,当用户调用getBean的时候就会触发 Bean的创建动作,其是如何创建的呢?

  • 演示基本BeanFactory获取一个Bean
#创建Bean堆栈
// 其反射实例化Bean
java.lang.reflect.Constructor.newInstance(Unknown Source:-1)
BeanUtils.instantiateClass()
//基于实例化策略 实例化Bean
SimpleInstantiationStrategy.instantiate()
AbstractAutowireCapableBeanFactory.instantiateBean()
// 执行Bean的实例化方法
AbstractAutowireCapableBeanFactory.createBeanInstance()
AbstractAutowireCapableBeanFactory.doCreateBean()
// 执行Bean的创建
AbstractAutowireCapableBeanFactory.createBean()
// 缓存中没有,调用指定Bean工厂创建Bean
AbstractBeanFactory$1.getObject()
// 从单例注册中心获取Bean缓存
DefaultSingletonBeanRegistry.getSingleton()
AbstractBeanFactory.doGetBean()
// 获取Bean
AbstractBeanFactory.getBean()
// 调用的客户类
com.tuling.spring.BeanFactoryExample.main()

Bean创建时序图:

image.png

从调用过程可以总结出以下几点:

  1. 调用BeanFactory.getBean() 会触发Bean的实例化。
  2. DefaultSingletonBeanRegistry 中缓存了单例Bean
  3. Bean的创建与初始化是由AbstractAutowireCapableBeanFactory 完成的。

3、BeanFactory 与 ApplicationContext区别

BeanFactory 看下去可以去做IOC当中的大部分事情,为什么还要去定义一个ApplicationContext 呢?
ApplicationContext 结构图


image.png

从图中可以看到 ApplicationContext 它由BeanFactory接口派生而来,因而提供了BeanFactory所有的功能。除此之外context包还提供了以下的功能:

  1. MessageSource, 提供国际化的消息访问
  2. 资源访问,如URL和文件
  3. 事件传播,实现了ApplicationListener接口的bean
  4. 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
特别感谢:

图灵学院

相关文章

网友评论

      本文标题:Spring深入 2.IOC设计原理与实现

      本文链接:https://www.haomeiwen.com/subject/urgzoctx.html