一、Spring概述
Spring是一个分层的Java SE/EE full-stack轻量级开源框架,以IoC(Inverse Of Control,即控制反转)和AOP(Aspect Oriented Programming,即面向切面编程)为内核,提供了展现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还整合了开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE企业级应用框架。
1.1Spring的优势
- 方便解耦、简化开发:
通过Spring提供的IOC容器,可以将对象间的依赖关系交给Spring进行控制,避免了硬编码所造成的过度程序耦合,或者说大大降低了组件之间的耦合性。
用户也不必再为单例模式类、属性解析等这些很底层的需求编写代码,可以更加专注于上层应用。
- AOP编程支持
通过Spring提供的AOP功能,方便进行面向切面编程,允许将一些通用的任务,如安全、事务、日志等进行集中式处理,许多不容易使用传统OOP实现的功能可以通过AOP轻松应付。
- 声明式事务支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活进行事务管理,提高开发效率和质量。
- 方便程序的测试
Spring提供了对Junit4的支持,可以通过注解的方式方便的测试Spring程序,即可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情。
- 方便集成各种优秀的框架
Spring可以降低各种框架的使用难度,提供了对各种框架的直接支持。
- 降低JavaEE API的使用难度
Spring对JavaEE API(如JSDBC、JavaMail、远程调用等)进行了薄薄的封装层,使得这些API的使用难度大大降低
1.2Spring体系结构
Spring框架采用的是分层架构,它一系列功能要素被分成20个模块,这些目模块从下到上主要是:Test、Core Container、AOP、Aspects、Instrumentation、Mesaaging、Data Access/Integration、Web等
上图中包含了Spring框架的所有模块,接下来分别对体系结构中的模块作用进行简单的介绍:
Core Container(核心容器)
Spring核心容器是其他模块建立的基础,主要由Beans模块、Core模块、Context模块、Context-support模块以及SpEL模块组成。
-
Beans模块:
提供了BeanFactory,是工厂模式的经典实现,Spring将管理对象称为Bean。由org.springframework.beans.factory.BeanFactory接口定义,是基础类型的IoC容器,提供了完整的IoC服务支持。简单来说,BeanFactory就是一个管理Bean的工厂,负责初始化各种Bean,并调用他们的声明周期方法,什么时候使用什么时候创建对象。ApplicationContext是BeanFactory的子接口,也被称为应用上下文,是另一种常用的Spring核心容器,只要一读取配置文件,默认情况下就会创建对象。提供了ClassPathXmlApplicationContext和FileSystemApplicationContext两种实现方式,ClassPathApplicationContext是从类路径下加载配置文件,目前推荐使用这种方式;FileSystemXmlApplicationContext是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置;AnnotationConfigApplicationContext是当我们使用注解配置容器对象时,需要使用此类来 创建spring容器。 -
Core核心模块:
提供了Spring框架的基本组成部分,包括IoC和DI功能。 -
Context上下文模块:
建立在Core和Beans模块的基础之上,它是访问定义和配置的任何对象的媒介。其中applicationContext接口是上下文模块的焦点。 -
Context-support模块:
提供了第三方库嵌入Spring应用的集成支持,比如缓存、邮件服务、任务调度和模块引擎。 -
SpEL模块:
提供了Spring Expression Language支持,是运行时查询和操作对象图的强大语言表达式。 -
AOP模块:
提供了面向切面编程的实现,允许定义方法拦截器和切入点,将代码按照功能进行分离以降低耦合性。 -
Aspects模块:提供了与AspectJ的集成功能,AspectJ是一个功能强大且成熟的面向切面编程(AOP)的框架。
-
Instrumentation模块:提供了工具类的支持和类加载器的实现,可以在特定的应用服务器中使用。
-
Messaging模块:Spring4.0以后新增的模块,提供了对消息传递体系结构和协议的支持
-
Test模块:提供了对单元测试和集成测试的支持。
Data Access/Integration(数据访问/集成):数据访问/集成层包括JDBC、ORM、OXM、JMS和Transaction模块,具体介绍如下:
-
JDBC模块:
提供了一个JDBC的抽象层,大幅度地减少了在开发过程中对数据库操作的编码。 -
ORM模块:对流行的关系映射API,包括JPA、JDO和Hibernate提供了集成层支持。
-
OXM模块:提供了一个支持对象/XML映射的抽象层实现,如JAXB、Castor、XMLBeans、JiBX和XStream。
-
JMS模块:
指Java消息传递服务,包含使用和产生信息的特性。 -
Transaction事务模块:支持对实现特殊接口以及所有POJO类的编程和声明式事务管理。
-
WEB
Spring的Web层包括WebSocket、Servlet、Web和Portlet模块,具体的介绍如下: -
WebSocket模块:Spring 4.0以后新增的模块,它提供了WebSocket和SockJS的实现,以及对STOMP的支持。
-
Servlet模块:也称为Spring-webmvc模块,包含了Spring的模型—视图—控制器(MVC)和REST Web Services实现的Web应用程序。
-
Web模块:提供了基本的Web开发集成特性,例如:多文件上传功能、使用Servlet监听器来初始化IoC容器以及Web应用上下文。
-
Portlet模块:提供了在Portlet环境中使用MVC实现,类似Servlet模块的功能。
1.3Spring中的Bean
Spring可以看作是一个大型工厂,这个工厂的作用就是生产和管理Spring容器中的Bean。在Spring中,XML配置文件的根元素是 beans,beans中包含多个bean子元素,每个baen子元素定义了一个Bean,并描述了该Bean如何装配到Spring容器中。bean中包含了多个属性以及子元素,其常用的属性以及子元素如下:
属性或子元素名称 | 描述 |
---|---|
id | Bean的唯一标识符,Spring容器对Bean的配置和管理都是通过该属性来完成 |
name | Spring可以通过此属性对容器中的Bean进行配置和管理,name属性可以为Bean指定多个名称,每个名称使用逗号分隔 |
class | 该属性指定了Bean的具体实现类,必须是一个完整的类名,使用类的全限定名 |
scope | 用来设定Bean实例的作用域,其属性值有:singleton(单例)、prototype(多例)、request、session、global session等,默认值是singleton |
property | bean元素的子元素,用于调用Bean实例中的setter方法完成属性赋值,从而完成依赖注入。该元素的name指定bean实例中相应属性的名称,ref属性或者value属性用于指定参数值 |
ref | property或者constructor-arg等元素的属性或者子元素,可以用于指定对Bean工厂中的某一个Bean实例引用 |
value | property、constructor-arg等元素的属性或者子元素,可以用于指定一个常量值 |
list | 用于封装List或者数组类型的依赖注入 |
set | 用于封装set类型的属性的依赖注入 |
map | 用于封装map类型属性的依赖注入 |
entry | map元素的子元素,用于设置一个键值对,其key属性用于指定字符串类型的键值,ref或者value子元素用于指定其值,也可以通过value-ref或者value属性指定其值 |
在配置文件中,通常一个普通的Bean只需与定义id和class两个属性即可。
二、使用Spring IoC解决程序耦合
2.1之前程序中出现的耦合
耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:如果模块间必须存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合。内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。内聚是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。耦合是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据。 程序讲究的是低耦合,高内聚。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却要不那么紧密。内聚和耦合是密切相关的,同其他模块存在高耦合的模块意味着低内聚,而高内聚的模块意味着该模块同其他模块之间是低耦合。在进行软件设计时,应力争做到高内聚,低耦合。在我们的开发中,有些依赖关系是必须的,有些依赖关系是可以通过代码来消除的。接下来看Servcie层的业务代码:
public class IAccountServiceImpl implements IAccountService {
private IAccountDao iAccountDao = new IAccountDaoImpl();
@Override
public List<Account> findAll() {
return iAccountDao.findAll();
}
}
上述代码中,业务层调用持久层,并且此时业务层在依赖持久层的接口和实现类,如果此时将持久层实现类删除,则编译不能通过。再比如JDBC操作,在注册驱动的时候,我们为啥不用DriverManager的register方法,而是采用Class.forName()的方式呢?
public class JDBCDemo1 {
public static void main(String[] args) throws SQLException {
//1.注册驱动
/*
* 方式1:直接通过new的方式来注册,这时候我们依赖了数据库的具体驱动类(MySql),
* 这个时候如果我们更换了数据库的品牌(比如Oracel),就需要修改源码来冲洗更新数据库的驱动,
* 这显然不是我们想要的
* */
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//2.获取连接
//3.获取预处理sql语句对象
//4.获取结果集
//5.遍历结果集
}
}
2.2解决程序耦合的思路
一般我们注册驱动的时候,都是使用反射的方式,代码如下:
public class JDBCDemo1 {
public static void main(String[] args) throws SQLException {
//1.注册驱动
/*
* 方式1:直接通过new的方式来注册,这时候我们依赖了数据库的具体驱动类(MySql),
* 这个时候如果我们更换了数据库的品牌(比如Oracel),就需要修改源码来冲洗更新数据库的驱动,
* 这显然不是我们想要的
* */
// DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");//此处只有一个字符串
//2.获取连接
//3.获取预处理sql语句对象
//4.获取结果集
//5.遍历结果集
}
}
这里的好处是我们不再依赖于具体的驱动类,此时就算删除了mysql的驱动jar包,依然可以编译通过(即不会编译时就不通过),运行时就不要想了,没有驱动类是不能运行成功的。同时也产生了一个新的问题,mysql驱动的全限定类名字符串是在Java类中写死的,一旦要修改还要修改源码,解决这个问题比较简单,就是使用配置文件。在实际开发过程中,我们可以把三层的对象都是用配置文件配置起来,当启动服务器应用加载的时候,让一个类中的方法读取配置文件,把这些对象创建出来并保存起来,在接下来的使用的时候直接拿过来用就好了,那么这个读取配置文件、创建和获取三层对象的类就是工厂。
控制反转(IoC):把对象的创建权利交给框架,这是框架的重要特征,并非面向对象编程的专用术语,包括依赖注入和依赖查找。
2.3Spring快速入门
2.3.1Spring程序开发步骤
- 导入Spring开发的基本坐标
- 编写Dao接口和实现类
- 编写Spring核心配置文件
- 在Spring配置文件中配置UserDaoImpl
- 使用Spring的API获取Bean
2.3.2导入Spring开发的基本包坐标
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>spring_test001</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
</dependencies>
</project>
2.3.3编写Dao接口和实现类
- 接口类IAccountDao
public interface IAccountDao {
//查找所有
List<Account> findAll();
//根据id查找Account账户
Account findAccountById(Integer id);
//根据name进行查找
Account findAccountByName(String name);
//新增账户
void addAccount(Account account);
//修改账户
void updateAccount(Account account);
//删除账户
void deleteAccount(Account account);
}
- 接口实现类IAccountDaoImpl
public class IAccountDaoImpl implements IAccountDao {
private QueryRunner runner;
@Override
public List<Account> findAll() {
try {
return runner.query("select * from account",new BeanListHandler<Account>(Account.class));
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public Account findAccountById(Integer id) {
try {
return runner.query("select * from account where id=?",new BeanHandler<Account>(Account.class),id);
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public Account findAccountByName(String name) {
try {
return runner.query("select * from account where name=?",new BeanHandler<Account>(Account.class),name);
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void updateAccount(Account account) {
try {
runner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void addAccount(Account account) {
try {
runner.update("insert into account(name,money) values(?,?);",account.getName(),account.getMoney());
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void deleteAccount(Integer id) {
try {
runner.update("delete account where id=?",id);
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
2.3.4创建Spring核心配置文件
在类路径下(resources)创建bean.xml配置文件,并在bean.xml中配置IAccountDao
<?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="iAccountDao" class="com.itheima.dao.impl.IAccountDaoImpl"></bean>
</beans>
2.3.5使用Spring的API获取Bean的实例
public class AccountTest {
@Test
public void test1(){
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountDao iAccountDao = (IAccountDao) ac.getBean("iAccountDao");
iAccountDao.findAll();
}
}
三、Spring配置文件
3.1bean标签的基本配置
3.1.1Bean标签作用
用于配置对象交由Spring来创建。默认情况下调用的是类中无参构造函数,如果没有无参构造函数则不能创建成功。
3.1.2Bean标签配置
- id:给对象在容器中提供一个唯一的标识,用于获取对象;
- class:指定类的全限定类名,用于反射创建对象,默认情况下调用的是无参构造函数。
- scope:指定对象的作用范围。singleton默认值,单例的;prototype是多例的。
取值范围 | 说明 |
---|---|
singleton | 默认值,单例的 |
prototype | 多例的 |
request | WEB项目中,Spring创建一个Bean对象,将对象存入到request域中 |
session | WEB项目中,Spring创建一个Bean对象,将对象存入session域中 |
global session | WEB项目中,应用在Porlet环境,如果没有Porlet环境那么global Session相当于session |
(1)当scope的取值为singleton时
- Bean的实例化个数:1个
- Bean的实例化时机: 当Spring核心配置文件被加载时,实例化配置Bean实例
- 对象创建:当应用加载,创建容器时,对象就被加载了;
- 对象运行:只要容器在,对象就会一直活着
- 对象销毁:当应用卸载,销毁容器时,对象就被销毁了
(2)当scope取值为prototype时
- Bean的实例化个数:多个
- Bean的实例化时机:当调用getBean()方法时,实例化Bean
- 对象创建:当使用对象时,创建新的对象实例
- 对象运行:只要对象在使用中,就一直活着
- 对象销毁:当对象长时间不使用时,就被Java的垃圾回收器回收了
3.1.3Bean对象的生命周期
Spring可以管理singleton作用域的生命周期,在此作用域下,Spring能够精确地知道该Bean何时被创建,何时完成初始化以及被销毁。对于prototype作用域的Bean,Spring只负责创建,当容器创建了Bean实例之后,Bean的实例就交给客户端来管理,Spring容器就不再跟踪其生命周期。每次客户端请求prototype作用域的Bean时,Spring容器都会创建一个新的实例,并且不会管那些被配置成prototype作用域的Bean的生命周期。了解Bean生命周期的意义在于,可以在某个Bean生命周期的某些指定时刻完成一些相关的操作。这种时刻可能很多,但是一般情况下,常会在Bean的postinitiation(初始化后)和predestrudtion(销毁前)执行一些相关操作。当一个Bean被加载到Spring容器的时候,它就具有了生命,而Spring容器在保证一个Bean能够使用之前,会做很多的工作。Singleton类型的Bean的生命周期的配置如下:
- init-method:指定类中的初始化方法
- destory-method:指定类中的销毁方法
3.1.4Bean实例化的三种方法
(1)使用无参构造方法实例化
它会根据默认无参构造方法来创建对象,如果Bean中没有默认的无参构造方法,就会创建失败。
<bean id="iAccountDao" class="com.itheima.dao.impl.IAccountDaoImpl"></bean>
(2)使用静态工厂实例化。
使用工厂的静态方法返回Bean实例
- 静态工厂类StaticFactoryBean:
public class StaticFactoryBean {
public static IAccountDao getIAccoutDao(){
return new IAccountDaoImpl();
}
}
- 配置beans.xml配置文件
<bean id="iAccountDao" class="com.itheima.factory.StaticFactoryBean" factory-method="getIAccoutDao"></bean>
(3)使用工厂实例方法实例化
工厂的非静态方法返回Bean实例
- 工厂非静态方法实例化Bean
public class DynamicFactoryBean {
public IAccountDao getAccountDao(){
return new IAccountDaoImpl();
}
}
- Beans.xml配置文件
<bean id="dynamicFactoryBean" class="com.itheima.factory.DynamicFactoryBean"></bean>
<bean id="userDao" factory-bean="dynamicFactoryBean" factory-method="getAccountDao"></bean>
3.2依赖注入
3.2.1 依赖注入的概念
Dependency Injection,它是spring框架核心ioc的具体实现,与控制反转IoC的含义相同,只不过这两种称呼是从两个角度描述的同一个概念。在编写程序时,通过控制反转把对象的创建交给spring容器(即控权发生了反转),但是代码中不可能出现没有依赖的情况。ioc解耦只是降低了他们的依赖关系,但是不会消除,业务层的方法还是会调用持久化层的方法。这种业务层和持久化层的依赖关系在使用spring之后,就让spring来维护了。依赖注入的作用就是在使用Spring框架创建对象的时候,动态的将所依赖的对象注入Bean组件中,其实现的方式通常有两种:一种是属性setter方法注入;另一种是构造方法注入。
3.2.2属性setter方法依赖注入的实现
IoC容器使用setter方法注入被依赖的对象实例,通过调用无参构造器或者无参静态工厂方法实例化Bean之后,调用该Bean的setter方法,即可实现基于setter方法的依赖注入。
- 在IAccountServiceImpl类中添加setiAccountDao方法
public class IAccountServiceImpl implements IAccountService {
private IAccountDao iAccountDao;
public void setiAccountDao(IAccountDao iAccountDao) {
this.iAccountDao = iAccountDao;
}
@Override
public List<Account> findAll() {
return iAccountDao.findAll();
}
}
- 在spring配置文件中配置Spring容器调用set方法进行注入
<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="iAccountService" class="com.itheima.service.impl.IAccountServiceImpl">
<property name="iAccountDao" ref="iAccountDao"></property>
</bean>
<bean id="iAccountDao" class="com.itheima.factory.StaticFactoryBean" factory-method="getIAccoutDao"></bean>
</bean>
3.2.3构造方法注入
IoC容器使用构造方法注入被依赖的实例,基于构造方法的依赖注入通过调用带参数的构造方法来实现,每一个参数代表一个依赖。
- 在IAccountServiceImpl类中添加带参数的构造方法
要求:类中需要提供一个对应参数列表的构造函数
public class IAccountServiceImpl implements IAccountService {
public IAccountServiceImpl() {
}
private Integer id ;
private String name;
private Double money;
private IAccountDao iAccountDao;
public IAccountServiceImpl(Integer id, String name, Double money, IAccountDao iAccountDao) {
this.id = id;
this.name = name;
this.money = money;
this.iAccountDao = iAccountDao;
}
}
- 在spring配置文件中配置Spring容器调用有参构造的形式进行注入。涉及的标签:
constructor-arg
属性:
index:指定参数在构造函数列表的索引位置
type:指定参数在构造函数中的数据类型
name:指定参数在构造函数中的名称
value:它能赋的值是基本数据类型和String类型
ref:它能赋的值是其他bean类型
<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="iAccountService" class="com.itheima.service.impl.IAccountServiceImpl">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="money" value="23.345"></constructor-arg>
<constructor-arg name="iAccountDao" ref="iAccountDao"></constructor-arg>
</bean>
<bean id="iAccountDao" class="com.itheima.dao.impl.IAccountDaoImpl">
<property name="runner" ref="runner"></property>
</bean>
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="datasource"></constructor-arg>
</bean>
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis"></property>
<property name="user" value="root"></property>
<property name="password" value="Shezeq1,"></property>
</bean>
3.2.4注入集合属性
注入集合属性就是给类中的集合成员传值,用的是set方法注入的方式,变量的数据类型是集合,这里介绍数组、List、Set、Map、Properties。具体的代码如下:
public class IAccountDaoImpl implements IAccountDao {
private QueryRunner runner;
private String[] myStrs;
private List<String> myList;
private Set<String> mySet;
private Map<String,String> myMap;
private Properties properties;
public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public void setRunner(QueryRunner runner) {
this.runner = runner;
}
@Override
public List<Account> findAll() {
try {
System.out.println(myStrs);
System.out.println(myList);
System.out.println(myMap);
System.out.println(mySet);
return runner.query("select * from account",new BeanListHandler<Account>(Account.class));
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public Account findAccountById(Integer id) {
try {
return runner.query("select * from account where id=?",new BeanHandler<Account>(Account.class),id);
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public Account findAccountByName(String name) {
try {
return runner.query("select * from account where name=?",new BeanHandler<Account>(Account.class),name);
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void updateAccount(Account account) {
try {
runner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void addAccount(Account account) {
try {
runner.update("insert into account(name,money) values(?,?);",account.getName(),account.getMoney());
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void deleteAccount(Integer id) {
try {
runner.update("delete account where id=?",id);
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
- spring主配置文件的注入配置
<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="iAccountService" class="com.itheima.service.impl.IAccountServiceImpl">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="money" value="23.345"></constructor-arg>
<constructor-arg name="iAccountDao" ref="iAccountDao"></constructor-arg>
</bean>
<bean id="iAccountDao" class="com.itheima.dao.impl.IAccountDaoImpl">
<property name="runner" ref="runner"></property>
<!--集合数据类型Properties的注入-->
<property name="properties">
<map>
<entry key="testA" value="testa"></entry>
<entry key="testB" value="testb"></entry>
<entry key="testC" value="testC"></entry>
</map>
</property>
<!--集合数据类型List的注入-->
<property name="myList">
<array>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</array>
</property>
<!--字符串数组的注入-->
<property name="myStrs">
<array>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</array>
</property>
<!--集合数据类型Set的注入-->
<property name="mySet">
<set>
<value>ddd</value>
<value>eee</value>
<value>fff</value>
</set>
</property>
<property name="myMap">
<map>
<entry key="ggg" value="ggg"></entry>
<entry key="hhh" value="hhh"></entry>
<entry key="iii" value="iii"></entry>
</map>
</property>
</bean>
<bean id="dynamicFactoryBean" class="com.itheima.factory.DynamicFactoryBean"></bean>
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="datasource"></constructor-arg>
</bean>
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis"></property>
<property name="user" value="root"></property>
<property name="password" value="Shezeq1,"></property>
</bean>
</beans>
3.3使用Spring的IoC实现账户的CRUD
3.3.1创建数据库
- 创建数据库表并插入数据
create table account(id int primary key auto_increment,name varchar(100),money int);
insert into account(name,money) values('汤显祖',23.32),('捷克李',34.56);
- 编写账户实体类
package com.itheima.domain;
public class Account {
private Integer id;
private String name;
private Double money;
public Integer getId() {
return id;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
}
- 编写持久层接口代码
package com.itheima.dao;
import com.itheima.domain.Account;
import java.util.List;
public interface IAccountDao {
//查找所有
List<Account> findAll();
//根据id查找Account账户
Account findAccountById(Integer id);
//根据name进行查找
Account findAccountByName(String name);
//新增账户
void addAccount(Account account);
//修改账户
void updateAccount(Account account);
//删除账户
void deleteAccount(Integer id);
}
- 编写持久层接口实现类
public class IAccountDaoImpl implements IAccountDao {
private QueryRunner runner;
private String[] myStrs;
private List<String> myList;
private Set<String> mySet;
private Map<String,String> myMap;
private Properties properties;
public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public void setRunner(QueryRunner runner) {
this.runner = runner;
}
@Override
public List<Account> findAll() {
try {
System.out.println(myStrs);
System.out.println(myList);
System.out.println(myMap);
System.out.println(mySet);
return runner.query("select * from account",new BeanListHandler<Account>(Account.class));
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public Account findAccountById(Integer id) {
try {
return runner.query("select * from account where id=?",new BeanHandler<Account>(Account.class),id);
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public Account findAccountByName(String name) {
try {
return runner.query("select * from account where name=?",new BeanHandler<Account>(Account.class),name);
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void updateAccount(Account account) {
try {
runner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void addAccount(Account account) {
try {
runner.update("insert into account(name,money) values(?,?);",account.getName(),account.getMoney());
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void deleteAccount(Integer id) {
try {
runner.update("delete account where id=?",id);
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
- 编写业务层接口
package com.itheima.service;
import com.itheima.domain.Account;
import java.util.List;
public interface IAccountService {
//查找所有
List<Account> findAll();
//根据id查找Account账户
Account findAccountById(Integer id);
//根据name进行查找
Account findAccountByName(String name);
//新增账户
void addAccount(Account account);
//修改账户
void updateAccount(Account account);
//删除账户
void deleteAccount(Account account);
}
- 编写业务层接口实现类
public class IAccountServiceImpl implements IAccountService {
public IAccountServiceImpl() {
}
private Integer id ;
private String name;
private Double money;
private IAccountDao iAccountDao;
public IAccountServiceImpl(Integer id, String name, Double money, IAccountDao iAccountDao) {
this.id = id;
this.name = name;
this.money = money;
this.iAccountDao = iAccountDao;
}
public void setiAccountDao(IAccountDao iAccountDao) {
this.iAccountDao = iAccountDao;
}
@Override
public List<Account> findAll() {
return iAccountDao.findAll();
}
@Override
public Account findAccountById(Integer id) {
return null;
}
@Override
public Account findAccountByName(String name) {
return null;
}
@Override
public void addAccount(Account account) {
}
@Override
public void updateAccount(Account account) {
}
@Override
public void deleteAccount(Account account) {
}
}
- 创建并编写配置文件
<?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="iAccountService" class="com.itheima.service.impl.IAccountServiceImpl">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="money" value="23.345"></constructor-arg>
<constructor-arg name="iAccountDao" ref="iAccountDao"></constructor-arg>
</bean>
<bean id="iAccountDao" class="com.itheima.dao.impl.IAccountDaoImpl">
<property name="runner" ref="runner"></property>
<property name="properties">
<map>
<entry key="testA" value="testa"></entry>
<entry key="testB" value="testb"></entry>
<entry key="testC" value="testC"></entry>
</map>
</property>
<property name="myList">
<array>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</array>
</property>
<property name="myStrs">
<array>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</array>
</property>
<property name="mySet">
<set>
<value>ddd</value>
<value>eee</value>
<value>fff</value>
</set>
</property>
<property name="myMap">
<map>
<entry key="ggg" value="ggg"></entry>
<entry key="hhh" value="hhh"></entry>
<entry key="iii" value="iii"></entry>
</map>
</property>
</bean>
<bean id="dynamicFactoryBean" class="com.itheima.factory.DynamicFactoryBean"></bean>
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="datasource"></constructor-arg>
</bean>
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis"></property>
<property name="user" value="root"></property>
<property name="password" value="Shezeq1,"></property>
</bean>
</beans>
- 测试类代码
public class AccountTest {
@Test
public void test1(){
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountService iAccountService = (IAccountService) ac.getBean("iAccountService");
iAccountService.findAll();
System.out.println(iAccountService);
IAccountDao iAccountDao = (IAccountDao) ac.getBean("iAccountDao");
List<Account> accounts = iAccountDao.findAll();
}
}
3.4 常用注解
3.4.1用于创建对象的注解
相当于:<bean id="" class=""></bean>
3.4.1.1 @Component
- 作用:把资源让spring来管理,相当于在xml中配置一个bean。
- 属性:value,指定bean的id,如果不指定value属性,默认bean的id是当前类的类名,首字母小写。
3.4.1.2 @Controller、@Service、@Repository
他们三个注解都是针对一个衍生的注解,他们的作用和属性都是一摸一样的,他们只不过是提供了更加明确的语意化。下面的三个注解中,如果注解中有且只有一个属性要赋值的时候,且名称是value时,那么value在赋值的时候是可以不写的。
- @Controller:一般用于表现层的注解
- @Service:一般用于业务层的注解
- @Repository:一般用于持久层的注解
3.4.2用于数据注入的注解
相当于:<property name="" ref="">
或者:<property name="" value="">
3.4.2.1 @Autowired
作用:自动按照类型注入。当使用注解注入属性的时候,set方法可以省略。它只能注入其他的bean类型。当有多个类型匹配的时候,使用要注入的对象变量名称作为bean的id,在spring容器中查找,找到了可以注入成功,找不到就报错。
3.4.2.2@Qualifier
作用:在自动按照类型注入的基础上,再按照Bean的id注入。它在给字段注入的时候,必须和@Autowire一起使用,但是在给方法注入的时候,可以单独使用。
属性:value指定Bean的id
3.4.2.3 @Resource
作用:直接按照Bean的id注入,它也只能注入其他bean的类型
属性:name指定bean的id
3.4.2.4 @Value
作用:注入基本数据类型和String类型的数据
属性:value用于指定值
3.4.3用于改变作用范围的
相当于:<bean id="" class="" scope=""></bean>
3.4.3.1@Scope
作用:指定bean的作用范围
属性:value指定范围的值。取值有:singleton、prototype、request、session、globalsession
3.4.4和生命周期相关的
相当于:<bean id="" class="" init-method="" destory-method=""/>
3.4.4.1 @postConstructor
作用:指定初始化方法
3.4.4.2 @PreDestory
作用:用于指定销毁方法
3.4.5Spring注解和xml选择的问题
- 注解的优势:配置简单,维护方便(找到了类,就相当于找到了对应的配置)。
- XML的优势:修改的时候,不用修改源码。不涉及重新编译和部署
- Spring管理Bean方式的比较:
基于XML的配置 | 基于注解的配置 | |
---|---|---|
Bean定义 | < bean id="…" class="…" /> | @Component衍生类@Repository、@Service、@Controller |
Bean名称 | 通过id或者name指定 | @Component(“person”) |
Bean注入 | 或者通过p命名空间 | @Autowired按照类型注入、@Qualifier按照名称注入 |
生命过程、Bean作用范围 | init-method、destory-method、范围的scope属性 | @PostConstruct初始化、@PreSestory销毁、@Scope设置作用范围 |
适合场景 | Bean来自第三方,使用其他 | Bean的实现由用户自己开发 |
3.4.6 Spring管理对象细节
基于注解的Spring IoC配置中,bean对象特点和基于XML配置是一摸一样的。
3.4.6.1@Configuration
- 作用:用于指定当前类是一个spring配置类,当创建容器的时候会从该类上加载注解。获取容器时需要使用AnnotationApplicationContext(有@Configuration注解类的.class)
- 属性:value用于指定配置类的字节码
@Configuration注解用于代替配置文件的,加载了这个注解之后就不需要再用bean.xml配置文件了
@org.springframework.context.annotation.Configuration
public class Configuration {
}
3.4.6.2 @ComponentScan
- 作用:用于指定spring在初始化容器的时候需要扫描的包。作用和在bean.xml配置文件中的:
<context:component-scan base-package="com.itheima"/>是一样的
- 属性:basepackages用于指定要扫描的包。和该注解中的value属性作用一样。
@org.springframework.context.annotation.Configuration
@ComponentScan("com.itheima")
public class Configuration {
}
3.4.6.3@Bean
我们已经配置好了扫描包,要将数据源和JdbcTemplate对象从配置文件中移除,需要使用@Bean注解。
- 作用:该注解只能写在方法上,表示使用此方法创建一个对象,并将这个对象放进spring容器中。
- 属性:name表示给当前@Bean注解方法创建的对象指定一个名称
/*
* 连接数据库的配置类
* */
public class JdbcConfig {
/*
* 创建一个数据源,并存入spring容器中
* */
@Bean
public DataSource getDataSource(){
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setUser("root");
ds.setDriverClass("com.jdbc.mysql.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/mybatis");
ds.setPassword("Shezeq1,");
return ds;
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
3.4.6.4@PropertySource
- 作用:主要用于加载.properties文件中的配置。例如我们配置数据源的时候,可以把连接数据库的信息写进properties配置文件中,然后使用此注解指定properties配置文件的位置。
- 属性:value[]:用于指定properties文件的位置。如果是在列路径下,需要写上classpath:
/*
* 连接数据库的配置类
* */
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {
/*
* 创建一个数据源,并存入spring容器中
* */
@Bean
public DataSource getDataSource(){
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setUser("root");
ds.setDriverClass("com.jdbc.mysql.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/mybatis");
ds.setPassword("Shezeq1,");
return ds;
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
3.4.6.5@Import
- 作用:用于导入其配置类,在引入其他配置类的时候,可以不用再写@Configuration注解,当然写上也没有问题。
- 属性:value[]:用于指定其他配置类的字节码
/*
* 连接数据库的配置类
* */
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {
/*
* 创建一个数据源,并存入spring容器中
* */
@Bean
public DataSource getDataSource(){
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setUser("root");
ds.setDriverClass("com.jdbc.mysql.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/mybatis");
ds.setPassword("Shezeq1,");
return ds;
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
3.5Spring整合Junit
3.5.1原始Junit测试Spring
在原始测试类中,每个测试方法都要有下面的两行代码:
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountService iAccountService = ac.getBean("iAccountService",IAccountService.class);
这些代码的作用是获取容器,如果不写的话,会直接提示空指针异常,所以不能删掉。
3.5.2上述问题的解决思路
让SpringJunit负责创建Spring容器,但是需要将配置文件的名称告诉它,将需要测试的Bean直接在测试类中注入。
3.5.3Spring集成Junit步骤
- 导入spring集成junit坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
- 使用RunWith注解替代原来的运行期
- 使用@ContextConfiguration指定配置文件或者配置类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AnnoAccountTest {
@Autowired
private IAccountService as=null;
@Test
public void testFindAll(){
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountService iAccountService = ac.getBean("iAccountService",IAccountService.class);
List<Account> accounts = as.findAll();
for (Account account :accounts){
System.out.println(account);
}
}
@Test
public void testFindAccountById(){
Account account = as.findAccountById(5);
System.out.println(account);
}
@Test
public void testFindAccountByName(){
Account account = as.findAccountByName("王二麻子");
System.out.println(account);
}
@Test
public void testAddAccount(){
Account account = new Account();
account.setName("赵敏");
account.setMoney(2345.6789);
as.addAccount(account);
}
@Test
public void testDeleteAccount(){
as.deleteAccount(7);
}
@Test
public void testUpdateAccount(){
Account account = new Account();
account.setName("赵敏");
account.setMoney(2345.6789);
account.setId(5);
as.updateAccount(account);
}
}
- 使用@Autowired注入需要测试的对象
- 创建测试方法进行测试
3.6使用spring IoC注解的方式实现账户的CRUD
3.6.1Spring程序开发步骤
- 导入Spring开发的基本坐标
- 编写Account实体类
- 编写Dao接口和实现类
- 编写Service接口和实现类
- 编写Spring核心配置类JdbcConfig.java和Configuration.java配置类
- 编写测试类
3.6.2导入Spring开发的基本坐标到pom.xml文件中
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>spring_test02</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.9.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
3.6.2编写Account实体类
package com.itheima.domain;
import java.io.Serializable;
public class Account implements Serializable {
private Integer id;
private String name;
private Double money;
public Integer getId() {
return id;
}
@Override
public String toString() {
return "IAccount{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
}
3.6.3编写AccountDao接口和实现类
- IAccountDao接口
package com.itheima.dao;
import com.itheima.domain.Account;
import java.util.List;
public interface IAccountDao {
//查找所有
List<Account> findAll();
//根据id查找
Account findAccountById(Integer id);
//根据name查找
Account findAccountByName(String name);
//新增account
void addAccount(Account account);
//删除账户
void deleteAccount(Integer id);
//修改账户
void updateAccount(Account account);
}
- IAccountDao实现类
@Repository("accountDao")
public class IAccountDaoImpl implements IAccountDao {
@Autowired
private QueryRunner runner;
@Override
public List<Account> findAll() {
try {
return runner.query("select * from account",new BeanListHandler<Account>(Account.class));
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public Account findAccountById(Integer id) {
try {
return runner.query("select * from account where id=?",new BeanHandler<Account>(Account.class),id);
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public Account findAccountByName(String name) {
try {
List<Account> accounts = runner.query("select * from account where name=?",new BeanListHandler<Account>(Account.class),name);
if (accounts.isEmpty()) return null;
if (accounts.size()>1){
throw new RuntimeException("结果集大于1,数据有误");
}
return accounts.get(0);
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void addAccount(Account account) {
try {
runner.update("insert into account(name,money) values(?,?)",account.getName(),account.getMoney());
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void deleteAccount(Integer id) {
try {
runner.update("delete from account where id=?",id);
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void updateAccount(Account account) {
try {
runner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
3.6.4编写AccountService接口和实现类
- 编写AccountService接口
package com.itheima.service;
import com.itheima.domain.Account;
import java.util.List;
public interface IAccountService {
//查找所有
List<Account> findAll();
//根据id查找
Account findAccountById(Integer id);
//根据name查找
Account findAccountByName(String name);
//新增account
void addAccount(Account account);
//删除账户
void deleteAccount(Integer id);
//修改账户
void updateAccount(Account account);
}
- 编写AccountService接口的实现类
@Service("accountService")
public class IAccountServiceImpl implements IAccountService {
@Autowired
private IAccountDao accountDao;
@Override
public List<Account> findAll() {
return accountDao.findAll();
}
@Override
public Account findAccountById(Integer id) {
return accountDao.findAccountById(id);
}
@Override
public Account findAccountByName(String name) {
return accountDao.findAccountByName(name);
}
@Override
public void addAccount(Account account) {
accountDao.addAccount(account);
}
@Override
public void deleteAccount(Integer id) {
accountDao.deleteAccount(id);
}
@Override
public void updateAccount(Account account) {
accountDao.updateAccount(account);
}
}
3.6.5编写Spring核心配置类JdbcConfig.java和Configuration.java配置类
- Spring核心配置类JdbcConfig.java
package com.itheima.config;
public class JdbcConfiguration {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean(name = "datasource")
public DataSource getDataSource(){
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Bean(name = "runner")
public QueryRunner getQueryRunner(@Qualifier("datasource")DataSource dataSource){
return new QueryRunner(dataSource);
}
}
- Spring核心配置类SpringConfiguration.java
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
@ComponentScan("com.itheima")
@Import(JdbcConfiguration.class)
@PropertySource("classpath:jdbc.properties")
public class SpringConfiguration {
}
3.6.6编写测试类
import com.itheima.config.SpringConfiguration;
import com.itheima.domain.Account;
import com.itheima.service.IAccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AnnoAccountTest {
@Autowired
private IAccountService as=null;
@Test
public void testFindAll(){
List<Account> accounts = as.findAll();
for (Account account :accounts){
System.out.println(account);
}
}
@Test
public void testFindAccountById(){
Account account = as.findAccountById(5);
System.out.println(account);
}
@Test
public void testFindAccountByName(){
Account account = as.findAccountByName("王二麻子");
System.out.println(account);
}
@Test
public void testAddAccount(){
Account account = new Account();
account.setName("赵敏");
account.setMoney(2345.6789);
as.addAccount(account);
}
@Test
public void testDeleteAccount(){
as.deleteAccount(7);
}
@Test
public void testUpdateAccount(){
Account account = new Account();
account.setName("赵敏");
account.setMoney(2345.6789);
account.setId(5);
as.updateAccount(account);
}
}