第一章 概述
1 关于框架
框架:框架是一个程序的半成品,里面有基础代码,在基础代码的基础上进行开发,节约开发时间,提高开发效率。
spring(包括springmvc)和mybatis是企业开发中最基础的两个框架。
2 Spring概述
官网地址:https://spring.io/
2.1 Spring简介
Spring 是分层的 Java SE/EE 应用 full-stack 轻量级开源框架,以 IOC(Inverse Of Control:反转控制)和AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层 SpringMVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架 。
2.2 Spring框架特点
Spring框架:面向service层,但是也能整合web、dao以及其他的框架,都要受到它的管理。
- 方便解耦,简化开发
通过 Spring 提供的 IoC 容器,可以将对象间的依赖关系交由 Spring 进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
-
AOP 编程的支持
通过 Spring 的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付。 -
声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发效率和质量。 -
方便集成各种优秀框架
Spring 可以降低各种框架的使用难度,提供了对各种优秀框架( Struts、 Hibernate、 Hessian、 Quartz等)的直接支持。
第二章 控制反转IoC - Inverse Of Control
1 工厂模式解耦
1.1 内聚和耦合
原则:高内聚 低耦合
高内聚:比如用户的登录、注册等属性和方法,都应该放到用户类中,而不是多个不相关的类中。
低耦合:比如用户下订单:涉及到用户模块和订单模块,各个模块交换数据通过接口文件来实现。
1.2 解耦的思路
解耦,顾名思义,即解除耦合,消除依赖关系。但是在程序开发中,如果两个模块协同工作,则必然存在耦合。
思路:在我们使用一些不是频繁创建的对象时,采用反射的方式创建对象显然更加合理。而反射创建时需要提供创建类的全限定类名,这个名称如果写在java代码中,造成的结果就是修改仍然避免不了修改源码。所以,我们需要使用配置文件,把要创建类的全限定类名用配置文件配置起来。
总结:
- 第一:使用反射创建对象
- 第二:创建对象用到的全限定类名用配置文件配置起来
1.3 工厂模式解耦
工厂模式:工厂模式是我们最常用的实例化对象模式了,它是用工厂中的方法代替new创建对象的一种设计模式。
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build("SqlMapConfig.xml");
SqlSession sqlSession = factory.openSession();
Mybatis框架在使用时为我们提供了SqlSessionFactory工厂类,通过openSession()方法获取到SqlSession对象。openSession()同时方法有很多重载,用于实现不同的需求。它支持传入Connection参数来保证连接的一致性;支持传入true|false来保证事务的提交时机等等。
###1.4 运用工厂模式解耦
在service层中:
在我们使用三层架构作为开发基础时,层和层之间的调用,如果使用具体实现类就会出现内容依赖。
在需要更换实现时,就需要修改源码,造成当前业务层功能的独立性很差。同时给我们维护带来极大不便。
/**
* 账户的业务层实现类
*/
public class AccountServiceImpl implements AccountService {
//此处的依赖关系有待解决
//private AccountDao accountDao = new AccountDaoImpl();
//使用工厂模式获取dao对象
private AccountDao accountDao = (AccountDao)BeanFactory.getBean("AccountDao");
@Override
public void saveAccount() {
accountDao.saveAccount();
}
}
使用Bean工厂来创建对象:
通过解析配置文件 beans.xml,获取id和类型。
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!-- 配置 service -->
<bean id="AccountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
<!-- 配置 dao -->
<bean id="AccountDao" class="com.itheima.dao.impl.AccountDaoImpl"></bean>
</beans>
Bean工厂类,解析该配置文件,使用反射创建对象,并使用一个map容器存放该对象。用户需要该对象的时候,通过容器去取就行了(getBean获取对象)。
package com.itheima.factory;
/**
* Bean工厂:创建对象
* 步骤:
* 1. 解析xml,获取所有对象的全限定类型(全名称)
* 2. 反射创建对象,存储到容器中
* 容器:有查找的需求,使用map集合
* 3. 用户需要对象时,从容器中根据id直接获取
*/
public class BeanFactory {
// String: id , Object : 反射创建好的对象
private static Map<String,Object> map = new HashMap<>();
//静态代码块:类加载时执行,只会执行一次
static {
//解析xml,获取所有对象的全限定类型(全名称)
SAXReader reader = new SAXReader();
try {
//获取文档对象
Document doc = reader.read(BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml"));
//获取根节点
Element rootElement = doc.getRootElement();
//获取根节点下的所有的子节点
List<Element> elements = rootElement.elements();
//遍历
for (Element element : elements) {
String idValue = element.attributeValue("id");
String classValue = element.attributeValue("class");
//反射创建对象,存储到容器中
Class clazz = Class.forName(classValue);
Object obj = clazz.newInstance();
//存储到容器中
map.put(idValue, obj);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static Object getBean(String id){
return map.get(id);
}
}
2 关于IOC
2.1 什么是IOC
它的全称是Inversion Of Control,意为控制反转。它不是一个技术,而是一种思想。其作用是用于削减代码间的耦合。它的实现思想就是利用了工厂设计模式,把创建对象代码从具体类中剥离出去,交由工厂来完成,从而降低代码间的依赖关系。
2.2 IoC的实现思路分析

IoC的作用
明确:它是用于降低我们代码间的依赖关系,削减程序中的耦合。
第三章 Spring的IOC入门
1 案例的前置说明
在使用Spring中IoC的配置时,它支持纯XML配置或者纯注解配置以及XML和注解混合配置这三种方式,我们首先以纯XML配置方式为spring入门案例的技术实现。————这就是我们的Spring配置技术选型
本案例要解决 账户的业务层和持久层的依赖关系。
2 Spring基于XML的入门
创建业务层的接口和接口实现类
创建持久层的接口和接口实现类
Spring基于XML的的配置:
步骤1: 导入jar包依赖 pom.xml
步骤2: 创建Spring的配置文件 beans.xml (文件名可任意起名)
步骤3: 让Spring管理资源, 在配置文件中配置service和dao
<!-- bean 标签:用于配置让 spring 创建对象,并且存入 ioc 容器之中
id 属性:对象的唯一标识。
class 属性:指定要创建对象的全限定类名
-->
<!-- 配置 service -->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
<!-- 配置 dao -->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"></bean>
步骤4:测试配置是否成功
/**
* 测试spring基于xml的Ioc入门案例
*/
public class SpringIocTest {
/**
* 步骤分析:
* 第一步:创建容器
* 第二步:根据bean的唯一标识获取对象
* 第三步:执行方法
*/
public static void main(String[] args) {
//1.使用 ApplicationContext 接口,就是在获取 spring 容器
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
//2.根据 bean 的 id 获取对象
AccountService accountService = (AccountService) ac.getBean("accountService");
System.out.println(accountService);
AccountDao accountDao = (AccountDao) ac.getBean("accountDao");
System.out.println(accountDao);
}
}
3 基于XML的IOC深入
3.1 Spring中工厂类结构图

BeanFactory和ApplicationContext的区别:
-
通过类视图我们可以看出,BeanFactory是Spring中IoC容器的顶层接口,而ApplicationContext是它的一个子接口,所以ApplicationContext具备BeanFactory提供的全部功能。
通常情况下,我们称BeanFactory是Spring的IoC基础容器。而ApplicationContext是容器的高级接口,它比BeanFactory多了很多重要的功能。例如,父子容器的概念(在SpringMVC课程中讲解),AOP的支持,消息发布机制,事件处理机制,国际化和资源访问等等。
-
BeanFactory 和 ApplicationContext 的区别:
- 创建对象的时间点不一样。
- ApplicationContext:只要一读取配置文件, 默认情况下就会创建对象。
- BeanFactory:什么使用什么时候创建对象
- 创建对象的时间点不一样。
ApplicationContext 接口的实现类:
- ClassPathXmlApplicationContext:
- 它是从类的根路径下加载配置文件,推荐使用这种
- FileSystemXmlApplicationContext:
- 它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置
- AnnotationConfigApplicationContext :
- 当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解
代码演示
// 创建容器对象,加载配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
//从容器获取对象
Object obj = ac.getBean("accountDao");
System.out.println(obj);
3.2 IOC中Bean标签和管理对象细节
Bean标签的对象获取: getBean方法:
public class SpringIocTest {
public static void main(String[] args) {
//1.使用 ApplicationContext 接口,就是在获取 spring 容器
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
//2.根据 bean 的 id 获取对象
AccountDao accountDao = (AccountDao) ac.getBean("accountDao");
System.out.println(accountDao);
accountDao.saveAccount();
//方式2 : 根据字节码获取对象(常用),不适合接口有多个实现类的情况下
AccountDao accountDao2 = ac.getBean(AccountDao.class);
System.out.println(accountDao2);
accountDao2.saveAccount();
//方式3 : (一个接口有多个实现类时)根据字节码与bean的id 进行确定获取指定Bean对象
//若AccountDao有多个实现类,那么仅凭接口名无法确定哪个接口的实现类
AccountDao accountDao3 = ac.getBean("accountDao", AccountDao.class);
System.out.println(accountDao3);
accountDao3.saveAccount();
}
}
Bean标签的作用和属性
-
作用:
- 用于配置对象让 spring 来创建的。
- 默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。
-
属性:
-
id: 给对象在容器中提供一个唯一标识。用于获取对象。
-
class: 指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
-
scope: 指定对象的作用范围。
- singleton :默认值,单例的.每次通过getBean获取对象,都是同一个对象,只初始化一次 - prototype :多例的. - request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中. - session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中. -
init方法: 指定类中的初始化方法名称:对象的初始化工作
-
destroy方法: 指定类中销毁方法名称 :对象销毁前执行的方法,用于资源的释放
-
bean标签的生命周期:
-
单例对象: scope=“singleton”
-
一个应用只有一个对象的实例。它的作用范围就是整个引用。
-
生命周期:
对象出生: 当应用加载,创建容器时,对象就被创建了。 对象活着: 只要容器在,对象一直活着。 对象死亡: 当应用卸载,销毁容器时,对象就被销毁了。 -
一句话总结:单例模式的bean对象生命周期与容器相同。
-
-
多例对象: scope=“prototype”
-
每次访问对象时,都会重新创建对象实例。
-
生命周期:
对象出生: 当使用对象时,创建新的对象实例。 对象活着: 只要对象在使用中,就一直活着。 对象死亡: 当对象长时间不用时,被 java 的垃圾回收器回收了。 -
一句话总结:多例模式的bean对象,spring框架只负责创建,不负责销毁。即使容器销毁了,对象还是存在的。
不配置scope:默认是单例的
-
实例化Bean的三种方式:
方式1: Spring 使用默认无参构造函数(掌握,工作开发中使用第一种)
在默认情况下, Spring会根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败。
- 步骤1: 编写beans.xml
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"/>
方式二和方式三不推荐使用,不进行介绍
4 Spring的依赖注入(DI)
4.1 什么是依赖注入
依赖注入(DI): Dependency Injection。就是让spring框架给Bean对象的属性进行赋值. 它是 spring 框架核心 ioc 的具体实现.
- 我们的程序在编写时, 通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。ioc 解耦只是降低他们的依赖关系,但不会消除。 例如:我们的业务层仍会调用持久层的方法。那这种业务层和持久层的依赖关系, 在使用 spring 之后, 就让 spring 来维护了。
- 简单的说,依赖注入(DI)就是坐等框架把持久层对象传入业务层,而不用我们自己去获取
4.2 使用构造方法方式注入
顾名思义,就是使用类中的构造函数,给成员变量赋值。
注意,赋值的操作不是我们自己做的,而是通过配置的方式,让 spring 框架来为我们注入。具体代码如下
步骤1: 编写AccountServiceImpl
public class AccountServiceImpl implements AccountService {
private String name;
private Integer age;
private Date birthday;
public AccountServiceImpl(String name, Integer age, Date birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}
@Override
public void saveAccount() {
System.out.println(name+","+age+","+birthday);
}
}
步骤2: 编写beans.xml
使用构造函数的方式,给pojo中的属性传值
要求:
- 类中需要提供一个对应参数列表的构造函数。
涉及的标签:
-
constructor-arg
- 属性:
index:指定参数在构造函数参数列表的索引位置 type:指定参数在构造函数中的数据类型 name:指定参数在构造函数中的名称 用这个找给谁赋值 ========上面三个都是找给谁赋值,下面两个指的是赋什么值的======== value:它能赋的值是基本数据类型和 String 类型 ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean ()
编写beans.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="birthdayId" class="java.util.Date"></bean>
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<!--使用构造方法的方式1,通过构造方法中索引位置来赋值,不推荐-->
<!--<constructor-arg index="0" value="zhang3"></constructor-arg>-->
<!--<constructor-arg index="1" value="25"></constructor-arg>-->
<!--<constructor-arg index="2" ref="birthdayId"></constructor-arg>-->
<!--使用构造方法的方式2,通过构造方法中参数的类型来赋值,不推荐-->
<!--<constructor-arg type="java.lang.String" value="zhang3"></constructor-arg>-->
<!--<constructor-arg type="java.lang.Integer" value="25"></constructor-arg>-->
<!--<constructor-arg type="java.util.Date" ref="birthdayId"></constructor-arg>-->
<!--使用构造方法的方式3,通过构造方法中形参的名称来赋值 推荐-->
<constructor-arg name="name" value="zhang3"></constructor-arg>
<constructor-arg name="age" value="25"></constructor-arg>
<constructor-arg name="birthday" ref="birthdayId"></constructor-arg>
</bean>
</beans>
4.3 使用set方法方式注入
区分一般的数据类型,引用数据类型,集合类型的方式
**顾名思义,就是在类中提供需要注入成员的 set 方法。**实际开发中,此种方式用的较多
具体代码如下
步骤1: 编写AccountServiceImpl
public class AccountServiceImpl implements AccountService {
private String name;
private Integer age;
private Date birthday;
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public void saveAccount() {
System.out.println(name+","+age+","+birthday);
}
}
步骤2: 编写beans.xml(普通的属性)
通过配置文件给 bean 中的属性传值:使用 set 方法的方式
涉及的标签:
-
property
- 属性:
name: 找的是类中 set 方法后面的部分 value: 给属性赋值是基本数据类型和 string 类型的 ref: 给属性赋值是其他 bean 类型的
<bean id="birthdayId" class="java.util.Date"></bean>
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="name" value="lisi"></property>
<property name="age" value="30"></property>
<property name="birthday" ref="birthdayId"></property>
</bean>
步骤2: 编写beans.xml(集合属性)
注入集合数据, 在注入集合数据时,只要结构相同,标签可以互换
-
List 结构的:array,list,set
-
Map 结构的: map,entry; props,prop
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<!--数组-->
<property name="myStrs">
<array>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</array>
</property>
<!--list集合-->
<property name="myList">
<list>
<value>javase</value>
<value>mysql</value>
<value>javaweb</value>
</list>
</property>
<!--set集合-->
<property name="mySet">
<set>
<value>北京</value>
<value>上海</value>
<value>南京</value>
</set>
</property>
<!--map集合-->
<property name="myMap">
<map>
<entry key="aaa" value="你好"></entry>
<entry key="bbb" value="hello"></entry>
<entry key="ccc" value="Hi"></entry>
</map>
</property>
<!--properties集合-->
<property name="myProps">
<props>
<prop key="111">哈哈</prop>
<prop key="222">嘿嘿</prop>
<prop key="333">呵呵</prop>
</props>
</property>
</bean>
</bean>
- 在List结构的集合数据注入时:
array,list,set这三个标签通用,另外注值的value标签内部可以直接写值,也可以使用bean标签配置一个对象,或者用ref标签引用一个已经配合的bean的唯一标识。
- 在Map结构的集合数据注入时:
map标签使用entry子标签实现数据注入,entry标签可以使用key和value属性指定存入map中的数据。- 使用value-ref属性指定已经配置好的bean的引用。
- 同时
entry标签中也可以使用ref标签,但是不能使用bean标签。 - 而
property标签不能中不能使用ref或者bean标签引用对象
第四章 Spring整合Mybatis开发
1 整合思路
Spring和Mybatis都是框架,整合到底是Mybatis接管Spring,还是Spring接管Mybatis呢?
通过早期的学习,我们知道Mybatis框架是一个持久层ORM框架,而今天我们学习的Spring则是一个综合性的框架。所以整合是Mybatis往Spring上整合。就是让Spring框架接管Mybatis中的SqlSessionFactory工厂的创建,同时再通过读取mapper配置内容创建dao的代理实现类,并把他们都存入IoC容器。
Spring和Mybatis他们都有独立的配置文件,我们在整合时,有两种选择。第一种是保留两个框架的配置文件,第二种是只保留Spring的配置文件,把Mybatis相关的配置都写在Spring的配置文件中。这两种方式的结果是第二种看起来更为简洁明了。
2 Mybatis框架搭建
在整合之前,我们先要分析整合步骤。我们的思路是,一个框架一个框架的去搭建环境,这样的好处是当出现问题能很快定位到哪里出了问题。
1 创建数据库表
2 创建pom文件
3 创建pojo
4 实现Dao层:
创建Dao接口:增删改查的方法签名。
创建接口的实现类(不用我们自己实现,mybatis框架):原理:使用sql的映射文件
创建dao下的资源目录用于存放接口对应的Mapper映射文件
编写Mapper映射文件,每条sql语句对应接口中定义的方法
创建Mybatis的核心配置文件:
分离一个连接数据库的properties文件,存放连接数据库的配置信息,
加载SQL的映射文件,package自动扫描包下的所有配置文件
设置pojo的别名映射,简化sql映射文件中的参数名
5 测试:
导入单元测试包4.12以上,用了spring
为dao接口中的每个方法设置测试方法
抽取@before 创建连接池
3 Spring框架搭建及整合Mybatis
6 实现Service层:
创建Service接口:对应dao中接口的方法
创建Service的接口对应的实现类:
Service中需要dao的实现类对象,使用依赖注入:set或构造方法的方式,Spring容器注入了一个对象
7 创建Spring的核心配置文件ApplicationContext.xml
配置Service层代码,依赖注入的配置:bean标签service的接口实现类,
property中配置的ref的类型是dao实现类对象的类型,所以配置dao层的代码
配置dao层的代码(Mybatis框架与Spring框架的整合)
配置数据源Druid
配置SQLSessionFactory
配置扫描Dao层代码,实现对接口与SQL文件进行加载,SpringIOC容器会自动创建dao接口的接口实现类对象(动态代理),存到Map集合
Mybatis的配置文件全部整合到Spring中,Mybatis的配置文件可以删除了
配置service层bean对象:
<!--service层开始-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<!--此时还没有配置扫描accountDao,会报错,先不管-->
<property name="accountDao" ref="accountDao"></property>
</bean>
<!--service层结束-->
配置dao层bean对象:
<!--dao层开始-->
<!--配置properties文件的位置-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--配置mybatis的SqlSessionFactory工厂-->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
<!--配置别名-->
<property name="typeAliasesPackage" value="com.itheima.pojo"></property>
</bean>
<!--配置创建dao代理实现类的扫描器-->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.itheima.dao"></property>
</bean>
<!--dao层结束-->
4 MyBatis框架测试
public class TestSpring {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
AccountService accountService = ac.getBean(AccountService.class);
Account account = accountService.findByName("热巴");
System.out.println("account = " + account);
}
}
本文介绍了Spring框架的基本概念及其特点,详细探讨了控制反转IoC的原理与实现思路,并通过具体案例展示了如何使用Spring进行依赖注入DI。此外,还介绍了Spring与MyBatis的整合过程,包括配置与测试。
2344

被折叠的 条评论
为什么被折叠?



