IoC思想
IoC
:Inversion of Control,控制反转。是指 把创建对象的控制权交给框架:要想得到一个对象,由原来的主动创建对象,变成自己被动接收 框架创建的对象。IoC
是Spring的核心思想之一
作用:用于降低程序间的耦合性
控制反转IoC
1. 快速入门
需求描述
- 有
UserDao
接口和UserDaoImpl
实现类 - 通过Spring容器得到
UserDaoImpl
的实例对象(IoC方式)
开发步骤
- 创建Maven项目,导入依赖坐标:Spring的依赖坐标
- 编写dao接口
UserDao
及实现UserDaoImpl
- 创建Spring核心配置文件,并配置
UserDaoImpl
- 测试:使用Spring的API,获取Bean实例对象
需求实现
1. 创建Maven项目,导入依赖坐标
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2. 编写dao接口UserDao
及实现UserDaoImpl
- 接口
UserDao
public interface UserDao {
void save();
}
- 实现类
UserDaoImpl
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("UserDaoImpl.save......");
}
}
3. 创建Spring核心配置文件,并配置UserDaoImpl
- 配置文件名称,通常叫
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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置UserDaoImpl -->
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
</beans>
4. 使用Spring的API,获取Bean实例对象
- 编写测试类
public class SpringIocQuickStartTest {
@Test
public void test(){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = context.getBean("userDao", UserDao.class);
userDao.save();
}
}
小结
-
导入依赖:
spring-context
-
编写自己的业务代码:
UserDao, UserDaoImpl
-
创建配置文件:
applicationContext.xml
<bean id="唯一标识" class="全限定类名"></bean>
-
创建容器,加载配置文件,从容器里获取bean对象
ApplicationContext app = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); Object obj = app.getBean("唯一标识");
2. 配置文件详解
1. bean
标签的基本配置
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
-
介绍
-
用于配置:把对象交给Spring进行控制
-
默认情况下,Spring是调用类的无参构造来创建对象的;如果没有无参构造,则不能创建成功
-
-
基本属性
id
:唯一标识class
:bean的全限定类名
了解:bean的id和name的区别
- 一个bean只能有一个id;一个bean可以有多个name
- bean的name值:多个name之间以
,
;
空格
隔开,第1个name作为id,其它作为别名
2. bean
标签的作用范围配置
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" scope="singleton"></bean>
- scope属性取值如下:
取值 | 说明 |
---|---|
singleton | 默认,表示单例的,一个Spring容器里,只有一个该bean对象 |
prototype | 多例的,一个Spring容器里,有多个该bean对象 |
request | web项目里,Spring创建的bean对象将放到request 域中:一次请求期间有效 |
session | web项目里,Spring创建的bean对象将放到session 域中:一次会话期间有效 |
globalSession | web项目里,应用在Portlet环境/集群环境;如果没有Portlet/集群环境,那么globalSession相当于session(新版本中已删除) |
-
不同scope的bean,生命周期:
-
singleton:bean的生命周期和Spring容器的生命周期相同
- 整个Spring容器中,只有一个bean对象
- 何时创建:加载Spring配置文件,初始化Spring容器时,bean对象创建
- 何时销毁:Spring容器销毁时,bean对象销毁
-
prototype:bean的生命周期和Spring容器无关。Spring创建bean对象之后,交给JVM管理了
- 整个Spring容器中,会创建多个bean对象,创建之后由JVM管理
-
-
何时创建:调用
getBean
方法获取bean对象时,bean对象创建- 何时销毁:对象长时间不用时,垃圾回收
3. bean
生命周期相关方法的配置【了解】
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"
init-method="" destroy-method=""></bean>
-
init-method
:指定类中初始化方法名称,该方法将在bean对象被创建时执行 -
destroy-method
:指定类中销毁方法名称,该方法将在bean对象被销毁时执行注意:
- prototype类型的bean:Spring容器销毁时,也不会执行销毁方法,因为Spring不负责它的销毁
- singleton类型的bean:在Spring容器显式关闭时,会执行destroy-method指定的方法
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao userDao = context.getBean("userDao", UserDao.class); //显式的关闭Spring容器 ((ClassPathXmlApplicationContext)context).close();
4. bean
实例化的三种方式
- 无参构造方法实例化,默认的:让Spring调用bean的无参构造,生成bean实例对象给我们
- 工厂静态方法实例化:让Spring调用一个工厂类的静态方法,得到一个bean实例对象
- 工厂非静态方法实例化(实例化方法):让Spring调用一个工厂对象的非静态方法,得到一个bean实例对象
1. 无参构造方法实例化
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
2. 工厂静态方法实例化
- 工厂类如下:
com.itheima.factory.StaticFactory
public class StaticFactory{
public static UserDao createUserDao(){
return new UserDaoImpl();
}
}
- 配置如下:
<bean id="userDao" class="com.itheima.factory.StaticFactory"
factory-method="createUserDao"></bean>
3. 工厂非静态方法实例化
- 工厂类如下:
com.itheima.factory.InstanceFactory
public class InstanceFactory{
public UserDao createUserDao(){
return new UserDaoImpl();
}
}
- 配置如下:
<!-- 先配置工厂 -->
<bean id="instanceFactory" class="com.itheima.factory.InstanceFactory"></bean>
<!-- 再配置UserDao -->
<bean id="userDao" factory-bean="instanceFactory" factory-method="createUserDao"></bean>
3. IoC小结
- bean标签的基本配置
<bean id="唯一标识" class="全限定类名"></bean>
-
bean对象的作用范围。使用bean标签的scope属性进行设置的
- singleton:默认的,单例的。
- 何时创建:容器初始化时
- 何时销毁:容器关闭时
- 生命周期:非懒加载的单例bean对象和容器同生共死
- prototype:多例的
- 何时创建:获取bean对象时
- 何时销毁:长时间不使用,JVM垃圾回收
- singleton:默认的,单例的。
-
bean对象生命周期相关的方法配置:
- 给bean标签增加init-method属性,用于指定一个初始化方法
- 当bean对象被创建之后,会执行一次
- 给bean标签增加destroy-method属性,用于指定一个销毁方法
- 当单例bean被销毁前,会执行一次
- 多例bean销毁时,是不会执行销毁方法(因为Spring不管理多例bean对象)
- 给bean标签增加init-method属性,用于指定一个初始化方法
-
bean实例化方式:
- 默认的无参构造
<bean id="" class=""></bean>
- 工厂的静态方法:
- 如果要得到一个类的代理对象,就可以使用工厂的静态方法
<bean id="" class="工厂类全限定类名" factory-method="生成对象的静态方法"></bean>
- 工厂的非静态方法:
- 如果要得到一个类的代理对象,就可以使用工厂的非静态方法
<bean id="" factory-bean="工厂bean对象" factory-method="生成对象的非静态方法"></bean> <bean id="工厂bean" class="工厂bean的全限定类名"></bean>
依赖注入DI
-
依赖注入:Dependency Injection,是Spring的Ioc核心的具体实现。
- 类里依赖什么,由Spring注入(提供)什么
-
我们需要进行配置:告诉Spring,依赖什么
我们通过Ioc把bean对象交给了Spring容器进行管理,降低了耦合性。
但是耦合性不能彻底消除,bean之间还是有一些依赖关系。比如:业务层userService要依赖于持久层userDao。
这样的依赖关系,可以交给Spring帮我们进行依赖的注入,而不用我们自己注入依赖
快速入门
需求描述
- 有dao层:
UserDao
和UserDaoImpl
- 有service层:
UserService
和UserServiceImpl
UserServiceImpl
中的方法依赖于UserDaoImpl
- 使用Spring,把
UserDaoImpl
注入给UserServiceImpl
开发步骤
- 创建Maven项目,导入依赖坐标
- 编写dao层
UserDao
及UserDaoImpl
、service层UserService
和UserServiceImpl
- 创建Spring核心配置文件,并配置bean和依赖注入
- 使用Spring的API,测试
需求实现
1. 创建Maven项目,导入依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2. 编写dao层和service层代码
- dao层接口
UserDao
public interface UserDao {
void save();
}
- dao层实现类
UserDaoImpl
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("UserDaoImpl.save......");
}
}
- service层接口
UserService
public interface UserService {
void save();
}
- service层实现类
UserServiceImpl
public class UserServiceImpl implements UserService {
//依赖于dao层的UserDao,定义一个成员变量
private UserDao userDao;
@Override
public void save() {
userDao.save();
}
//提供userDao的get/set方法
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
3. 创建Spring核心配置文件,并配置bean和依赖注入
<?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">
<!--配置UserDao-->
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
<!--配置UserService-->
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<!--把userDao注入给userService的属性-->
<property name="userDao" ref="userDao"/>
</bean>
</beans>
4. 使用Spring的API,测试
public class UserTest {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.save();
}
}
小结
-
UserServiceImpl里有userDao,需要注入UserDaoImpl对象
- 修改userServiceImpl,里边增加userDao属性
private UserDao userDao; public void setUserDao(UserDao userDao){ this.userDao = userDao; }
- 修改xml配置文件
<bean id="" class="UserServiceImpl全限定类名"> <property name="userDao" ref="要注入的bean对象"/> </bean>
2. 三种常见注入方式
set方法注入
1) 介绍
在类中提供需要注入的成员(依赖项)的set方法,在配置文件中注入属性的值
<bean id="" class="">
<property name="属性名" value="属性值"></property>
<property name="属性名" ref="bean的id"></property>
</bean>
property
标签:用在bean标签内部,表示要给某一属性注入数据name
:属性名称value
:要注入的属性值,注入简单类型值ref
:要注入的属性值,注入其它bean对象
优势:创建bean对象时没有明确的限制,可以使用无参构造直接创建
缺点:如果某个成员必须有值,则获取对象时,有可能set方法未执行
需求实现
1. 创建Maven项目,导入依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2. 编写dao层和service层代码
- dao层接口
UserDao
public interface UserDao {
void save();
}
- dao层实现类
UserDaoImpl
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("UserDaoImpl.save......");
}
}
- service层接口
UserService
public interface UserService {
void save();
}
- service层实现类
UserServiceImpl
public class UserServiceImpl implements UserService {
//依赖于dao层的UserDao,定义一个成员变量
private UserDao userDao;
@Override
public void save() {
userDao.save();
}
//提供userDao的get/set方法
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
3. 创建Spring核心配置文件,并配置bean和依赖注入
<?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">
<!--配置UserDao-->
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
<!--配置UserService-->
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<!--把userDao注入给userService的属性-->
<property name="userDao" ref="userDao"/>
</bean>
</beans>
4. 使用Spring的API,测试
public class UserTest {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.save();
}
}
2) 示例
构造方法注入< constructor-arg >
1) 介绍
在类中提供构造方法,构造方法的每个参数就是一个依赖项,通过构造方法给依赖项注入值。
<bean id="" class="">
<constructor-arg name="构造参数名称" value="构造参数的值"></constructor-arg>
<constructor-arg name="构造参数名称" ref="bean的id"></constructor-arg>
</bean>
name
:构造参数的名称type
:构造参数的类型index
:构造参数的索引value
:要注入的值,注入简单类型值ref
:要注入的值,注入其它bean对象
优势:在获取bean对象时,注入数据是必须的操作,否则无法创建成功。
缺点:改变了bean对象的实例化方式,如果在创建对象时用不到这些数据,也必须要提供
2) 示例
p名称空间注入
1) 介绍
p名称空间注入,本质仍然是set方法注入
在xml中引入p名称空间的约束
然后通过p:属性名称=""
来注入简单数据、使用p:属性名称-ref=""
注入其它bean对象,它的本质仍然是set方法注入
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="" class="" p:属性名="简单值" p:属性名-ref="bean的id"></bean>
</beans>
2) 示例
小结
-
通过set方法注入(注入属性)
- bean里的依赖项,必须有set方法
- 在xml的bean标签里,使用property标签注入每个属性值
<bean id="" class="" > <property name="属性名称" value="注入简单值"/> <property name="属性名称" ref="注入其它bean对象"/> </bean>
-
通过构造方法注入
- bean里必须有构造方法。构造方法里每个参数,就是一个依赖项
- 在xml的bean标签里,使用constructor-arg标签注入每个构造参数的值
<bean id="" class=""> <constructor-arg name="属性名称" value="注入简单值"/> <constructor-arg name="属性名称" ref="注入其它bean对象"/> </bean>
-
通过p名称空间注入
- 本质还是set方法注入,只是xml里的配置的语法不同
- bean里每个依赖项必须有set方法
- 在xml里:
- 引入p名称空间
- bean标签上,使用
p:属性名
或者p:属性名-ref
注入值
<bean id="" class="" p:属性名="注入简单值" p:属性名-ref="注入其它bean对象"></bean>
3. 注入集合数据
介绍
- 前边我们介绍了如何注入简单数据类型和bean对象,但是在实际开发中,可能会需要给集合属性注入数据,比如:给数组、List、Set、Map等注入数据
示例
有UserDaoImpl
需要注入数据
public class UserDaoImpl implements UserDao {
private String[] arr;
private List<String> list;
private Set<String> set;
private Map<String,String> map;
private Properties properties;
// get/set...
public void show(){
System.out.println(Arrays.toString(this.arr));
System.out.println(this.list);
System.out.println(this.set);
System.out.println(this.map);
System.out.println(this.properties);
}
}
配置注入数据
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<!--给数组注入数据-->
<property name="arr">
<array>
<value>a</value>
<value>b</value>
<value>c</value>
</array>
</property>
<!--给list注入数据-->
<property name="list">
<list>
<value>a1</value>
<value>b1</value>
<value>c1</value>
</list>
</property>
<!--给set注入数据-->
<property name="set">
<set>
<value>a2</value>
<value>b2</value>
<value>c2</value>
</set>
</property>
<!--给map注入数据-->
<property name="map">
<map>
<entry key="a3" value="a3"/>
<entry key="b3" value="b3"/>
<entry key="c3" value="c3"/>
</map>
</property>
<!--给properties注入数据-->
<property name="properties">
<props>
<prop key="a4">a4</prop>
<prop key="b4">b4</prop>
<prop key="c4">c4</prop>
</props>
</property>
</bean>
所有单列结构的数据集合,标签可以互换使用。例如:List、Set、数组等
所有键值对结构的数据集合,标签可以互换使用。例如:Map、Properties等
小结
- 给数组、List、Set属性注入数据,使用:
array/list/set
中任一标签均可 - 给Map、Properties属性中注入数据,使用:
map/props
中任一标签均可
相关API介绍
1. ApplicationContext
的继承体系
ApplicationContext
:接口,代表应用上下文,可以通过其实例对象获取Spring容器中的bean对象
2. ApplicationContext
2.1 BeanFactory
和 ApplicationContext
的区别
-
ApplicationContext 是现在使用的工厂
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
-
XmlBeanFactory是老版本使用的工厂,目前已经被废弃【了解】
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
-
两者的区别:
-
ApplicationContext加载方式是框架启动时就开始创建所有单例的bean,存到了容器里面
-
BeanFactory加载方式是用到bean时再加载(目前已经被废弃)
-
2.2 ApplicationContext
的实现类
2.2.1 ClassPathXmlApplicationContext
- 是从类加载路径里,加载xml配置文件的
- 什么是类加载路径:代码编译之后的那个classes文件夹,
- 开发中可以认为Maven项目的:Java文件夹、resources文件夹,都是类加载路径
2.2.2 FileSystemXmlApplicationContext
- 从磁盘路径里,加载xml配置文件的
2.2.3 AnnotationConfigApplicationContext
- 用注解配置Spring时,通过此类加载配置类创建Spring容器,它用于读取类上的注解配置
2.3 getBean()
方法
- ApplicationContext提供了多种getBean方法的重载,常用的如下:
方法 | 参数 | 返回值 |
---|---|---|
getBean(String beanId) | bean的id | Object ,bean对象 |
getBean(String beanId,Class beanType) | bean的Class类型 | bean对象 |
getBean(Class beanType) | bean对象 |
CURD练习
需求描述
- 完成帐户信息的增、删、改、查操作,要求使用Spring对service层和dao层解耦
需求分析
- 准备工作:
- 创建Maven的Java项目,配置坐标,引入依赖
- 创建JavaBean
- 编写代码:
- 创建service和dao的接口和实现类,并添加上:查询全部、添加帐号、修改帐号、删除帐号的功能
- 配置文件:
- 创建Spring核心配置文件,配置所有的bean
- 测试
- 创建单元测试类,测试功能是否正常
需求实现
3.1 准备工作
-
创建Maven的Java项目,项目坐标自定,然后引入依赖如下:
<dependencies> <!-- 数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!-- c3p0连接池(也可以用其它连接池) --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency> <!-- DBUtils工具包 --> <dependency> <groupId>commons-dbutils</groupId> <artifactId>commons-dbutils</artifactId> <version>1.7</version> </dependency> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.2.RELEASE</version> </dependency> <!-- 单元测试 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
-
创建JavaBean:Account类如下:
public class Account { private Integer id; private String name; private Float money; //get/set... //toString... }
3.2 编写代码
1) Service层代码如下:
-
Service层接口:
AccountService
public interface AccountService { List<Account> queryAll() throws SQLException; void save(Account account) throws SQLException; void edit(Account account) throws SQLException; void delete(Integer id) throws SQLException; }
-
Service实现类:
AccountServiceImpl
public class AccountServiceImpl implements AccountService { private AccountDao accountDao; /***************业务功能方法*****************/ @Override public List<Account> queryAll() throws SQLException { return accountDao.queryAll(); } @Override public void save(Account account) throws SQLException { accountDao.save(account); } @Override public void edit(Account account) throws SQLException { accountDao.edit(account); } @Override public void delete(Integer id) throws SQLException { accountDao.delete(id); } /***************get/set方法*****************/ public AccountDao getAccountDao() { return accountDao; } public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } }
2) dao层代码如下:
-
dao层接口:
AccountDao
public interface AccountDao { List<Account> queryAll() throws SQLException; void save(Account account) throws SQLException; void edit(Account account) throws SQLException; void delete(Integer id) throws SQLException; }
-
dao实现类:
AccountDaoImpl
public class AccountDaoImpl implements AccountDao { private QueryRunner runner; /***************功能方法*****************/ @Override public List<Account> queryAll() throws SQLException { return runner.query("select * from account", new BeanListHandler<>(Account.class)); } public void save(Account account) throws SQLException{ runner.update("insert into account (id,name,money) values (?,?,?)", account.getId(), account.getName(), account.getMoney()); } public void edit(Account account) throws SQLException{ runner.update("update account set name = ?, money = ? where id = ?", account.getName(), account.getMoney(), account.getId()); } public void delete(Integer id) throws SQLException{ runner.update("delete from account where id = ?", id); } /***************get/set方法*****************/ public QueryRunner getRunner() { return runner; } public void setRunner(QueryRunner runner) { this.runner = runner; } }
3.3 提供配置
-
创建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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"/> </bean> <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"> <property name="runner" ref="runner"/> </bean> <bean id="runner" class="org.apache.commons.dbutils.QueryRunner"> <constructor-arg name="ds" ref="dataSource"/> </bean> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql:///spring"/> <property name="user" value="root"/> <property name="password" value="root"/> </bean> </beans>
3.4 功能测试
-
编写单元测试类
AccountTest
如下:public class AccountTest { private AccountService accountService; @Before public void before(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); accountService = context.getBean("accountService", AccountService.class); } @Test public void testQueryAll() throws SQLException { List<Account> accounts = accountService.queryAll(); for (Account account : accounts) { System.out.println(account); } } @Test public void testSave() throws SQLException { Account account = new Account(); account.setName("tom"); account.setMoney(10000f); accountService.save(account); } @Test public void testEdit() throws SQLException { Account account = new Account(); account.setId(3); account.setName("jerry"); account.setMoney(5000f); accountService.edit(account); } @Test public void testDelete() throws SQLException { accountService.delete(3); } }
文件引入:
引入properties
文件
如果需要在applicationContext.xml
中引入properties文件:
- 准备一个properties文件放在resources里:
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring
jdbc.username=root
jdbc.password=root
- 在
applicationContext.xml
中引入并使用jdbc.properties
- Spring的名称空间(建议使用idea自动生成的,如果idea抽风了,就自己手写)
<beans
xmlns:名称空间="http://www.springframework.org/schema/名称空间"
xsi:scehmaLocation="
http://www.springframework.org/schema/名称空间
http://www.springframework.org/schema/名称空间/spring-名称空间.xsd">
</beans>
- 使用context名称空间提供的标签,引入外部的properties文件
<!-- 注意:需要引入context名称空间,才可以使用这个标签 -->
<context:property-placeholder location="classpath:jdbc.properteis"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 使用properties中的数据 -->
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
分模块提供配置文件
在大型项目开发中,如果把所有的配置都写在一个配置文件applicationContext.xml
中,会导致:
- 配置文件过于臃肿
- 不利于分模块开发,不利于模块之间的解耦
Spring提供了分模块配置的方式,即:每个模块提供一个配置文件,在核心配置文件中引入模块配置:
- dao模块有一个配置文件:
applicationContext-dao.xml
只配置dao相关的对象 - service模块有一个配置文件:
applicationContext-service.xml
只配置service相关的对象 - 有一个总的核心配置文件:
applicationContext.xml
如下
<import resource="classpath:applicationContext-service.xml"/>
<import resource="classpath:applicationContext-dao.xml"/>
Spring整合Junit
在上边的CURD中,单元测试类里还需要我们自己去创建ApplicationContext
,并自己去获取bean对象。Spring提供了整合Junit的方法,让单元测试更简洁方便。
注解简介
注解 | 说明 |
---|---|
@RunWith | 用在测试类上,用于声明不再使用Junit,而是使用Spring提供的运行环境 |
@ContextConfiguration | 用在测试类上,用于指定Spring配置类、或者Spring的配置文件 |
Spring提供了单元测试的运行环境:SpringJunit4ClassRunner,配置到
@RunWith
注解上:
@RunWith(SpringJunit4ClassRunner.class)
- 要使用以上注解,需要导入jar包依赖:
spring-test
和junit
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
使用示例
步骤
-
在pom.xml文件中增加依赖:
spring-test
和junit
-
修改单元测试类
-
在单元测试类上增加注解:
@RunWith(SpringJunit4ClassRunner.class)
目的:使用Spring的单元测试运行器,替换Junit原生的运行器
-
在单元测试类上增加注解:
@ContextConfiguration()
目的:指定配置文件或配置类
-
在测试类里的依赖项上,直接使用
@Autowired
注入依赖
-
实现
-
在pom.xml文件中增加依赖:
spring-test
和junit
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.2.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency>
-
修改单元测试类
@RunWith(SpringJUnit4ClassRunner.class)//使用Spring的单元测试运行器 @ContextConfiguration("classpath:applicationContext.xml")//指定核心配置类/核心配置文件 public class AccountTest { @Autowired private AccountService accountService; @Test public void queryAll() throws SQLException { List<Account> accounts = accountService.queryAll(); for (Account account : accounts) { System.out.println(account); } } //...... }