文章目录
Spring框架的IoC容器
Spring
框架的IoC
容器是
Spring
框架的核心
是Spring
框架实现控制反转功能的容器
IoC
容器负责创建
并装配
需要注入到容器中实现控制反转
的对象IoC
容器还负责管理 容器中的对象 的整个生命周期,被IoC
管理的对象通常被称为Bean
IoC
容器对应于Spring
框架的BeanFactory
接口,描述了管理对象的工厂BeanFactory
接口中定义了从容器中获取对象的方法- 而通常
IoC
的容器对象是BeanFactory
的子接口ApplicationContext
的实例对象,以此作为Bean
容器ApplicationContext
接口继承了其父接口BeanFactory
的所有功能ApplicationContext
接口还提供了国际化支持、资源访问等方法
Spring
中,可使用xml
文件进行Bean
对象的配置,也可使用注解
配置- 通常
Spring
配置文件的名字为:applicationContext.xml
或beans.xml
- 通常
使用Spring的IoC容器
- 涉及的
jar
包有:org.springframework.beans.jar
org.springframework.context.jar
org.springframework.context.support.jar
org.springframework.core.jar
org.springframework.expression.jar
commons-logging.jar
用于日志输出,便于调试,并非Spring
框架中的依赖jar
包
ApplicationContext
接口的常用实现类FileSystemXmlApplicationContext
- 该类通过
xml
配置文件的完整物理路径创建IoC
容器
- 该类通过
ClassPathXmlApplicationContext
- 该类通过从
类路径
下的xml
配置文件创建IoC
容器
- 该类通过从
WebXmlApplicationContext
- 该类适用于
Web
应用程序中,可以配合Servlet
容器进行工作,通过在Web
根目录下的xml
配置文件创建IoC
容器
- 该类适用于
xml配置
配置文件主要配置需要在
IoC
容器中进行控制反转的Java Bean
对象
通常需给出以下信息:类名
bean
的作用范围(单例
或原型
)
bean
的依赖关系
xml
配置文件的根元素是<beans>
根元素配置如下;<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> </beans>
<bean>
元素是根元素<beans>
的子元素id
属性:用来唯一标识一个bean
name
属性:定义bean
的别名,可以使用空格
或分号
隔开的多个别名class
属性:必须指定的属性,指定用来创建bean
对象的完全限定类名Spring
容器默认使用类的无参构造函数创建对象,且默认是使用单例的- 即:放入容器的对象必须要有一个无参的构造函数,或者完全没有构造函数
<bean>
元素配置如下;
<bean id="productService" class="com.Spring.demo.service.ProductServiceImpl"/></bean>
- 即:放入容器的对象必须要有一个无参的构造函数,或者完全没有构造函数
使用IoC
容器
- 创建
IoC
容器- 通过从
类路径
下的xml
配置文件创建IoC
容器
示例如下;ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
- 通过
xml
配置文件的完整物理路径创建IoC
容器
示例如下;ApplicationContext context = new FileSystemXmlApplicationContext("D:\\文档资料夹\\文件夹\\idea_ws\\Spring_demo\\src\\ApplicationContext.xml");
- 通过从
- 从
IoC
容器中得到bean
- 通过
bean
的id
或name
获得
示例如下;ProductService service = (ProductService) context.getBean("productService");
- 通过
bean
实现的接口类型获得Spring
中通过面向接口编程实现分层解耦- 先定义接口,规范接口中要实现的功能和方法
- 再创建接口的具体实现类
示例如下;
ProductService productService = context.getBean(ProductService.class);
- 通过
bean
的name
和接口类型获得
示例如下;ProductService productService = context.getBean("productService",ProductService.class);
- 通过
- 关闭
IoC
容器- 通过
ApplicationContext
接口的实现类的close()
方法关闭
示例如下;
- 通过
((ClassPathXmlApplicationContext)context).close();
Bean的配置
bean
对象的创建、销毁等都可交由IoC
容器管理
scope
属性:用来配置bean
的作用范围
scope="singleton"
:单例模式
的bean
默认情况下 在容器创建时被实例化
,并被缓存下来scope
的默认值为singleton
- 被缓存下来的
bean
对象在后续所有请求到来时被IoC
容器返回 - 可以在
<bean>
元素中配置lazy-init="true"
实现延迟初始化- 默认的
lazy-init
属性为false
,即:非延迟初始化(容器创建时被实例化
)延迟初始化
: 当第一次需要获取bean
对象时实例化- 对所有
bean
对象进行延迟初始化,可以在根元素<beans>
元素中配置default-lazy-init="true"
来实现
- 默认的
scope="prASototype"
:原型模式
的bean
对象每次从容器中获取时都返回的是另外一个重新实例化的对象
给bean
注入值
- 构造函数注入
- 使用时的条件是注入的
bean
对象有定义对应的构造器 - 构造函数注入的方式:
- 使用构造函数中的形参名注入:
- 使用
<constructor-arg>
元素进行构造函数中的形参名注入 - 在
<constructor-arg>
元素中使用name
属性指定形参名 - 注入形参值的方式:
- 使用
<constructor-arg>
元素的value
属性进行形参值的注入 - 也可以使用
<constructor-arg>
元素的子元素<value>
进行形参值的注入 - 虽然可以有两种注入方式,但此两种注入方式
不可同时使用
- 使用
- 对象引用注入:
- 若构造函数的形参中含有自定义类型,即:传递的是一个对象的引用
- 可以使用
<constructor-arg>
元素的ref
属性进行对象引用的注入ref
属性值为对应的bean
对象的id
属性值
- 使用
<constructor-arg>
元素的子元素<ref>
进行注入bean
对象的引用<ref>
元素的bean
属性值为对应的bean
对象的id
属性值
- 与上相同,
<ref>
元素与ref
属性不可同时存在
示例如下:
- 可以使用
- 若构造函数的形参中含有自定义类型,即:传递的是一个对象的引用
- 使用
<bean id="productService" class="com.Spring.demo.service.ProductServiceImpl" lazy-init="false"> <constructor-arg name="id" value="25"/> <constructor-arg name="value"> <value>Rv</value> </constructor-arg> <constructor-arg name="productDao"> <ref bean="productDao"></ref> </constructor-arg> </bean> <bean id="productDao" class="com.Spring.demo.dao.ProductDaoIml"></bean>
- 使用构造函数中的索引下标注入:
示例如下:
<bean id="productService" class="com.Spring.demo.service.ProductServiceImpl" lazy-init="false"> <constructor-arg index="0" value="25"/> <constructor-arg index="1" value="Rv"/> <constructor-arg index="2"> <ref bean="productDao"/> </constructor-arg> </bean> <bean id="productDao" class="com.Spring.demo.dao.ProductDaoIml"></bean>
- 使用构造函数中的形参名注入:
- 使用时的条件是注入的
- 属性注入(
setter
方法注入)- 使用
<bean>
元素的子元素<property>
进行属性注入 - 使用
<property>
元素的name
属性指定注入属性的属性名 - 属性值的注入与构造函数中形参值的注入时相同
- 属性值的注入既可以通过
<property>
元素的子元素<value>
注入 - 也可以通过
<property>
元素的value
属性注入 - 但
<property>
元素的子元素<value>
与value
属性不可同时用于同一个<property>
元素 - 当属性为一个自定义类的对象时,可使用
ref
属性或<ref>
子元素 - 当需要给一个属性对象的引用值设为
null
值时- 可以使用
<property>
元素的子元素<null/>
进行注入
示例如下:
- 可以使用
<bean id="productService" class="com.Spring.demo.service.ProductServiceImpl" lazy-init="false"> <property name="id" value="25"/> <property name="value"> <value>98984984</value> </property> <property name="productDao" ref="productDao"/> <property name="productDao1"> <ref bean="productDao"/> </property> </bean>
- 属性值的注入既可以通过
- 注入集合对象
Set
类型
- 可以在
<property>
元素的子元素<set>
中定义 - 在
<set>
元素中使用其子元素<value>
定义集合中的每一个元素的值
示例如下:
<property name="userlist"> <set> <value>张三</value> <value>李四</value> </set> </property>
List
类型
- 可以在
<property>
元素的子元素<list>
中定义 - 与
set
类型相同,使用<list>
元素的子元素<value>
定义集合元素
示例如下:
<property name="products"> <list> <value>手机</value> <value>路由器</value> </list> </property>
Map
类型
- 可以在
<property>
元素的子元素<map>
中定义 - 可以使用
<map>
元素的子元素<entry>
定义Map
集合中的键值对元素 - 使用
<entry>
元素的key
属性指定Map
集合键值对元素的键
- 使用
<entry>
元素的value
属性指定Map
集合键值对元素的值
示例如下:
<property name="users"> <map> <entry key="zhangsan" value="ID00001"/> <entry key="lisi" value="ID00002"/> </map> </property>
- 其他键值对集合
- 使用
<props>
元素也可以定义键值对集合 - 使用
<props>
元素的子元素<prop>
元素定义键值对集合的键值对元素 - 在
<prop>
元素的key
属性上定义键值对元素的键
- 在
<prop>
元素里面就可以定义键值对元素的值
示例如下:
<property name="user"> <props> <prop key="zhangsan">ID00001</prop> <prop key="lisi">ID00001</prop> </props> </property>
- 使用
- 注入数组对象
- 在
<property>
元素下使用其子元素<array>
定义要注入的数组 - 在
<array>
元素中使用其子元素<value>
定义数组中的元素
示例如下:<property name="id"> <array> <value>01</value> <value>02</value> </array> </property>
- 在
- 使用
依赖注入(DI
)
- 方式一:引用已定义的
bean
- 在
构造器注入
和属性注入
中注入bean
对象就是引用的已定义的bean
对象
- 在
- 方式二:使用内部
bean
- 使用嵌套的
<bean>
元素进行注入 - 嵌套的
<bean>
元素注入的bean
对象仅适用于当前注入的属性 - 其他的属性无法引用已经嵌套的
<bean>
元素注入的bean
对象- 因为嵌套的
<bean>
元素注入的bean
对象并没有id
属性 - 若其他地方在已有嵌套同一个
bean
对象时,再使用引用注入,则该对象并非单例
示例如下:
<constructor-arg name="productDao"> <bean class="com.Spring.demo.dao.ProductDaoIml"/> </constructor-arg>
- 因为嵌套的
- 使用嵌套的
bean
的生命周期
- 通过实现接口完成
bean
对象的生命周期
- 初始化方法
- 实现
InitializingBean
接口 InitializingBean
接口中定义了afterPropertiesSet()
方法afterPropertiesSet()
方法在设置了所有属性后自动调用
- 实现
- 销毁方法
- 实现
DisposableBean
接口 DisposableBean
接口中定义了destroy()
方法destroy()
方法在关闭IoC
容器时自动调用
示例如下:
- 实现
package com.Spring.demo.dao;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.sql.DataSource;
public class BaseDao implements InitializingBean, DisposableBean {
private DataSource dataSource;
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* InitializingBean 接口中定义的初始化方法
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
······
}
/**
* DisposableBean 接口中定义的销毁方法
* @throws Exception
*/
@Override
public void destroy() throws Exception {
······
}
}
- 通过xml配置文件指定
- 使用xml配置文件中的
<bean>
元素的init-method
属性指定初始化方法 - 使用xml配置文件中的
<bean>
元素的destroy-method
属性指定销毁方法 - 在使用
init-method
和destroy-method
属性时,属性值应该是bean
对象当中的方法名
示例如下:
<bean id="productService" class="com.Spring.demo.service.ProductServiceImpl" init-method="initMethod" destroy-method="destroyMethod" lazy-init="false">
<property name="productDao" ref="productDao"/>
</bean>
- 如果
bean
对象不是单例
的,即是原型
的- 初始化方法在
bean
对象每次被获取时执行,销毁方法不执行,bean
对象的销毁由JVM
进行垃圾回收,不由IoC
容器管理 - 也就是说只有在
bean
对象是单例的时候销毁方法才被执行
- 初始化方法在
- 如果既实现了
InitializingBean
接口,又使用了init-method
属性,则优先执行afterPropertiesSet()
方法,再调用init-method
属性指定的方法 - 如果既实现了
DisposableBean
接口,又使用了destroy-method
属性,则优先执行destroy()
方法,再调用destroy-method
属性指定的方法
自动装配
- 使用
<bean>
元素的autowire
属性指定自动装配模式 autowire
属性值有:byName
、byType
byName
byType
通过 bean
对象名字自动装配通过 bean
对象类型自动装配- 根据
setter
方法进行自动装配IoC
容器根据setter
方法后面的名称将首字母小写在容器中找对应id
值的bean
对象进行自动装配- 由于自动装配根据的是
bean
对象对应的<bean>
元素的id
属性值,所以id
属性值必须是唯一的 IoC
容器根据setter
方法的形参类型在IoC
容器中找对应的bean
对象进行自动装配- 若
IoC
容器中存在多个相同类型的bean
对象,则IoC
容器报错不能唯一确定注入的对象
示例如下:
<bean id="productService" class="com.Spring.demo.service.ProductServiceImpl" autowire="byName" lazy-init="false">
<property name="id" value="25"/>
<property name="value" value="98984984"/>
</bean>
IoC
容器管理数据源
- 导入与数据源相关的
jar
包,例如:commons-dbcp-1.4.jar、commons-pool-1.6.jar
以及数据库的驱动jar
包 - 在
Spring
的配置文件applicationContext.xml
中使用<beans>
根元素的子元素<bean>
元素注入数据源到IoC
容器,交由IoC
容器管理 - 数据源
bean
对象的id
属性可设为DataSource
- 数据源对象使用
commons-dbcp.jar
中的BasicDataSource
的实例对象 - 由于数据源交由
IoC
容器管理,故此在关闭IoC
容器时就要先关闭数据源- 使用
<bean>
元素的destroy-method
属性指定关闭数据源的方法为close
- 使用
- 使用属性注入的方式对数据源的各种属性进行配置注入
属性 说明 driverClassName
数据库驱动类类名 url
数据库连接地址 username
数据库的登录用户名 password
数据库的登录密码 maxActive
最大连接数 maxIdle
最大空闲连接数 maxWait
最大等待时间 initialSize
初始连接数 defaultAutoCommit
是否自动提交事务 - 在使用属性注入数据源的属性配置时,可使用属性配置文件的方式
- 在使用属性配置文件时,需要先引入
context
的命名空间
命名空间的引用示例:<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
- 使用
<context:property-placeholder>
元素引入属性占位符<context:property-placeholder>
元素的location
属性指定属性配文件的位置- 使用
classpath:
表示类路径 - 使用
classpath*:
表示类路径以及类路径下的子路径
- 使用
<context:property-placeholder>
元素的ignore-unresolvable
属性表示不可解析的属性是否被忽略
- 实质上是创建了一个
bean
对象,在其他bean
对象被属性注入前校验有无${···}
表达式,若有则进行替换
.properties
属性配置文件中以键值对的形式存储属性以及属性值- 在xml文件中使用
${key}
获取属性配置文件中key
对应的值,然后赋给value
属性
- 在使用属性配置文件时,需要先引入
- 将数据源注入到需要连接数据库的
bean
对象中
示例如下:
Spring
配置文件applicationContext.xml
:
<context:property-placeholder location="classpath:jdbc.properties" ignore-unresolvable="true"/>
<bean id="DataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="maxActive" value="10"/>
<property name="maxIdle" value="2"/>
<property name="maxWait" value="4000"/>
<property name="initialSize" value="1"/>
<property name="defaultAutoCommit" value="false"/>
</bean>
<bean id="productDao" class="com.Spring.demo.dao.ProductDaoIml">
<property name="dataSource" ref="DataSource"/>
</bean>
属性配置文件db.properties
:
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://127.0.0.1:3306/store?useSSL=false
在Web应用中使用Spring
Web
应用程序的IoC
容器是WebApplicationContext
接口的实例对象
Spring
启动时在/WEB/INF
下的web.xml
中加载Spring
的监听器并通过监听器加载Spring
的配置文件创建IoC
容器Spring
监听器的配置- 由于
Spring
的监听器类在org.springframework.web.jar
定义,所以需先导入该jar
包 - 在
web.xml
中的根元素<web-app>
下配置<listener>
元素用以配置监听器类 - 监听器类包含在
<listener-class>
元素中,而<listener-class>
元素是<listener>
的子元素 Spring
的监听器通过加载解析Spring
的配置文件来创建IoC
容器,故而需使用<context-param>
元素指定Spring
的配置文件位置<context-param>
元素的子元素<param-name>
标识上下文参数的名字。即该参数名表示Spring
的配置文件的加载路径<context-param>
元素的子元素<param-value>
包含了Spring
配置文件的具体路径- 路径中可使用
classpath:
和classpath*:
来表示表达式 含义 classpath:
表示当前类路径下 classpath*:
表示当前类路径下以及类路径的子路径 - 如果
Spring
的配置文件位于WEB-INF
目录下,则示例如下:
<param-value>/WEB-INF/spring-config.xml</param-value>
示例如下:
- 路径中可使用
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-config.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
- 由于
Spring
的监听器会创建WebApplicationContext
接口的实例对象并保存在ServletContext
中- 获取
IoC
容器- 可使用
WebApplicationContextUtils
工具类的getWebApplicationContext(..)
方法获取Spring
的IoC
容器
示例如下:
package com.Spring.web.servlet; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import javax.servlet.http.HttpServlet; public class BaseServlet extends HttpServlet { public <T> T getService(String ServiceName,Class<T> ServiceType){ WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(super.getServletContext()); return context.getBean(ServiceName,ServiceType); } }
- 可使用