IoC—Inversion of Control,即控制反转

IoC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。

理解IoC的关键:“谁控制谁,控制什么,为何是反转,哪些方面反转了”:

谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由IoC容器来控制对象的创建;

谁控制谁?IoC 容器控制对象;

控制什么?控制外部资源获取。

为何是反转,哪些方面反转了:传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象;而IoC则是由容器来帮忙创建及注入依赖对象;

为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;

哪些方面反转了?依赖对象的获取被反转了。

IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”

DI—Dependency Injection,即“依赖注入”

是组件之间依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,而不需要关心具体的资源来自何处,由谁实现。

理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”:

谁依赖于谁:应用程序依赖于IoC容器;Bean依赖IoC容器;依赖指的是Bean之间的依赖关系

为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;Bean需要IoC容器来创建

谁注入谁:IoC容器注入应用程序某个对象,应用程序依赖的对象;

●注入了什么:注入某个对象所需要的外部资源(包括对象、资源、常量数据)。

Spring IoC容器如何知道哪些是它管理的对象呢?

Spring IoC容器通过读取配置文件中的配置元数据(BeanDefinition),通过元数据对应用中的各个对象进行实例化及装配。

Spring与配置文件完全解耦,可以使用任何可能的方式进行配置元数据,比如注解、基于xml的、基于java文件的、基于属性文件的配置。

由IoC容器管理的那些组成应用程序的对象我们就叫它Bean。

在Spring中BeanFactory是IoC容器的实际代表者。ApplicationContext 接口继承了BeanFactory。简单说, BeanFactory提供了IoC容器最基本功能,而 ApplicationContext 则增加了更多支持企业级功能支持。

public static void main(String[] args) {
// 1、读取配置文件实例化一个IoC容器
ApplicationContext context = new ClassPathXmlApplicationContext("hello.xml");
// 2、从容器中获取Bean,注意此处完全“面向接口编程,而不是面向实现”
HelloApi helloApi = context.getBean("hello", HelloApi.class);
// 3、执行业务逻辑
helloApi.sayHello();
}

Bean?

本质就是一个POJO类,但具有以下限制:

  • 该类必须要有公共的无参构造器
  • 属性为private访问级别,不建议public,如private String message
  • 属性必要时通过一组setter和getter方法来访问

作用域

Spring 框架支持以下五个作用域,分别为singleton、prototype、request、session和global session。

作用域 描述
singleton Spring会缓存单例对象,在IoC容器仅存在一个Bean实例,默认值
prototype Spring不会缓存原型对象,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()
request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
session 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境
global-session 一般用于Portlet应用环境,该运用域仅适用于WebApplicationContext环境
<bean id="..." class="..." scope="singleton"></bean>

自定义作用域:org.springframework.beans.factory.config.Scope

生命周期

Bean的生命周期可以表达为:Bean的定义——Bean的初始化——Bean的使用——Bean的销毁

初始化回调

一、org.springframework.beans.factory.InitializingBean 接口指定一个单一的方法:

void afterPropertiesSet() throws Exception;

二、配置元数据,使用 init-method 属性来指定带有 void 无参数方法的名称:

<bean id="exampleBean" class="examples.ExampleBean" init-method="init"/>

销毁回调

一、org.springframework.beans.factory.DisposableBean 接口指定一个单一的方法:

void destroy() throws Exception;

二、配置元数据,你使用 destroy-method 属性来指定带有 void 无参数方法的名称:

<bean id="exampleBean" class="examples.ExampleBean" destroy-method="destroy"/>

后置处理器

允许在调用初始化方法前后对 Bean 进行额外的处理。

是一个监听器,它可以监听容器触发的事件。将它向IoC容器注册后,容器中管理的Bean具备了接收IoC容器事件回调的能力。

在populateBean之后的initializeBean中被调用。在Bean的初始化之前提供postProcessBeforeInitialization回调入口。在Bean的初始化之后提供postProcessAfterInitialization回调入口。

public class InitBean implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeforeInitialization : " + beanName);
return bean; // you can return any other object as well
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("AfterInitialization : " + beanName);
return bean; // you can return any other object as well
}
}

Bean自身的方法:如调用 Bean 构造函数实例化 Bean,调用 Setter 设置 Bean 的属性值以及通过的 init-method 和 destroy-method 所指定的方法;

Bean级生命周期接口方法:如 BeanNameAware、 BeanFactoryAware、 InitializingBean 和 DisposableBean,这些接口方法由 Bean 类直接实现;

容器级生命周期接口方法:在上图中带“★” 的步骤是由 InstantiationAwareBean PostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“ 后处理器” 。 后处理器接口一般不由 Bean 本身实现,它们独立于 Bean,实现类以容器附加装置的形式注册到 Spring 容器中并通过接口反射为 Spring 容器预先识别。当Spring 容器创建任何 Bean 的时候,这些后处理器都会发生作用,所以这些后处理器的影响是全局性的。当然,用户可以通过合理地编写后处理器,让其仅对感兴趣Bean 进行加工处理

