笔记输出来源:拉勾教育Java就业急训营
如有侵权,私信立删
修改时间:2020年2月20日
作者:pp_x
邮箱:[email protected]
Spring概述
Spring 是什么
- Spring是分层的 Java SE/EE应用** full-stack(全栈式) 轻量级开源框架**。
- 提供了表现层 SpringMVC和持久层 Spring JDBC Template以及 业务层 事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框架。
- 两大核心:
- IOC(Inverse Of Control:控制反转)
- AOP(Aspect Oriented Programming:面向切面编程):底层动态代理
Spring发展历程
- EJB
- 1997 年,IBM提出了EJB 的思想
- 1998 年,SUN制定开发标准规范 EJB1.0
- 1999 年,EJB1.1 发布
- 2001 年,EJB2.0 发布
- 2003 年,EJB2.1 发布
- 2006 年,EJB3.0 发布
- Spring
- Rod Johnson( Spring 之父)
- 2002年编著
《Expert one on one J2EE design and development》
- 指出了JavaEE和EJB组件框架中的存在的一些主要缺陷;提出普通java类依赖注入更为简单的解决方案。
- 2004年编著
《Expert one-on-one J2EE Development without EJB》
- 阐述了JavaEE开发时不使用EJB的解决方式(Spring 雏形)
- 同年4月spring1.0诞生
- 2006年10月,发布 Spring2.0
- 2009年12月,发布 Spring3.0
- 2013年12月,发布 Spring4.0
- 2017年9月, 发布最新 Spring5.0 通用版(GA)
Spring优势
- 方便解耦,简化开发
- Spring就是一个容器,可以将所有对象创建和关系维护交给Spring管理
- 什么是耦合度?对象之间的关系,通常说当一个模块(对象)更改时也需要更改其他模块(对象),这就是耦合,耦合度过高会使代码的维护成本增加。要尽量解耦
- AOP编程的支持
- Spring提供面向切面编程,方便实现程序进行权限拦截,运行监控等功能
- 声明式事务的支持
- 通过配置完成事务的管理,无需手动编程
- 方便测试,降低JavaEE API的使用
- Spring对Junit4支持,可以使用注解测试
- 方便集成各种优秀框架
- 不排除各种优秀的开源框架,内部提供了对各种优秀框架的直接支持
- 不排除各种优秀的开源框架,内部提供了对各种优秀框架的直接支持
Spring体系结构
SpringIOC
IOC概述
- 控制反转(Inverse Of Control)不是什么技术,而是一种设计思想。它的目的是指导我们设计出更加松耦合的程序
- 控制:在java中指的是对象的控制权限(创建、销毁)
- 反转:指的是对象控制权由原来由开发者在类中手动控制反转到由Spring容器控制
- 栗子:
- 传统方式:之前我们需要一个userDao实例,需要开发者自己手动创建 new UserDao()
- IOC方式:现在我们需要一个userDao实例,直接从spring的IOC容器获得,对象的创建权交给了spring控制
自定义IOC容器
需求:实现service层与dao层代码解耦合
传统方式
- dao层
public interface IUserDao {
public void save();
}
public class UserDaoImpl implements IUserDao {
public void save() {
System.out.println("保存成功了...");
}
}
- service层
public interface IUserService {
public void save() throws ClassNotFoundException, IllegalAccessException, InstantiationException;
}
public class UserServiceImpl implements IUserService {
private IUserDao userDao;
public void save() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
userDao = new UserDaoImpl();
userDao.save();
}
}
- 测试
public class SpringTest {
@Test
public void test1() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
IUserService userService = new UserServiceImpl();
userService.save();
}
}
传统方式的问题
- 每一个Service实现类都要new一个DaoImpl,存在编译期依赖,耦合重
解决方法:反射
- 使用反射的方法避免使用new关键字来创建对象,达到解耦作用
- 修改后的service层
public class UserServiceImpl implements IUserService {
private IUserDao userDao;
public void save() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//调用dao层方法 传统方式 存在编译器依赖
//userDao = new UserDaoImpl();
//反射
userDao= (IUserDao)Class.forName("com.lagou.dao.impl.UserDaoImpl").newInstance();
userDao.save();
}
}
反射存在的问题
Class.forName("com.lagou.dao.impl.UserDaoImpl")
中存在硬编码问题
采用IOC容器
- 主要思想:配置文件解决硬编码,解析器解析配置文件,反射创建对象存入map集合
- 步骤分析
- 准备一个配置文件
bean.xml
- 编写一个工厂工具类,工厂类中使用dom4j来解析配置文件,获取到类的全路径
- 使用反射生成对应类的实例对象,存到map中(IOC容器)
- 准备一个配置文件
- bean.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<!-- id:标识 class:村的就是要生成类的全路径 -->
<bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"></bean>
</beans>
- 修改后的service
public class UserServiceImpl implements IUserService {
private IUserDao userDao;
public void save() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//调用dao层方法 传统方式 存在编译器依赖
//userDao = new UserDaoImpl();
//反射
//userDao= (IUserDao)Class.forName("com.lagou.dao.impl.UserDaoImpl").newInstance();
//ioc容器
IUserDao userDao = (IUserDao)BeanFactory.getBean("userDao");
userDao.save();
}
}
Spring相关API
BeanFactory
BeanFactory
是 IOC 容器的核心接口,它定义了IOC的基本功能- 特点:在第一次调用getBean()方法时,创建指定对象的实例
public void test2(){
//核心接口 不会创建Bean对象存到容器中
BeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
//getBean的时候才真正创建bean对象
UserDao userDao = (UserDao) xmlBeanFactory.getBean("userDao");
//调用方法
userDao.save();
}
ApplicationContext
- 代表应用上下文对象,可以获得spring中IOC容器的Bean对象
- 特点:在spring容器启动时,加载并创建所有对象的实例
public void test1(){
//获取到了spring上下文对象 借助上下文对象可以获取到IOC容器的bean对象 加载同时创建了bean对象存在容器中
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//使用上下文对象从IOC容器中获取对应的bean
//1.beanid在容器中找对应的bean对象
//UserDao userDao = (UserDao)classPathXmlApplicationContext.getBean("userDao");
//2.根据类型在容器中进行查询 如果查询到多个则报错
//UserDao userDao = classPathXmlApplicationContext.getBean(UserDao.class);
//3.根据类型和beanId同时查找
UserDao userDao = classPathXmlApplicationContext.getBean("userDao", UserDao.class);
userDao.save();
}
ApplicationContext常用实现类
ClassPathXmlApplicationContext
:它是从类的根路径下加载配置文件 推荐使用这种。FileSystemXmlApplicationContext
:它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
public void test3(){
ApplicationContext fileSystemXmlApplicationContext = new FileSystemXmlApplicationContext("D:\\Lagou\\Code\\spring\\spring_quickstart\\src\\main\\resources\\applicationContext.xml");
UserDao userDao = (UserDao) fileSystemXmlApplicationContext.getBean("userDao");
userDao.save();
}
AnnotationConfigApplicationContext
:当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解
ApplicationContext常用方法
Object getBean(String name)
:根据Bean的id从容器中获得Bean实例,返回是Object,需要强转<T> T getBean(Class<T> requiredType)
:根据类型从容器中匹配Bean实例,当容器中相同类型的Bean有多个时,则此方法会报错<T> T getBean(String name,Class<T> requiredType)
:根据Bean的id和类型获得Bean实例,解决容器中相同类型Bean有多个情况
Spring配置文件
Bean标签的基本配置
<bean id="" class=""></bean>
- 用于配置对象交由Spring来创建。
- 基本属性:
id
:Bean实例在Spring容器中的唯一标识class
:Bean的全限定名
- 默认情况下它调用的是类中的 无参构造函数,如果没有无参构造函数则不能创建成功
Bean标签范围配置
<bean id="" class="" scope=""></bean>
- scope取值范围
取值范围 | 说明 |
---|---|
singleton | 默认值,单例的 |
prototype | 多例的 |
request | WEB项目中,Spring创建一个Bean的对象,将对象存入到request域中 |
session | WEB项目中,Spring创建一个Bean的对象,将对象存入到session域中 |
global session | WEB项目中,应用在Portlet环境,如果没有Portlet环境那么globalSession 相当于 session |
- 当scope的取值为
singleton
时- Bean的实例化个数:1个
- Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例
- Bean的生命周期:
- 对象创建:当应用加载,创建容器时,对象就被创建了
- 对象运行:只要容器在,对象一直活着
- 对象销毁:当应用卸载,销毁容器时,对象就被销毁
- 当scope的取值为
prototype
时- Bean的实例化个数:多个
- Bean的实例化时机:当调用getBean()方法时实例化Bean
- Bean的生命周期:
- 对象创建:当使用对象时,创建新的对象实例
- 对象运行:只要对象在使用中,就一直活着
- 对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了
Bean生命周期配置
<bean id="" class="" scope="" init-method="" destroy-method=""></bean>
init-method
:指定类中的初始化方法名称destroy-method
:指定类中销毁方法名称
public void init(){
System.out.println("初始化方法执行了");
}
public void destory(){
System.out.println("销毁方法执行了");
}
<bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl" scope="singleton" init-method="init" destroy-method="destory"></bean>
Bean实例化的三种方式
- 无参构造方法实例化
- 工厂静态方法实例化
- 工厂普通方法实例化
无参构造方法实例化
- 会根据默认无参构造方法来创建类对象,如果bean中没有默认无参构造函数,将会创建失败
<bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"/>
工厂静态方法实例化
- 应用场景
- 依赖的jar包中有个A类,A类中有个静态方法m1,m1方法的返回值是一个B对象。如果我们频繁使用B对象,此时我们可以将B对象的创建权交给spring的IOC容器,以后我们在使用B对象时,无需调用A类中的m1方法,直接从IOC容器获得。
public class StaticFactoryBean {
public static UserDao createUserDao(){
return new UserDaoImpl();
}
}
<bean id="userDao" class="com.lagou.factory.StaticFactoryBean" factory-method="createUserDao" />
工厂普通方法实例化
- 依赖的jar包中有个A类,A类中有个普通方法m1,m1方法的返回值是一个B对象。如果我们频繁使用B对象,此时我们可以将B对象的创建权交给spring的IOC容器,以后我们在使用B对象时,无需调用A类中的m1方法,直接从IOC容器获得。
public class DynamicFactoryBean {
public UserDao createUserDao(){
return new UserDaoImpl();
}
}
<bean id="dynamicFactoryBean" class="com.lagou.factory.DynamicFactoryBean"/> <bean id="userDao" factory-bean="dynamicFactoryBean" factory- method="createUserDao"/
Bean依赖注入概述
- 依赖注入 DI(Dependency Injection):它是 Spring 框架核心 IOC 的具体实现。
- 在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情况。IOC 解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。
- 那这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了。简单的说,就是通过框架把持久层对象传入业务层,而不用我们自己去获取。
Bean依赖注入方法
构造方法
- 在UserServiceImpl中创建有参构造
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
}
- 配置Spring容器调用有参构造时进行注入
<bean id="userService" class="com.lagou.service.impl.UserServiceImpl">
<!-- 有参构造实现依赖注入
需要添加constructor-arg来指定有参构造
index="0"代表从第一个参数开始
type="com.lagou.dao.UserDao" 代表传入参数的类型
ref:引入的实例
name:与有参构造种形参名保持一致
-->
<constructor-arg index="0" type="com.lagou.dao.UserDao" ref="userDao"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>
Set方法
- 在UserServiceImpl中创建set方法
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override public void save() {
userDao.save();
}
}
- 配置Spring容器调用set方法进行注入
<bean id="userService" class="com.lagou.service.impl.UserServiceImpl">
<!-- set实现依赖注入
ref:指定传入的实参
value:传入基本类型
-->
<property name="userDao" ref="userDao"></property>
</bean>
P命名空间注入
- P命名空间注入本质也是set方法注入,但比起上述的set方法注入更加方便,主要体现在配置文件中,如下:
- 首先,需要引入P命名空间
xmlns:p="http://www.springframework.org/schema/p"
- 其次,需要修改注入方式:
<bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.lagou.service.impl.UserServiceImpl" p:userDao-ref="userDao"/>
Bean依赖注入的数据类型
- 普通数据类型
- 引用数据类型
- 集合数据类型
- 由于上部分代码都是引用类型,以下仅展示普通数据类型和集合数据类型
<!-- 注入类型的测试 -->
<bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl">
<!-- 普通数据类型的注入 -->
<property name="username" value="柳潇"></property>
<property name="age" value="18"></property>
<!-- 集合数据类型的注入-->
<!-- list注入-->
<property name="list">
<list>
<value>aaa</value>
<ref bean="user"></ref>
</list>
</property>
<!-- set注入-->
<property name="set">
<list>
<value>bbb</value>
<ref bean="user"></ref>
</list>
</property>
<!-- 数组注入-->
<property name="array">
<list>
<value>ccc</value>
<ref bean="user"></ref>
</list>
</property>
<!-- map注入-->
<property name="map">
<map>
<entry key="k1" value="ddd"></entry>
<entry key="k2" value-ref="user"></entry>
</map>
</property>
<!-- properties注入-->
<property name="properties">
<props>
<prop key="k1">v1</prop>
<prop key="k2">v2</prop>
</props>
</property>
</bean>
配置文件模块化
- 实际开发中,Spring的配置内容非常多,这就导致Spring配置很繁杂且体积很大,所以,可以将部分配置拆解到其他配置文件中,也就是所谓的配置文件模块化
- 并列的多个配置文件
ApplicationContext act = new ClassPathXmlApplicationContext("beans1.xml","beans2.xml","...");
- 主从配置文件 在配置文件中编写
<import resource="applicationContext-xxx.xml"/>
- 注意:
- 同一个xml中不能出现相同名称的bean,如果出现会报错
- 多个xml如果出现相同名称的bean,不会报错,但是后加载的会覆盖前加载的bean
小结
<bean>
标签:创建对象并放到spring的IOC容器- id属性:在容器中Bean实例的唯一标识,不允许重复
- class属性:要实例化的Bean的全限定名
- scope属性:Bean的作用范围,常用是Singleton(默认)和prototype
<constructor-arg>
标签:属性注入- name属性:属性名称
- value属性:注入的普通属性值
- ref属性:注入的对象引用值
<property>
标签:属性注入- name属性:属性名称
- value属性:注入的普通属性值
- ref属性:注入的对象引用值
<list>
<set>
<array>
<map>
<props>
<import>
标签:导入其他的Spring的分文件
IOC整合Dbutils
- dao层实现类
public class AccountDaoImpl implements AccountDao {
private QueryRunner queryRunner;
public void setQueryRunner(QueryRunner queryRunner) {
this.queryRunner = queryRunner;
}
public List<Account> findAll() {
List<Account> list = null;
//编写sql
String sql = "select * from account";
try {
list = queryRunner.query(sql, new BeanListHandler<Account>(Account.class));
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public Account findById(int id) {
Account query = null;
//编写sql
String sql = "select * from account where id = ?";
try {
query = queryRunner.query(sql, new BeanHandler<Account>(Account.class),id);
} catch (SQLException e) {
e.printStackTrace();
}
return query;
}
public void save(Account account) {
String sql = "insert into account values(null,?,?)";
try {
queryRunner.update(sql, account.getName(), account.getMoney());
} catch (SQLException e) {
e.printStackTrace();
}
}
public void update(Account account) {
String sql = "update account set name = ? , money = ? where id = ?";
try {
queryRunner.update(sql,account.getName(),account.getMoney(),account.getId());
} catch (SQLException e) {
e.printStackTrace();
}
}
public void delete(int id) {
String sql = "delete from account where id = ?";
try {
queryRunner.update(sql,id);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- service层实现类
public class AccountServiceImpl implements AccountService {
@Autowired //根据类型进行注入 相当于<property>
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public List<Account> findAll() {
return accountDao.findAll();
}
public Account findById(int id) {
return accountDao.findById(id);
}
public void save(Account account) {
accountDao.save(account);
}
public void update(Account account) {
accountDao.update(account);
}
public void delete(int id) {
accountDao.delete(id);
}
}
- xml配置文件
<!-- 引入jdbc.properties
cla sspath: 代表找文件时会定位到当前项目编译过后的classpath目录下查找
-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- dataSource -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- QueryRunner -->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<!-- ds是queryrunner有参构造的参数名-->
<constructor-arg name="ds" ref="dataSource"/>
</bean>
<!-- AccountDao -->
<bean id="accountDao" class="com.lagou.dao.impl.AccountDaoImpl">
<property name="queryRunner" ref="queryRunner"/>
</bean>
<!-- AcountService-->
<bean id="accountService" class="com.lagou.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
- 测试
public class AccountServiceTest {
private ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
private AccountService accountService = (AccountService) classPathXmlApplicationContext.getBean("accountService");
//测试添加
@Test
public void testSave(){
Account account = new Account();
account.setName("ppx");
account.setMoney(8888d);
accountService.save(account);
}
//测试根据id进行查询
@Test
public void testFindById(){
Account accountServiceById = accountService.findById(1);
System.out.println(accountServiceById);
}
//查询所有的信息
@Test
public void testFindAll(){
List<Account> all = accountService.findAll();
for (Account account : all) {
System.out.println(account);
}
}
//修改
@Test
public void testUpdate(){
Account account = new Account();
account.setId(3);
account.setName("xiaogege");
account.setMoney(1000d);
accountService.update(account);
}
}
- Spring容器加载properties文件
<context:property-placeholder location="xx.properties"/>
<property name="" value="${key}"/>
Spring注解开发
常用注解
- Spring常用注解主要是替代
<bean>
的配置
注解 | 功能 |
---|---|
@Component | 使用在类上用于实例化Bean |
@Controller | 使用在web层类上用于实例化Bean |
@Service | 使用在service层类上用于实例化Bean |
@Repository | 使用在dao层类上用于实例化Bean |
@Autowired | 使用在字段上用于根据类型依赖注入 |
@Qualifier | 结合@Autowired一起使用,根据名称进行依赖注入 |
@Resource | 相当于@Autowired+@Qualifier,按照名称进行注入 |
@Value | 注入普通属性 |
@Scope | 标注Bean的作用范围 |
@PostConstruct | 使用在方法上标注该方法是Bean的初始化方法 |
@PreDestroy | 使用在方法上标注该方法是Bean的销毁方法 |
@Repository
如果没有写value属性值,Bean的id为:类名首字母小写@Autowired
按类型匹配,如果没有设置@Qualifier,默认按变量名匹配,如果匹配到多个类型相同的则报错- 注意:JDK11以后完全移除了javax扩展导致不能使用@resource注解
- 需要引入依赖
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
- 注意:使用注解进行开发时,需要在
applicationContext.xml
中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法
<!--注解的组件扫描-->
<context:component-scan base-package="com.lagou"></context:component-scan>
Spring新注解
- 使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:
- 非自定义的Bean的配置:
<bean>
- 加载properties文件的配置:
<context:property-placeholder>
- 组件扫描的配置:
<context:component-scan>
- 引入其他文件:
<import>
- 非自定义的Bean的配置:
注解 | 功能 |
---|---|
@Configuration | 用于指定当前类是一个Spring 配置类,当创建容器时会从该类上加载注解 |
@Bean | 使用在方法上,标注将该方法的返回值存储到 Spring 容器中 |
@PropertySource | 用于加载properties 文件中的配置 |
@ComponentScan | 用于指定Spring 在初始化容器时要扫描的包 |
@Import | 用于导入其他配置类 |
注解完全整合Dbutils
- dao层
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired//使用注解后 set方法不需要
private QueryRunner queryRunner;
public List<Account> findAll() {
List<Account> list = null;
//编写sql
String sql = "select * from account";
try {
list = queryRunner.query(sql, new BeanListHandler<Account>(Account.class));
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public Account findById(int id) {
Account query = null;
//编写sql
String sql = "select * from account where id = ?";
try {
query = queryRunner.query(sql, new BeanHandler<Account>(Account.class),id);
} catch (SQLException e) {
e.printStackTrace();
}
return query;
}
public void save(Account account) {
String sql = "insert into account values(null,?,?)";
try {
queryRunner.update(sql, account.getName(), account.getMoney());
} catch (SQLException e) {
e.printStackTrace();
}
}
public void update(Account account) {
String sql = "update account set name = ? , money = ? where id = ?";
try {
queryRunner.update(sql,account.getName(),account.getMoney(),account.getId());
} catch (SQLException e) {
e.printStackTrace();
}
}
public void delete(int id) {
String sql = "delete from account where id = ?";
try {
queryRunner.update(sql,id);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- service层
@Service("accountService")//相当于配置了Bean标签的Class属性 手动配置id属性
@Scope("singleton")
public class AccountServiceImpl implements AccountService {
@Autowired //根据类型进行注入 相当于<property>
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public List<Account> findAll() {
return accountDao.findAll();
}
public Account findById(int id) {
return accountDao.findById(id);
}
public void save(Account account) {
accountDao.save(account);
}
public void update(Account account) {
accountDao.update(account);
}
public void delete(int id) {
accountDao.delete(id);
}
}
- 核心配置类
@Configuration//表示该类是核心配置类
@ComponentScan("com.lagou")//标识扫描该包及子包下的注解
@Import(DataSourceConfig.class)
public class SpringConfig {
@Bean("queryRunner")
//此处的@AutoWired代表有参构造的依赖注入
public QueryRunner getQueryRunner(@Autowired DataSource dataSource){
QueryRunner queryRunner = new QueryRunner(dataSource);
return queryRunner;
}
}
- 数据配置类
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfig {
@Value("${jdbc.driverClassName}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean("dataSource")
//会将该方法的返回值存到ioc容器中
//如果不另起一个名字 则以方法名为key值
public DataSource getDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(driver);
druidDataSource.setUrl(url);
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
return druidDataSource;
}
}
- 测试类
public class AccountServiceTest {
//纯注解形式
//使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
AccountService accountService = (AccountService) annotationConfigApplicationContext.getBean("accountService");
//测试添加
@Test
public void testSave(){
Account account = new Account();
account.setName("ppx");
account.setMoney(8888d);
accountService.save(account);
}
//测试根据id进行查询
@Test
public void testFindById(){
Account accountServiceById = accountService.findById(1);
System.out.println(accountServiceById);
}
//查询所有的信息
@Test
public void testFindAll(){
List<Account> all = accountService.findAll();
for (Account account : all) {
System.out.println(account);
}
}
//修改
@Test
public void testUpdate(){
Account account = new Account();
account.setId(3);
account.setName("xiaogege");
account.setMoney(1000d);
accountService.update(account);
}
}
Spring整合Junit
普通Junit测试问题
- 在普通的测试类中,需要开发者手动加载配置文件并创建Spring容器,然后通过Spring相关API获得Bean实例;如果不这么做,那么无法从容器中获得对象。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountService accountService = applicationContext.getBean(AccountService.class);
Spring整合Junit
- 步骤
- 导入spring集成Junit的坐标
- 使用
@Runwith
注解替换原来的运行器 - 使用
@ContextConfiguration
指定配置文件或配置类 - 使用
@Autowired
注入需要测试的对象 - 创建测试方法进行测试
- 导入spring集成Junit的坐标
<!--此处需要注意的是,spring5 及以上版本要求 junit 的版本必须是 4.12 及以上-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
- 使用@Runwith注解替换原来的运行器
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringJunitTest {
}
- 使用@ContextConfiguration指定配置文件或配置类
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(value = {"classpath:applicationContext.xml"}) 加载spring 核心配置文件
@ContextConfiguration(classes = {
SpringConfig.class}) // 加载spring核心配置类
public class SpringJunitTest {
}
- 使用@Autowired注入需要测试的对象
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {
SpringConfig.class})
public class SpringJunitTest {
@Autowired
private AccountService accountService;
}
- 测试
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration({"classpath:applicationContext.xml"})//配置文件
@ContextConfiguration(classes = {
SpringConfig.class}) //配置类
public class SpringJunitTest {
@Autowired private AccountService accountService;
//测试查询
@Test
public void testFindById() {
Account account = accountService.findById(3);
System.out.println(account);
}
}