spring- IOC

spring- IOC: 管理Bean 的生命周期,以及依赖注入。
一、 IOC 核心知识点

  • IOC概要

  • 实体Bean 的创建

  • Bean的基本特性

  • 依赖注入

    1. IOC 概要:
      java中,对象A 调用对象B 的几种方法:
      spring- IOC_第1张图片
      上表可以看到, 引用一个对象可以在不同地点(其它引用者)、不同时间由不同的方法完成。如果B只是一个非常简单的对象 如直接new B(),怎样都不会觉得复杂,比如你从来不会觉得创建一个String 是一个件复杂的事情。但如果B 是一个有着复杂依赖的Service对象,这时在不同时机引用B将会变得很复杂。
      spring- IOC_第2张图片
      IOC容器的出现正是为解决这一问题,其可以将对象的构建方式统一,并且自动维护对象的依赖关系,从而降低系统的实现成本。前提是需要提前对目标对象基于XML进行声明。

    2. 实体Bean 的创建

      a. 基于class创建
      b. 构造方法创建
      c. 静态工厂方法创建
      d. FactoryBean创建

a . 基于 class创建:



b. 基于构造方法创建


   
     
 

name:构造方法参数变量名称
type:参数类型index:参数索引,从0开始
value:参数值,spring 会自动转换成参数实际类型值
ref:引用容串的其它对象

c. 静态工厂方法创建


          
  

d. FactoryBean 创建:
指定一个Bean工厂来创建实际的Bean


   
   

 public class DriverFactoryBean implements FactoryBean {
       private String jdbcUrl;
       public Object getObject() throws Exception {
            return DriverManager.getDriver(jdbcUrl);
       }
       public Class getObjectType() {
             return Driver.class;
       }
       public boolean isSingleton() {
              return true;
       }
       public String getJdbcUrl() {
             return jdbcUrl;   
      }
      public void setJdbcUrl(String jdbcUrl) {
            this.jdbcUrl = jdbcUrl;  
      }
 }
  1. bean 的基本特性:
    a. 作用范围
    b. 生命周期
    c. 装载依赖

    a、作用范围:
    很多时候Bean对象是无状态的 ,而有些又是有状态的 无状态的对象我们采用单例即可,而有状态则必须是多例的模式,通过scope 即可创建scope=“prototype”scope=“singleton”

scope=“prototype



如果一个Bean设置成 prototype 我们可以 通过BeanFactoryAware 获取 BeanFactory 对象即可每次获取的都是新对像。

b. 生命周期:
Bean对象的创建、初始化、销毁即是Bean的生命周期。通过 init-method、destroy-method 属性可以分别指定期构建方法与初始方法。




c、加载机制指示Bean在何时进行加载。
设置lazy-init 即可,
其值如下:true: 懒加载,即延迟加载false:非懒加载,容器启动时即创建对象default:默认,采用default-lazy-init 中指定值,如果default-lazy-init 没指定就是false

  1. 依赖注入
    a.set方法注入
    b.构造方法注入
    c.自动注入(byName、byType)
    d.方法注入(lookup-method)

a. set方法注入:


        
 

b. 构造方法注入


     
           
    

c. 自动注入



byName:基于变量名与bean 名称相同作为依据插入
byType:基于变量类别与bean 名称作
constructor:基于IOC中bean 与构造方法进行匹配(语义模糊,不推荐)

d. 依赖方法注入(lookup-method)
当一个单例的Bean,依赖于一个多例的Bean,用常规方法只会被注入一次,如果每次都想要获取一个全新实例就可以采用lookup-method 方法来实现。

#编写一个抽像类
public abstract class MethodInject {
    public void handlerRequest() {
      // 通过对该抽像方法的调用获取最新实例
                  getFine();
   }
    # 编写一个抽像方法
   public abstract FineSpring getFine();
 }
 
 // 设定抽像方法实现
     
        
     

该操作的原理是基于动态代理技术,重新生成一个继承至目标类,然后重写抽像方法到达注入目的。前面说所单例Bean依赖多例Bean这种情况也可以通过实现 ApplicationContextAware 、BeanFactoryAware 接口来获取BeanFactory 实例,从而可以直接调用getBean方法获取新实例,推荐使用该方法,相比lookup-method语义逻辑更清楚一些

二、 IOC 设计原理及实现

		    Bean工厂是如何生产Bean的?
		     Bean的依赖关系是由谁解来决的?
		     Bean工厂和应用上文的区别?
  • Bean的构建过程
    spring.xml 文件中保存了我们对Bean的描述配置,BeanFactory 会读取这些配置然后生成对应的Bean。

  • BeanDefinition :Bean信息的承载对象,与spring 中bean是一一对应的关系。
    xml bean中设置的属性最后都会体现在BeanDefinition中。如:
    spring- IOC_第3张图片

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

  • BeandefinitionReader :读取器
    BeanDefinition 中存储了Xml Bean信息,而BeanDefinitionRegister 基于ID和name 保存了Bean的定义。从xml Bean到BeanDefinition 然后在注册至BeanDefinitionRegister 整个过程
    spring- IOC_第4张图片
    上图中可以看出Bean的定义是由BeanDefinitionReader 从xml 中读取配置并构建出BeanDefinitionReader,然后在基于别名注册到BeanDefinitionRegister中。

  • 实例演示 装载bean

/创建一个简单注册器
BeanDefinitionRegistry register = new SimpleBeanDefinitionRegistry();
//创建bean定义读取器
BeanDefinitionReader reader = new XmlBeanDefinitionReader(register);
// 创建资源读取器
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
// 获取资源
Resource xmlResource = resourceLoader.getResource("spring.xml");
// 装载Bean的定义
reader.loadBeanDefinitions(xmlResource);
// 打印构建的Bean 名称
System.out.println(Arrays.toString(register.getBeanDefinitionNames());

  • BeanFactory Bean 工厂
    有了Bean的定义就相当于有了产品的配方,接下来就是要把这个配方送到工厂进行生产了。在ioc当中Bean的构建是由BeanFactory 负责的。
    方法说明:

  • getBean(String)基于ID或name 获取一个Bean

  •  T getBean(Class requiredType) 基于Bean的类别获取一个Bean(如果出现多个该类的实例,将会报错。但可以指定primary=“true” 调整优先级来解决该错误

  • Object getBean(String name, Object… args)基于名称获取一个Bean,并覆盖默认的构造参数

  • boolean isTypeMatch(String name, Class typeToMatch)指定Bean与指定Class 是否匹配

  • 演示基本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()

spring- IOC_第5张图片
从调用过程可以总结出以下几点:
1.调用BeanFactory.getBean() 会触发Bean的实例化。
2 DefaultSingletonBeanRegistry 中缓存了单例Bean
3.Bean的创建与初始化是由AbstractAutowireCapableBeanFactory 完成的

  • BeanFactory 与 ApplicationContext区别
    spring- IOC_第6张图片
    可以看到 ApplicationContext 它由BeanFactory接口派生而来,因而提供了BeanFactory所有的功能。除此之外context包还提供了以下的功能:
    1.MessageSource, 提供国际化的消息访问
    2.资源访问,如URL和文件
    3.事件传播,实现了ApplicationListener接口的bean
    4.载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层

你可能感兴趣的:(框架)