Spring IoC容器如何实例化Bean呢?

IoC容器需要根据Bean定义里的配置元数据使用反射机制来创建Bean。

一、使用构造器实例化Bean

指定必须的class属性

<bean id="hello" class="hello.HelloApiImpl"></bean>

二、使用静态工厂方式实例化Bean

指定必须的class属性

指定factory-method属性来指定实例化Bean的方法

<bean id="hello" class="hello.HelloApiStaticFactory" factory-method="newInstance"></bean>

三、使用实例工厂方法实例化Bean

不能指定class属性

使用factory-bean属性指定工厂Bean

使用factory-method属性指定实例化Bean的方法

<!—定义实例工厂Bean -->
<bean id="beanInstanceFactory" class="hello.HelloApiInstanceFactory"/>
<!—使用实例工厂Bean创建Bean -->
<bean id="hello" factory-bean="beanInstanceFactory" factory-method="newInstance"></bean>

Spring IoC容器如何注入Bean的依赖资源?

在基于构造函数注入中,我们使用的是〈bean〉标签中的〈constructor-arg〉元素;

而在基于设值函数的注入中,我们使用的是〈bean〉标签中的〈property〉元素。

构造器注入:

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

  • 根据参数索引注入
<constructor-arg index="0" value="Hello World!"/>

构造函数的参数在 bean 定义中的顺序就是把这些参数提供给适当的构造函数的顺序。

最好的传递构造函数参数的方式,是使用 index 属性来显式的指定构造函数参数的索引。

  • 根据参数类型注入
<constructor-arg type="java.lang.String" value="Hello World!"/>
  • 根据参数名注入:在构造器上使用@ConstructorProperties注解来指定参数名。只对构造器实例化Bean方式起作用,而对工厂不起作用。
<constructor-arg name="message" value="Hello World!"/>

setter注入

实例化Bean后,通过调用Bean类的setter方法进行注入依赖;

  • 注入常量:
<property name="message" value="Hello World!"/>
<property name="message"><value>Hello World!</value></property>
  • 注入Bean ID:
<property name="id"><idref bean="bean1"/></property>
  • 注入集合(Collection、Set、List):
<property name="values">
<list value-type="可选" merge="可选">
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
<property name="values"><set value-type="同上">...</set></property>
  • 注入数组:

一维:

<property name="id">
<array>...</array>
</property>

二维:

<property name="id">
<array>
<array>...</array>
<array>...</array>
</array>
</property>
  • 注入字典:
<property name="id">
<map>
<entry key="" value=""/>
<entry key="" value=""/>
</map>
</property>
  • 注入Properties:
<property name="id">
<props value-type="无用,就是String">
<prop key="">value</prop>
<prop key="">value</prop>
</map>
</property>
  • 注入依赖Bean:

如果你想要向一个对象传递一个引用,你需要使用标签的 ref 属性,如果你想要直接传递值,那么你应该使用如上所示的 value 属性。

一般:

<constructor-arg index="0" ref="bean1"/>
<property name="helloApi" ref="bean1"/>

高级:

<ref local=""/>
<ref parent=""/>
<!-- sources/chapter3/parentBeanInject.xml表示父容器配置-->
<!--注意此处可能子容器也定义一个该Bean-->
<bean id="helloApi" class="cn.HelloImpl4">
<property name="message" value="Hello Parent!"/>
</bean> <!-- sources/chapter3/localBeanInject.xml表示当前容器配置-->
<!-- 注意父容器中也定义了id 为 helloApi的Bean -->
<bean id="helloApi" class="cn.HelloImpl4">
<property name="message" value="Hello Local!"/>
</bean>
<!-- 通过local注入 -->
<bean id="bean1" class="cn.bean.HelloApiDecorator">
<constructor-arg index="0"><ref local="helloApi"/></constructor-arg>
</bean>
<!-- 通过parent注入 -->
<bean id="bean2" class="cn.bean.HelloApiDecorator">
<property name="helloApi"><ref parent="helloApi"/></property>
</bean>
  • 注入内部Bean:
<bean id="bean" class="cn.bean.HelloApiDecorator">
<property name="helloApi">
<bean id="即便指定也没有用,是匿名的,对外部不可见" class="cn.hello.HelloImpl"/>
</property>
</bean>
  • 处理null值:
<property name=""><null/></property>

