4

Spring IoC学习总结


学习spring Ioc整理的一些笔记,很简单。分享给大家。

IoC 基本概念

在这之前,我们先记住一句话。好莱坞原则:Don't call us, we will call you.
其实这句话很恰当地形容了“反转”的意味;
Ioc, Inversion of Control,控制反转,它还有一个别名叫“依赖注入”(DI Dependency Injection)。IoC不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”

  • 谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
  • 为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

还有一个概念:DI 依赖注入。大部分认为IoC和DI只是不同的叫法而已。
理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么

  • 谁依赖于谁:当然是应用程序依赖于IoC容器;
  • 为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
  • 谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
  • 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。

Spring IoC

我理解的spring IoC分为两部分:Bean实例的创建依赖注入

Spring IoC容器如何实例化Bean呢?传统应用程序可以通过new和反射方式进行实例化Bean。而Spring IoC容器则需要根据Bean定义里的配置元数据使用反射机制来创建Bean。(大家可以了解一下Java的反射机制,这是Spring Ioc实现Bean实例化的核心机制)在Spring IoC容器中根据Bean定义创建Bean主要有以下几种方式:

  • 使用构造器实例化Bean 有参/无参
  • 使用静态工厂实例化Bean
  • 使用实例工厂实例化Bean
<!--使用默认构造参数-->  
<bean name="bean1" class="com.java.spring.Demo"/>  
    <!--使用有参数构造参数-->  
   
<bean name="bean2" class="com.java.spring.Demo">  
<!-- 指定构造器参数 -->  
    <constructor-arg index="0" value="Hello Spring!"/>  
</bean> 

<!-- 使用静态工厂方法 -->  
<bean id="bean3" class="com.java.spring.DemoStaticFactory" factory-method="newInstance">  
     <constructor-arg index="0" value="Hello Spring!"/>  
</bean>

<!--1、定义实例工厂Bean -->  
<bean id="DemoInstanceFactoryv"  
class="com.java.spring.DemoInstanceFactory"/>  
<!—2、使用实例工厂Bean创建Bean -->  
<bean id="bean4"  
factory-bean="DemoInstanceFactory"  
     factory-method="newInstance">  
 <constructor-arg index="0" value="Hello Spring!"></constructor-arg>  
</bean>

另外,静态工厂和实例工厂方法还有对应的静态工厂类和实例工厂类

/**
*   静态工厂类
*
**/
public class DemoStaticFactory {  
    //工厂方法  
       public static HelloApi newInstance(String message) {  
              //返回需要的Bean实例  
           return new Demo(message);  
}  
}  

/**
*   实例工厂类
*
**/
package com.java.spring;  
public class DemoInstanceFactory {  
public HelloApi newInstance(String message) {  
          return new Demo(message);  
   }  
} 

这一块补充一个细节。Spring什么时候实例化bean,首先要分2种情况:

  • 第一:如果你使用BeanFactory作为Spring Bean的工厂类,则所有的bean都是在第一次使用该Bean的时候实例化
  • 第二:如果你使用ApplicationContext作为Spring Bean的工厂类,则又分为以下几种情况:

       (1):如果bean的scope是singleton的,并且lazy-init为false(默认是false,所以可以不用设置),则ApplicationContext启动的时候就实例化该Bean,并且将实例化的Bean放在一个map结构的缓存中,下次再使用该Bean的时候,直接从这个缓存中取 
       (2):如果bean的scope是singleton的,并且lazy-init为true,则该Bean的实例化是在第一次使用该Bean的时候进行实例化 
       (3):如果bean的scope是prototype的,则该Bean的实例化是在第一次使用该Bean的时候进行实例化 

    通常使用ApplicationContext作为容器的。

使用@Autowire注解注入的时机则是容器刚启动的时候就开始注入;注入之前要先初始化bean;
ApplicationContext 的初始化和BeanFactory 有一个重大的区别:BeanFactory在初始化容器时,并未实例化Bean,直到第一次访问某个Bean 时才实例目标Bean;而ApplicationContext 则在初始化应用上下文时就实例化所有单实例的Bean。


了解Bean的实例化后,接下来就是Bean实例之间的关系,也就是依赖注入;
Spring IoC容器的依赖有两层含义:Bean依赖容器容器注入Bean的依赖资源

  • Bean依赖容器:也就是说Bean要依赖于容器,这里的依赖是指容器负责创建Bean并管理Bean的生命周期,正是由于由容器来控制创建Bean并注入依赖,也就是控制权被反转了,这也正是IoC名字的由来,此处的有依赖是指Bean和容器之间的依赖关系。
  • 容器注入Bean的依赖资源:容器负责注入Bean的依赖资源,依赖资源可以是Bean、外部文件、常量数据等,在Java中都反映为对象,并且由容器负责组装Bean之间的依赖关系,此处的依赖是指Bean之间的依赖关系,可以认为是传统类与类之间的“关联”、“聚合”、“组合”关系。

Spring IoC容器注入依赖资源主要有以下两种基本实现方式:

  • 构造器注入:就是容器实例化Bean时注入那些依赖,通过在在Bean定义中指定构造器参数进行注入依赖,包括实例工厂方法参数注入依赖,但静态工厂方法参数不允许注入依赖;
  • setter注入:通过setter方法进行注入依赖;

一、构造器注入:
1)常量值

<constructor-arg index="0" value="常量"/> <!--简写 -->
<constructor-arg index="0"><value>常量</value></constructor-arg><!--全写 -->

2)引用

<constructor-arg index="0" ref="引用"/><!--简写 -->
<constructor-arg index="0"><ref bean="引用"/></constructor-arg><!--全写 -->

二、setter注入:
1)常量值

<property name="message" value="常量"/><!--简写 -->
<property name="message"><value>常量</value></ property><!--全写 -->

2)引用

<property name="message" ref="引用"/><!--简写 -->
<property name="message"><ref bean="引用"/></ property><!--全写 -->

3)数组:<array>

<property name="values">  
    <array>  
        <value>1</value>  
        <value>2</value>  
        <value>3</value>  
    </array>  
</property>  

4)列表:<list>

<property name="values">  
    <list>  
        <value>1</value>  
        <value>2</value>  
        <value>3</value>  
    </list>  
</property>  

5)集合:<set>

<property name="values">  
    <set>  
        <value>1</value>  
        <value>2</value>  
        <value>3</value>  
    </set>  
</property>  

6)字典

<!--简写 -->
<map>
    <entry key="键常量" value="值常量"/>
    <entry key-ref="键引用" value-ref="值引用"/>
</map>
<!--全写 -->
<map>
    <entry><key><value>键常量</value></key><value>值常量</value></entry>
    <entry><key><ref bean="键引用"/></key><ref bean="值引用"/></entry>
</map>

7)Properties

另外,基于注解驱动的Spring Ioc的原理以及Spring IoC源码剖析相关我在在网上找到一些文章,大家也可以看一下。
Spring依赖注入的两种方式xml和注解
使用注释驱动的Ioc功能
Spring IoC源码剖析


丶木叶
112 声望5 粉丝

我始终相信比你优秀的人过着比你更努力的生活。