IOC本质 #
控制反转IOC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IOC的一种方法,也有人认为DI只是IOC的另一种说法。没有IOC的程序中,我们使用面向对象编程,对象的创建于对象的依赖关系完全硬编码在程序中,对象的创建由程序控制,控制反转后将对象的创建转移给第三方,控制反转就是获得依赖对象的方式反转了。
采用XML方式配置Bean的时候,Bean的定义信息和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转时一种通过描述 (XML或注解) 并通过第三方取生产或获取特定对象的方式。在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入 (Dependency Injection,DI)
Spring容器中的Bean #
对于开发者来说,开发者使用Spring框架主要是做两件事:①开发Bean;②配置Bean。对于Spring框架来说,它要做的就是根据配置文件来创建Bean实例,并调用Bean实例的方法完成”依赖注入”——这就是所谓IoC的本质。
Bean管理 #
- Bean管理指的是两个操作
- Spring创建对象
- Spring注入属性
- Bean管理操作有两种方式
- 基于xml配置文件方式实现
- 基于注解方式实现
创建Bean的3种方式 #
使用构造器创建Bean实例 #
使用构造器来创建Bean实例是最常见的情况,如果不采用构造注入,Spring底层会调用Bean类的无参数构造器来创建实例,因此要求该Bean类提供无参数的构造器。
采用默认的构造器创建Bean实例,Spring对Bean实例的所有属性执行默认初始化,即所有的基本类型的值初始化为0或false;所有的引用类型的值初始化为null。
使用静态工厂方法创建Bean #
使用静态工厂方法创建Bean实例时,class属性也必须指定,但此时class属性并不是指定Bean实例的实现类,而是静态工厂类,Spring通过该属性知道由哪个工厂类来创建Bean实例。
除此之外,还需要使用factory-method属性来指定静态工厂方法,Spring将调用静态工厂方法返回一个Bean实例,一旦获得了指定Bean实例,Spring后面的处理步骤与采用普通方法创建Bean实例完全一样。如果静态工厂方法需要参数,则使用<constructor-arg.../>
元素指定静态工厂方法的参数。
调用实例工厂方法创建Bean #
实例工厂方法与静态工厂方法只有一个不同:调用静态工厂方法只需使用工厂类即可,而调用实例工厂方法则需要工厂实例。使用实例工厂方法时,配置Bean实例的<bean.../>
元素无须class属性,配置实例工厂方法使用factory-bean
指定工厂实例。
采用实例工厂方法创建Bean的<bean.../>
元素时需要指定如下两个属性:
- factory-bean: 该属性的值为工厂Bean的id。
- factory-method: 该属性指定实例工厂的工厂方法。
若调用实例工厂方法时需要传入参数,则使用<constructor-arg.../>
元素确定参数值。
Bean的作用域 #
当通过Spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。Spring支持如下五种作用域:
- singleton: 单例模式,在整个Spring IoC容器中,singleton作用域的Bean将只生成一个实例。
- prototype: 每次通过容器的getBean()方法获取prototype作用域的Bean时,都将产生一个新的Bean实例。
- request: 对于一次HTTP请求,request作用域的Bean将只生成一个实例,这意味着,在同一次HTTP请求内,程序每次请求该Bean,得到的总是同一个实例。只有在Web应用中使用Spring时,该作用域才真正有效。
- session:该作用域将 bean 的定义限制为 HTTP 会话。 只在web-aware Spring ApplicationContext的上下文中有效。
- global session: 每个全局的HTTP Session对应一个Bean实例。在典型的情况下,仅在使用portlet context的时候有效,同样只在Web应用中有效。
如果不指定Bean的作用域,Spring默认使用singleton作用域。prototype作用域的Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成果,就可以重复使用。因此,应该尽量避免将Bean设置成prototype作用域。
在Spring中, 默认情况下, bean是单实例对象
- 单实例的对象会在容器启动时立即创建,并存放在
IOC
容器中,由Spring
管理 - 多实例的对象在容器启动时不会创建,在调用
getBean()
方法时创建,不会存放IOC
容器中
XML创建对象 #
注意点:创建对象时的构造器必须要存在,否则Spring获取不到,就会报错
applicationContext.xml
#
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c" 名称空间在这
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
bean: 代表一个对象
id: 对象的唯一标识
class: 对象的全类名
-->
<bean id="user1" class="xyz.zhazong710.pojo.User"></bean>
<!--
constructor-arg: 代表构造器中的一个参数
index: 在参数列表中的索引
value: 参数的值
-->
<bean id="user2" class="xyz.zhazong710.pojo.User">
<constructor-arg index="0" value="hong"></constructor-arg>
<constructor-arg index="1" value="18"></constructor-arg>
<constructor-arg index="2" value="男"></constructor-arg>
</bean>
<!--
constructor-arg: 代表构造器中的一个参数
type: 参数的类型
value: 参数的值
-->
<bean id="user3" class="xyz.zhazong710.pojo.User">
<constructor-arg type="java.lang.String" value="Tom"/>
<constructor-arg type="java.lang.Integer" value="18"/>
<constructor-arg type="java.lang.String" value="男"/>
</bean>
<!--
constructor-arg: 代表构造器中的一个参数
name: 参数名
value: 参数的值
-->
<bean id="user4" class="xyz.zhazong710.pojo.User">
<constructor-arg name="name" value="Jerry"/>
<constructor-arg name="age" value="16"/>
<constructor-arg name="sex" value="男"/>
</bean>
<!--
c:xxx=yyy 等价于
<constructor-arg name="xxx" value="yyy"/>
-->
<bean id="user5" class="xyz.zhazong710.pojo.User"
c:name="Bob"
c:age="17"
c:sex="女"></bean>
</beans>
注解创建对象 #
创建一个 applicationContext3.xml
配置文件
Spring创建对象提供的注解 #
@Component
创建组件的注解@Service
创建 service 层的注解@Controller
创建 controller 层的注解@Repository
创建 dao层的注解
使用这4个注解默认 id
为类名首字母小写,可以设置 value
属性指定 id
值
注意:这4个注解默认调用空参构造器;如果类中只有一个构造器,则调用,参数来源是 IOC
容器;如果类中即没有无参构造且有多个有参构造,则会报错。
ioc的底层原理 #
(1)xml配置文件
(2)dom4j解析xml
(3)工厂模式
(4)反射