Spring IoC
[TOC]
Spring 介绍
框架的作用
Spring 是什么?
Spring 体系结构
Spring 发展历史
Spring 优势
- 方便解耦,简化开发
- 方便集成各种优秀框架
- 方便程序的测试
- AOP 编程的支持
- 声明式事务的支持
- 降低 JavaEE API 的使用难度
- Java 源码是经典学习范例
IoC 介绍
耦合与内聚
耦合(Coupling)
:代码书写过程中所使用技术的结合紧密度,用于衡量软件中各个模块之间的互联程度。内聚(Cohesion)
:代码书写过程中单个模块内部各组成部分间的联系,用于衡量软件中各个功能模块自身内部的功能联系。
程序书写的目标:
高内聚,低耦合。即同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却不要那么紧密。
工厂模式发展史
Spring 发展历程
IoC 概念
IoC(Inversion Of Control)控制反转:Spring 反向控制应用程序所需要使用的外部资源。
Spring 控制的资源全部放置在 Spring 容器中,该容器称为 IoC 容器。
DI 概念
- DI(Dependency Injection)依赖注入:应用程序运行依赖的资源由 Spring 为其提供,资源进入应用程序的方式称为注入。
- IoC 与 DI 的关系:同一件事站在不同角度看待问题。
入门案例
模拟三层架构中,表现层调用业务层功能。案例步骤如下:
1)导入 spring 坐标:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.9.RELEASE</version> </dependency>
2)编写业务层接口与实现类:
- UserService.java:
public interface UserService { // 业务方法 void save(); }
- UserServiceImpl.java:
import com.service.UserService; public class UserServiceImpl implements UserService { @Override public void save() { System.out.println("UserService running..."); } }
3)创建 spring 配置文件:配置所需资源(UserService)为 Spring 控制的资源
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 创建spring控制的资源 --> <bean id="userService" class="com.service.impl.UserServiceImpl"/> </beans>
4)表现层(UserApp)通过 Spring 获取资源(Service 实例):
import com.service.UserService; import org.springframework.context.support.ClassPathXmlApplicationContext; public class UserApp { public static void main(String[] args) { // 加载配置文件,创建Spring容器 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 获取资源 UserService userService = (UserService)context.getBean("userService"); userService.save(); } }
IoC 配置
bean 标签
类型:标签
归属:beans 标签
作用:定义 spring 中的资源,受此标签定义的资源将受到 spring 控制
基本属性:
id
:bean 的名称,通过 id 值获取 bean 。class
:bean 的类型。name
:bean 的名称,可以通过 name 值获取 bean,用于多人配合时给 bean 起别名。
示例:
<beans> <bean id="beanId" name="beanName1,beanName2" class="ClassName" /> </beans>
scope 属性
类型:属性
归属:bean标签
作用:定义 bean 的作用范围
示例:
<!-- scope用于控制bean创建后的对象是否是单例的 --> <bean id="userService" scope="prototype" class="com.service.impl.UserServiceImpl" />
- 取值:
singleton
:设定创建出的对象保存在 spring 容器中,是一个单例的对象。 prototype
:设定创建出的对象不保存在 spring 容器中,是一个非单例的对象。- request、session、application、websocket(四者不常用):设定创建出的对象放置在 web 容器对应的位置。
bean 生命周期配置
名称:init-method,destroy-method
类型:属性
归属:bean 标签
作用:定义 bean 对象在初始化或销毁时完成的工作
示例:
<!-- inti-method 与 destroy-method 用于控制 bean 的生命周期 --> <bean id="userService" scope="prototype" init-method="init" destroy-method="destroy" class="com.service.impl.UserServiceImpl" />
取值:
当 scope="singleton" 时,spring 容器中有且仅有一个对象,init 方法在创建容器时仅执行一次。
当 scope="prototype" 时,spring 容器要创建同一类型的多个对象,init 方法在每个对象创建时均执行一次。
当 scope="singleton" 时,关闭容器会导致 bean 实例的销毁,调用 destroy 方法一次。
当 scope="prototype" 时,对象的销毁由垃圾回收机制 gc() 控制,destroy 方法将不会被执行。
set 方法注入 bean(主流方式)
名称:property
类型:标签
归属:bean 标签
作用:使用 set 方法的形式为 bean 提供资源
示例:
<bean> <property name="propertyName" value="propertyValue" ref="beanId"/> </bean>
基本属性:
name
:对应 bean 中的属性名,要求该属性必须提供可访问的 set 方法(严格规范为此名称是 set 方法对应名称)value
:设定非引用类型属性对应的值,不能与 ref 同时使用。ref
:设定引用类型属性对应 bean 的 id ,不能与value同时使用。
注意:一个 bean 可以有多个 property 标签。
代码示例:
- UserDaoImpl.java:
public void save(){ System.out.println("user dao running..."); }
- UserServiceImpl.java:
import com.dao.UserDao; import com.service.UserService; public class UserServiceImpl implements UserService { private UserDao userDao; private int num; // 对需要进行注入的变量(基本数据类型)添加set方法 public void setNum(int num) { this.num = num; } // 对需要进行注入的变量(引用数据类型)添加set方法 public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void save() { System.out.println("user service running..." + num); // user dao running...666 userDao.save(); // user dao running... } }
- applicationContext.xml:
<bean id="userService" class="com.service.impl.UserServiceImpl"> <!-- 2. 将要注入的引用类型的变量通过property属性进行注入,对应的name是要注入的变量名,使用ref属性声明要注入的bean的id --> <property name="userDao" ref="userDao"/> <property name="num" value="666"/> </bean> <!-- 1. 将要注入的资源声明为bean --> <bean id="userDao" class="com.dao.impl.UserDaoImpl"/>
集合类型数据注入
名称:array、list、set、map、props
类型:标签
归属:property 标签或 constructor-arg 标签
作用:注入集合数据类型属性
示例:
- BookDaoImpl.java:
package com.dao.impl; import com.dao.BookDao; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; public class BookDaoImpl implements BookDao { private List al; private Properties properties; private int[] arr; private Set hs; private Map hm ; public void setAl(List al) { this.al = al; } public void setProperties(Properties properties) { this.properties = properties; } public void setArr(int[] arr) { this.arr = arr; } public void setHs(Set hs) { this.hs = hs; } public void setHm(Map hm) { this.hm = hm; } @Override public void save() { System.out.println("book dao running..."); System.out.println("ArrayList:"+al); System.out.println("Properties:"+properties); for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } System.out.println("HashSet:"+hs); System.out.println("HashMap:"+hm); } }
- UserServiceImpl.java:
package com.service.impl; import com.dao.BookDao; import com.service.UserService; public class UserServiceImpl implements UserService { private BookDao bookDao; public UserServiceImpl() { } public UserServiceImpl(BookDao bookDao) { this.bookDao = bookDao; } public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } @Override public void save() { bookDao.save(); } }
- 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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 创建spring控制的资源 --> <bean id="userService" class="com.service.impl.UserServiceImpl"> <property name="bookDao" ref="bookDao"/> </bean> <bean id="bookDao" class="com.dao.impl.BookDaoImpl"> <property name="al"> <list> <value>value1</value> <value>value2</value> </list> </property> <property name="properties"> <props> <prop key="name">xiaoming</prop> <prop key="age">17</prop> </props> </property> <property name="arr"> <!-- 不常用 --> <array> <value>12</value> <value>34</value> </array> </property> <property name="hs"> <!-- 不常用 --> <set> <value>value1</value> <value>value2</value> </set> </property> <property name="hm"> <!-- 不常用 --> <map> <entry key="name" value="xiaoming"/> <entry key="age" value="19"/> </map> </property> </bean> </beans>
- UserApp.java(控制层):
package com.servlet; import com.service.UserService; import org.springframework.context.support.ClassPathXmlApplicationContext; public class UserApp { public static void main(String[] args) { // 加载配置文件 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 获取资源 UserService userService = (UserService)context.getBean("userService"); userService.save(); } }
- 执行结果:
book dao running... ArrayList:[value1, value2] Properties:{age=17, name=xiaoming} 12 34 HashSet:[value1, value2] HashMap:{name=xiaoming, age=19}
加载 properties 文件
Spring 提供了读取外部 properties 文件的机制,使用读取到的数据为 bean 的属性赋值。
- resource 目录下的 data.properties:
username=xiaoming password=admin123
- 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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1.加载context命名空间的支持 --> <!-- xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd --> <!-- 2.加载配置文件:*表示加载全部文件 --> <context:property-placeholder location="classpath:*.properties"/> <!-- 创建spring控制的资源 --> <bean id="userService" class="com.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"/> </bean> <bean id="userDao" class="com.dao.impl.UserDaoImpl"> <!-- 读取数据使用 ${propertiesName} 格式进行,其中 propertiesName 指 properties 文件中的属性值 --> <property name="userName" value="${username}"/> <property name="password" value="${password}"/> </bean> </beans>
- UserDaoImpl.java:
package com.dao.impl; import com.dao.UserDao; public class UserDaoImpl implements UserDao { private String userName; private String password; public void setUserName(String userName) { this.userName = userName; } public void setPassword(String password) { this.password = password; } @Override public void save() { System.out.println("userDao running:"+userName+" "+password); } }
- UserServiceImpl.java:
package com.service.impl; import com.dao.BookDao; import com.dao.UserDao; import com.service.UserService; public class UserServiceImpl implements UserService { private UserDao userDao; public UserServiceImpl() { } public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void save() { userDao.save(); } }
- UserApp.java(控制层):
package com.servlet; import com.service.UserService; import org.springframework.context.support.ClassPathXmlApplicationContext; public class UserApp { public static void main(String[] args) { // 加载配置文件 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 获取资源 UserService userService = (UserService)context.getBean("userService"); userService.save(); } }
- 运行结果:
userDao running:juno admin123
团队开发:import 导入配置文件
名称:import
类型:标签
归属:beans 标签
作用:在当前配置文件中导入其他配置文件中的项
示例:在 applicationContext.xml 中加载其他配置文件
<import resource="applicationContext-user.xml"/> <import resource="applicationContext-book2.xml"/> <import resource="applicationContext-book.xml"/>
Spring 容器加载多个配置文件:
new ClassPathXmlApplicationContext("config1.xml", "config2.xml");
Spring 容器中 bean 定义冲突问题:
同 id 的 bean,后定义的覆盖先定义的。
导入配置文件可以理解为将导入的配置文件复制粘贴到对应位置。
导入配置文件的顺序与位置不同可能会导致最终程序运行结果不同。
ApplicationContext 分析
ApplicationContext 是一个接口,提供了访问 Spring 容器的 API 。
ClassPathXmlApplicationContext 是一个类,实现了上述功能。
ApplicationContext 的顶层接口是 BeanFactory 。
BeanFactory 定义了 bean 相关的最基本操作。
ApplicationContext 在 BeanFactory 基础上追加了若干新功能。
ApplicationContext 对比 BeanFactory:
BeanFactory 创建的 bean 采用延迟加载形式,使用才创建;
ApplicationContext 创建的 bean 默认采用立即加载形式。
FileSystemXmlApplicationContext:
可以加载文件系统中任意位置的配置文件,而 ClassPathXmlApplicationContext 只能加载类路径下的配置文件。
示例:BeanFactory 创建 Spring 容器
Resource res = new ClassPathResource("applicationContext.xml"); BeanFactory bf = new XmlBeanFactory(res); UserService userService = (UserService)bf.getBean("userService");
案例:整合 Mybatis
案例介绍
使用 Spring 整合 Mybatis 技术,完成账户模块(Account)的基础增删改查功能。
账户模块对应字段:
- 编号:id
- 账户名:name
- 余额:money
案例分析
非 Spring 环境:
- 实体类与表
- 业务层接口与实现
- 数据层接口
- Mybatis 核心配置
- Mybatis 映射配置
- 客户端程序测试功能
Spring 环境:
- 实体类与表
- 业务层接口与实现(提供数据层接口的注入操作)
- 数据层接口
- Mybatis 核心配置(交给 Spring 控制,该文件省略)
- Mybatis 映射配置
- 客户端程序测试功能(使用 Spring 方式获取 bean)
- Spring 核心配置文件
- Druid 连接池(可选)
- Spring 整合 MyBatis
基础准备工作
环境准备
-
导入 Spring 坐标、MyBatis 坐标、MySQL 坐标、Druid 坐标
业务类与接口准备
创建数据库表,并制作相应的实体类 Account
定义业务层接口与数据层接口
在业务层调用数据层接口,并实现业务方法的调用
基础配置文件
jdbc.properties
MyBatis 映射配置文件
整合准备工作
Spring 配置文件,加上 context 命名空间,用于加载 properties 文件
开启加载 properties 文件
配置数据源 druid(备用)
定义 service 层 bean,注入 dao 层 bean
dao 的 bean 无需定义,使用代理自动生成
整合工作
整合工作:
导入 Spring 整合 MyBatis 坐标
将 mybatis 配置成 spring 管理的 bean(SqlSessionFactoryBean)
将原始配置文件中的所有项,转入到当前配置中
数据源转换
映射转换
通过 spring 加载 mybatis 的映射配置文件到 spring 环境中
设置类型别名
测试结果:
- 使用 spring 环境加载业务层 bean,执行操作
- Spring IoC 学习(3)
- 浅谈Spring概念(DI,IoC,AOP)
- 浅析Spring IoC源码(十一)Spring refresh()方法解析之一
- 【Java.Spring.Core】【IoC】Beans
- Spring中IoC和AOP的理解
- [spring源码学习]九、IOC源码-applicationEventMulticaster事件广播
- Spring IOC依赖注入的方式
- Spring的DI和IoC
- spring中IOC是什么意思 个人觉得解释的非常有意思
- 【Java.Spring.Core】【IoC】自定义bean nature
- spring ioc原理(看完后大家可以自己写一个spring)
- Spring 入门案例(含IOC、AOP、SpringMVC、Spring JDBC)
- 使用Spring2.5的Autowired实现注释型的IOC
- Spring IoC — 基于Java类的配置
- Spring IOC 源码解析
- IOC、Spring的IOC
- spring IOC与AOP
- spring.net结合普通三层(实现IOC 及AOP中的异常记录功能)
- Spring IOC/DI- 3 different types
- spring ioc DI 理解