Spring Bean自动装配?(不建议用

在 XML 配置文件中 beans 的 auto-wire 属性设置为 byName。然后,它尝试将它的属性与配置文件中定义为相同名称的 beans 进行匹配和连接。

在 XML 配置文件中 beans 的 autowire 属性设置为 byType。然后,如果它的 type 恰好与配置文件中 beans 名称中的一个相匹配,它将尝试匹配和连接它的属性。

在 XML 配置文件中 beans 的 autowire 属性设置为 constructor。然后,它尝试把它的构造函数的参数与配置文件中 beans 名称中的一个进行匹配和连线。

spring(四):IoC的更多相关文章

  1. Spring框架系列(四)--IOC控制反转和DI依赖注入

    背景: 如果对象的引用或者依赖关系的管理由具体对象完成,代码的耦合性就会很高,代码测试也变得困难.而IOC可以很好的解决这个问题,把这 些依赖关系交给框架或者IOC容器进行管理,简化了开发. IOC是 ...

  2. spring四种依赖注入方式

    一.Set注入 这是最简单的注入方式,假设有一个SpringAction,类中需要实例化一个SpringDao对象,那么就可以定义一个private的SpringDao成员变量,然后创建SpringD ...

  3. Spring总结—— IOC 和 Bean 的总结

    一.Spring 官方文档中给出的 Spring 的整体结构. 二.我自己所理解的 Spring 整体结构图. 三.本次总结 Spring 核心部分 1.从上面图中可以看出,Beans 和 Conte ...

  4. spring容器IOC创建对象<二>

    问题?spring是如何创建对象的?什么时候创建对象?有几种创建方式?测试对象是单例的还是多例的 ?对象的初始化和销毁? 下面的四大模块IOC的内容了!需要深刻理解 SpringIOC定义:把对象的创 ...

  5. Spring的IoC应用

    IoC(Inversion of Control,控制反转) Spring的IoC应用是其框架的最大的特点,通过依赖注入可以大大降低代码之间的耦合度,从而实现代码和功能之间的分离.在代码中可以不直接和 ...

  6. Spring的IOC

    引用:http://www.cnblogs.com/xdp-gacl/p/4249939.html 学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念 ...

  7. Spring的IOC原理[通俗解释一下]

    Spring的IOC原理[通俗解释一下] 1. IoC理论的背景我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 图 ...

  8. Spring的IOC容器第一辑

    一.Spring的IOC容器概述 Spring的IOC的过程也被称为依赖注入(DI),那么对象可以通过构造函数参数,工厂方法的参数或在工厂方法构造或返回的对象实例上设置的属性来定义它们的依赖关系,然后 ...

  9. (转)java之Spring(IOC)注解装配Bean详解

    java之Spring(IOC)注解装配Bean详解   在这里我们要详细说明一下利用Annotation-注解来装配Bean. 因为如果你学会了注解,你就再也不愿意去手动配置xml文件了,下面就看看 ...

  10. 【死磕 Spring】----- IOC 之解析 bean 标签:开启解析进程

    原文出自:http://cmsblogs.com import 标签解析完毕了,再看 Spring 中最复杂也是最重要的标签 bean 标签的解析过程. 在方法 parseDefaultElement ...

随机推荐

  1. C#浅拷贝与深拷贝测试

    1.浅拷贝与深拷贝 浅拷贝:只复制对象的基本类型,对象类型,仍属于原来的引用.       深拷贝:不紧复制对象的基本类,同时也复制原对象中的对象.就是说完全是新对象产生的. 2.浅拷贝与深拷贝的区别 ...

  2. Java安全笔记

    前言 后端接口开发中,涉及到用户私密信息(用户名.密码)等,我们不能传输明文,必须使用加密方式传输.这次政府项目中,安全测试组提出了明文传输漏洞,抽空研究了下Java加解密相关知识,记录下. 散列函数 ...

  3. C语言递归之二叉树的最小深度

    题目描述 给定一个二叉树,找出其最小深度. 最小深度是从根节点到最近叶子节点的最短路径上的节点数量. 说明: 叶子节点是指没有子节点的节点. 示例 输入:[3,9,20,null,null,15,7] ...

  4. Java(三)String类

    一.String类初始化方法 1.初始化一个空字符串 String str=new String();//这里调用了String的无参构造方法 2.初始化一个有值的字符串 String str1=&q ...

  5. jenkins自动化部署(tomcat+git)

    一.安装jenkins 1.安装jdk 查看可安装版本:yum search openjdk 安装:yum install -y java-1.8.0-openjdk java-1.8.0-openj ...

  6. npm常用模块之mkdirp使用

    更多npm常用模块使用请访问:npm常用模块汇总 mkdirp这是一款在node.js中像mkdir -p一样递归创建目录及其子目录. 更多使用文档请点击访问mkdirp工具官网. 安装 一键安装不多 ...

  7. POJ-3984-迷宫问题(bfs+记录路径)

    定义一个二维数组: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, ...

  8. Java中基本数据类型byte的溢出问题

    Java中基本数据类型byte的溢出问题 问题源于:https://www.cnblogs.com/HuoHua2020/p/12326631.html 定义两个byte类型的数据,将其之和赋值给一个 ...

  9. 题解【洛谷P2264】情书

    题面 看到每一单词在同一句话中出现多次感动值不叠加,一眼想到 \(\text{set}\). 首先将词汇列表中的单词存储起来,我用的是 \(\text{set}\). 对于每一个句子的单词,我们可以先 ...

  10. [P5555] 秩序魔咒 - 回文自动机,DFS

    #include <bits/stdc++.h> #define Sigma 30 #define MAXN 500010 #define int long long using name ...