spring- IOC

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

  • IOC概要

  • 实体Bean 的创建

  • Bean的基本特性

  • 依赖注入

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

    2. 实体Bean 的创建

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

a . 基于 class创建:

<bean class="com.huonilaifu.spring.User"></bean>

b. 基于构造方法创建

<bean class="com.huonilaifu.spring.User">
   <constructor-arg name="name" type="java.lang.String" value="xiaoming"/>
     <constructor-arg index="1" type="java.lang.String" value="sex" />
 </bean>

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

c. 静态工厂方法创建

<bean class="com.huonilaifu.spring.User" factory-method="build">
          <constructor-arg name="type" type="java.lang.String" value="B"/>
  </bean>

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

<bean class="com.tuling.spring.DriverFactoryBean">
   <property name="jdbcUrl" value="jdbc:mysql://localhost:3306"/>
   </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 class="com.huonilaifu.spring.User" scope="prototype">
</bean>

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

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

<bean class="com.huonilaifu.spring.User" init-method="init" destroy-method="destroy">
</bean>

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方法注入:

<bean class="com.huonilaifu.spring.User">
        <property name="fine" ref="fineSpring"/>
 </bean>

b. 构造方法注入

<bean class="com.huonilfaifu.spring.User">
     <constructor-arg name="fine">
           <bean class="com.huonilaifu.spring.FineSpring"/>
    </constructor-arg>
</bean>

c. 自动注入

<bean id="userAutowireConstructor"class="com.huonilaifu.spring.User" autowire="byName">
</bean>

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 id="MethodInject" class="com.huonilaifu.spring.MethodInject">
        <lookup-method name="getFine" bean="fine"></lookup-method>
     </bean>

该操作的原理是基于动态代理技术,重新生成一个继承至目标类,然后重写抽像方法到达注入目的。前面说所单例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中。如:
    在这里插入图片描述

  • 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 整个过程
    在这里插入图片描述
    上图中可以看出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()

在这里插入图片描述
从调用过程可以总结出以下几点:
1.调用BeanFactory.getBean() 会触发Bean的实例化。
2 DefaultSingletonBeanRegistry 中缓存了单例Bean
3.Bean的创建与初始化是由AbstractAutowireCapableBeanFactory 完成的

  • BeanFactory 与 ApplicationContext区别
    在这里插入图片描述
    可以看到 ApplicationContext 它由BeanFactory接口派生而来,因而提供了BeanFactory所有的功能。除此之外context包还提供了以下的功能:
    1.MessageSource, 提供国际化的消息访问
    2.资源访问,如URL和文件
    3.事件传播,实现了ApplicationListener接口的bean
    4.载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值