目录
1.Spring框架的主要内容
1.1Spring的发展版本
1.2Spring系统架构
(1)核心层
(2)AOP层
(3)数据层
(4)Web层
(5)Test层
1.3Spring核心概念
1.3.1IOC(Inversion of control)控制反转
1.3.2DI(Dependency Injection)依赖注入
1.3.3核心概念小结
1.4入门案例代码实现
步骤1:创建Maven项目
步骤2:添加Spring的依赖jar包
步骤3:添加案例中需要的类
步骤4:添加spring配置文件(先导入Spring的jar包)
步骤5:在配置文件中完成bean的配置
步骤6:获取IOC容器
步骤7:从容器中获取对象进行方法调用
步骤8:运行程序
总结
1.5DI入门案例
步骤1: 去除代码中的new
步骤2:为属性提供setter方法
步骤3:修改配置完成注入
步骤4:运行程序
1.6bean基础配置
1.6.1bean的name属性
*1.6.2bean作用范围scope配置
1.6.3scope思考
1.6.4小结
1.7bean实例化
1.7.1构造方法实例化bean
1.7.2静态工程实例化
1.7.3实例工厂与FactoryBean
1.7.4FactoryBean的使用
1.8bean的生命周期
1.8.2注册钩子关闭容器
注意(关于afterPropertiesSet与setBookDao的执行顺序):
1.8.3bean生命周期小结
1.9setter注入和构造器注入
1.9.1setter注入引用类型
1.9.2setter注入简单数据类型
1.9.3构造器注入引用数据类型
1.9.4构造器注入多个简单数据类型(解耦的两种方式)
1.9.5参数注入方式的选择
1.10自动配置
1.10.1依赖自动装配
1.10.2自动装配的方式(按类型byType和按名称byName)
1.10.3集合注入
简化开发 : Spring 框架中提供了两个大的核心技术,分别是 : IOC和 AOP事务处理1.Spring 的简化操作都是基于这两块内容 , 所以这也是 Spring 学习中最为重要的两个知识点。2. 事务处理属于 Spring 中 AOP 的具体应用,可以简化项目中的事务管理,也是 Spring 技术中的一大亮点。框架整合 : Spring 在框架整合这块已经做到了极致,它可以整合市面上几乎所有主流框架,比如 :MyBatisMyBatis-plusStrutsStruts2Hibernate综上所述,对于 Spring 的学习,主要学习四块内容 :(1)IOC,(2) 整合 Mybatis(IOC 的具体应用 ) , (3)AOP,(4) 声明式事务 (AOP 的具体应用 )
Spring1.0 是纯配置文件开发Spring2.0 为了简化开发引入了注解开发,此时是配置文件加注解的开发方式Spring3.0 已经可以进行纯注解开发,使开发效率大幅提升,我们的课程会以注解开发为主Spring4.0 根据 JDK 的版本升级对个别 API 进行了调整Spring5.0 已经全面支持 JDK8 ,现在 Spring 最新的是 5 系列所以建议大家把 JDK 安装成 1.8 版
(1)核心层
Core Container: 核心容器,这个模块是 Spring 最核心的模块,其他的都需要依赖该模块(2)AOP层
AOP: 面向切面编程,它依赖核心层容器,目的是 在不改变原有代码的前提下对其进行功能增强Aspects:AOP 是思想 ,Aspects 是对 AOP 思想的具体实现(3)数据层
Data Access: 数据访问, Spring 全家桶中有对数据访问的具体实现技术 Data Integration: 数据集成, Spring 支持整合其他的数据层解决方案,比如 MybatisTransactions: 事务, Spring 中事务管理是 Spring AOP 的一个具体实现,也是后期学习的 重点内容(4)Web层
这一层的内容将在 SpringMVC 框架具体学习(5)Test层
Spring 主要整合了 Junit 来完成单元测试和集成测试
在 Spring 核心概念这部分内容中主要包含 IOC/DI、IOC容器和 Bean , 那么问题就来了,这些都是什么呢 ?为了解决 现在代码在编写的过程中存在的问题是: 耦合度偏高使用对象时,在程序中不要主动使用 new 产生对象,转换为由 外部 提供对象,这种实现思想就是 Spring 的一个核心概念 。
(1)什么是控制反转呢?使用对象时,由主动 new 产生对象转换为由 外部 提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。(2)Spring和IOC之间的关系是什么呢?Spring 技术对 IOC 思想进行了实现Spring 提供了一个容器,称为 IOC 容器 ,用来充当 IOC 思想中的 " 外部 "IOC 思想中的 别人 [ 外部 ] 指的就是 Spring 的 IOC 容器(3)IOC容器的作用以及内部存放的是什么?IOC 容器负责对象的创建、初始化等一系列工作,其中包含了数据层和业务层的类对象被创建或被管理的对象在 IOC 容器中统称为 BeanIOC 容器中放的就是一个个的 Bean 对象(4)当IOC容器中创建好service和dao对象后,程序能正确执行么?不行,因为 service 运行需要依赖 dao 对象IOC 容器中虽然有 service 和 dao 对象但是 service 对象和 dao 对象没有任何关系需要把 dao 对象交给 service, 也就是说要绑定 service 和 dao 对象之间的关系像这种在容器中建立对象与对象之间的绑定关系就要用到 DI(依赖注入) :
(1)什么是依赖注入呢?在容器中建立 bean 与 bean 之间的依赖关系的整个过程,称为依赖注入业务层要用数据层的类对象,以前是自己 new 的, 现在自己不 new 了,靠 别人 [ 外部其实指的就是IOC 容器 ] 来给注入进来, 这种思想就是依赖注入(2)IOC容器中哪些bean之间要建立依赖关系呢?这个需要程序员根据业务需求提前建立好关系,如 业务层需要依赖数据层, service 就要和 dao 建 立依赖关系
Spring 的 IOC 和DI两个概念的最终目标就是 : 充分解耦使用 IOC 容器管理 bean ( IOC)在 IOC 容器内将有依赖关系的 bean 进行关系绑定( DI )最终结果为 : 使用对象时不仅可以直接从 IOC 容器中获取,并且获取到的 bean 已经绑定了所有的依赖关系
(1)什么IOC/DI思想?IOC: 控制反转,控制反转的是对象的创建权DI: 依赖注入,绑定对象与对象之间的依赖关系(2)什么是IOC容器?Spring 创建了一个容器用来存放所创建的对象,这个容器就叫 IOC 容器(3)什么是Bean?容器中所存放的一个个对象就叫 Bean 或 Bean 对象
需求分析 : 将 BookServiceImpl 和 BookDaoImpl 交给 Spring 管理,并从容器中获取对应的 bean对象进行方法调用。1. 创建 Maven 的 java 项目2.pom.xml 添加 Spring 的依赖 jar 包3. 创建 BookService,BookServiceImpl , BookDao 和 BookDaoImpl 四个类4.resources 下添加 spring 配置文件,并完成 bean 的配置5. 使用 Spring 提供的接口完成 IOC 容器的创建6. 从容器中获取对象进行方法调用
4.0.0
com.itheima
spring_01_quickstart
1.0-SNAPSHOT
8
8
org.springframework
spring-context
5.2.10.RELEASE
junit
junit
4.12
test
创建BookService,BookServiceImpl,BookDao和BookDaoImpl四个类
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
public interface BookService {
public void save();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao = new BookDaoImpl();
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
package com.itheima.service;
import com.itheima.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App2 {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
}
}
package com.itheima.service;
import com.itheima.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App2 {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// BookDao bookDao = (BookDao) ctx.getBean("bookDao");
//
// bookDao.save();
BookService bookService = (BookService) ctx.getBean("service");
bookService.save();
}
}
但是在 BookServiceImpl 的类中依然存在 BookDaoImpl 对象的new 操作,它们之间的耦合度还是比较高(在BookServiceImpl实体类中还是存在new BookDaoImpl,故耦合度还是较高),这块该如何解决,就需要用到下面的 DI: 依赖注入 。
首先获取IOC容器,使用ClassPathXmlApplicationContext()方法对配置文件applicationContext.xml进行加载,new出一个IOC容器对象调用getBean()方法通过id(bookService)对bean标签进行加载,即可得到bookService对象,在配置文件中,id="bookService"的标签通过全类名定位该实体类,最后调用其方法。
(1) 要想实现依赖注入,必须要基于 IOC 管理 BeanDI 的入门案例要依赖于前面 IOC 的入门案例(2)Service 中使用 new 形式创建的 Dao 对象是否保留 ?需要删除掉,最终要使用 IOC 容器中的 bean 对象(3)Service 中需要的 Dao 对象如何进入到 Service 中 ?在 Service 中提供方法,让 Spring 的 IOC 容器可以通过该方法传入 bean 对象(4)Service 与 Dao 间的关系如何描述 ?使用配置文件
需求 : 基于 IOC 入门案例,在 BookServiceImpl 类中删除 new 对象的方式,使用 Spring 的 DI 完成Dao 层的注入1. 删除业务层中使用 new 的方式创建的 dao 对象2. 在业务层提供 BookDao 的 setter 方法3. 在配置文件中添加依赖注入的配置4. 运行程序调用方法
在BookServiceImpl类中,删除业务层中使用new的方式创建的dao对象
package com.itheima.service.impl;
import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
package com.itheima.service.impl;
import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
注意 : 配置中的两个 bookDao 的含义是不一样的name="bookDao" 中 bookDao 的作用是让 Spring 的 IOC 容器在获取到名称后,将首字母大写,前面加 set 找对应的 setBookDao() 方法进行对象注入ref="bookDao" 中 bookDao 的作用是让 Spring 能在 IOC 容器中找到 id 为 bookDao 的 Bean 对象给bookService 进行注入
答案肯定是不行,因为接口是没办法创建对象的。
package com.itheima;
import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AppForName {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService) ctx.getBean("service4");
bookService.save();
}
}
singleton(单例):
只有一个共享的实例存在,所有对这个bean的请求都会返回这个唯一的实例。
prototype(多例):
对这个bean的每次请求都会创建一个新的bean实例,类似于new。
为什么bean默认为单例?1.bean 为单例的意思是在 Spring 的 IOC 容器中只会有该类的一个对象2.bean 对象只有一个就避免了对象的频繁创建与销毁,达到了 bean 对象的复用,性能高bean在容器中是单例的,会不会产生线程安全问题?1.如果对象是有状态对象,即该对象有成员变量可以用来存储数据的, 所有请求线程共用一个bean 对象,所以会存在线程安全问题。2.如果对象是无状态对象,即该对象没有成员变量没有进行数据存储的, 方法中的局部变量在方法调用完成后会被销毁,所以不会存在线程安全问题。哪些bean对象适合交给容器进行管理?1.表现层对象2.业务层对象3.数据层对象4.工具对象哪些bean对象不适合交给容器进行管理?封装实例的域对象,因为会引发线程安全问题,所以不适合。
Spring内部走的依然是构造函数 , 能访问到类中的私有构造方法 , 显而易见 Spring 底层用的是反射,Spring 底层使用的是类的无参构造方法。
配置文件:
class: 工厂类的类全名factory-mehod: 具体工厂类中创建对象的方法名通过IOC容器获取配置文件id,通过全类名获取工厂类,通过factory-method属性获取工厂类中的方法将对象返回到IOC容器中。
配置文件:
实例化工厂运行的顺序是 :1.创建实例化工厂对象 , 对应的是第一行配置2.调用对象中的方法来创建 bean ,对应的是第二行配置3.factory-bean: 工厂的实例对象factory-method: 工厂对象中的具体创建对象的方法名 , 对应关系如下 :首先我们想要从IOC容器中调用到UserDao对象,并且是通过实例工厂的方法,在配置文件中,第一行配置IOC容器已经得到UserDaoFactory对象,我们通过factory-bean="userFactory"得到该对象,再通过属性factory-method="getUserDao"得到该对象的方法,从而返回UserDaoImpl实体类对象。
package com.itheima.factory;
import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
import org.springframework.beans.factory.FactoryBean;
//FactoryBean创建对象
public class UserDaoFactoryBean implements FactoryBean {
//代替原始实例工厂中创建对象的方法
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
public Class> getObjectType() {
return UserDao.class;
}
}
T getObject() throws Exception;
Class> getObjectType();
default boolean isSingleton() {
return true;
}
查看源码会发现, FactoryBean 接口其实会有三个方法,分别是 :方法一 :getObject() ,被重写后,在方法中进行对象的创建并返回方法二 :getObjectType(), 被重写后,主要返回的是被创建类的 Class 对象方法三 : 没有被重写,因为它已经给了默认值,从方法名中可以看出其作用是设置对象是否为单 例,默 认 true。
1.7.5bean小结
关于 bean 的相关知识还有最后一个是 bean 的生命周期 , 对于生命周期,我们主要围绕着 bean 生命周期控 制 来讲解 :首先理解下什么是生命周期?从创建到消亡的完整过程 , 例如人从出生到死亡的整个过程就是一个生命周期。bean生命周期是什么?bean 对象从创建到销毁的整体过程。构造方法bean生命周期控制是什么?在 bean 创建后到销毁前做一些事情。
步骤1:添加初始化和销毁方法
package com.itheima.dao.impl;
import com.itheima.dao.BookDao;
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
//表示bean初始化对应的操作
public void init(){
System.out.println("init...");
}
//表示bean销毁前对应的操作
public void destory(){
System.out.println("destory...");
}
}
1.8.1close关闭容器
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
调用ctx的close()方法
ctx.close();
ctx.registerShutdownHook();
两种方式介绍完后,close和registerShutdownHook选哪个?相同点 : 这两种都能用来关闭容器不同点 :close() 是在调用的时候关闭, registerShutdownHook() 是在 JVM 退出前调用关闭。
package com.itheima.service.impl;
import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
System.out.println("set .....");
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
public void destroy() throws Exception {
System.out.println("service destroy");
}
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
}
对于 InitializingBean 接口中的 afterPropertiesSet 方法,翻译过来为 属性设置之后 。对于 BookServiceImpl 来说, bookDao 是它的一个属性setBookDao 方法是 Spring 的 IOC 容器为其注入属性的方法思考:afterPropertiesSet和setBookDao谁先执行?setBookDao 方法先执行,初始化方法会在类中属性设置之后执行,因为bookDao是一个属性,而afterPropertiesSet方法是在属性设置之后执行
(1)关于Spring中对bean生命周期控制提供了两种方式:在配置文件中的 bean 标签中添加 init-method 和 destroy-method 属性类实现 InitializingBean 与 DisposableBean 接口,这种方式了解下即可。(2)对于bean的生命周期控制在bean的整个生命周期中所处的位置如下:初始化容器1. 创建对象 ( 内存分配 )2. 执行构造方法3. 执行属性注入 (set 操作 )4. 执行 bean 初始化方法使用 bean1. 执行业务操作关闭 / 销毁容器1. 执行 bean 销毁方法(3)关闭容器的两种方式:ConfigurableApplicationContext 是 ApplicationContext 的子类close() 方法registerShutdownHook()方法
1.在实体类 中定义引用类型属性,并提供可访问的 set 方法2. 配置中使用 property 标签 ref 属性注入引用类型对象
例如:
1.在实体类 中定义引用类型属性,并提供可访问的 set 方2. 配置中使用 property 标签 value 属性注入简单数据类型的值
说明:value:后面跟的是简单数据类型,对于参数类型,Spring在注入的时候会自动转换,但无法
将字母转换为数字
1.删除 setter方法并且提供 构造方法2.配置文件中进行配置 构造方式注入
说明 :在标签中name 属性对应的值为构造函数中方法形参的参数名,必须要保持一致。ref 属性指向的是 spring 的 IOC 容器中其他 bean 对象。此外,构造器注入多个引用数据类型,只需在构造器中添加形参,而在配置文件中添加标签,该标签在多个的情况下,无先后顺序。
1.添加多个 简单属性并提供 构造方法2.配置完成 多个属性构造器注入
根据构造方法参数名称注入
由于根据属性name来进行数据注入存在较高耦合,我们使用以下两种方式来降低耦合
方式一(将name属性替换为type属性,添加相应的类型):
根据构造方法参数类型注入 方式二(将name属性替换为index属性,添加对应的参数位置(0开始)):
1.9.5参数注入方式的选择
1. 强制依赖使用构造器进行,使用 setter 注入有概率不进行注入导致 null 对象出现强制依赖指对象在创建的过程中必须要注入指定的参数2. 可选依赖使用 setter 注入进行,灵活性强可选依赖指对象在创建过程中注入的参数可有可无3. Spring 框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨4. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用 setter 注入完成可选依赖的注入5. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供 setter 方法就必须使用构造器注入6. 自己开发的模块推荐使用 setter 注入
按类型(常用)按名称按构造方法不启用自动装配
在配置文件中,将
例如:
注意事项 :需要注入属性的类中对应属性的 setter 方法不能省略被注入的对象必须要被 Spring 的 IOC 容器管理按照类型在 Spring 的 IOC 容器中如果找到多个对象,会报 NoUniqueBeanDefinitionException
注意事项 :按照名称注入中的名称指的是什么?0bookDao 是 private 修饰的,外部类无法直接方法, 外 部类只能通过属性的 set 方法进行访问对外部类来说, setBookDao 方法名,去掉 set 后首字母小写是其属性名为什么是去掉set首字母小写?这个规则是 set 方法生成的默认规则, set 方法的生成是把属性名首字母大写前面加 set 形成的方法名, 所以按照名称注入,其实是和对应的 set 方法有关,但是如果按照标准起名称,属性名和 set 对 应的名是一致的, 如果按照名称去找对应的 bean 对象,找不到则注入 Null, 当某一个类型在 IOC 容器中有多个对象,按照名称注入只找其指定名称对应的 bean 对象,不会报错两种方式介绍完后,以后用的更多的是按照类型注入。最后对于依赖注入,需要注意一些其他的配置特征 :1. 自动装配用于引用类型依赖注入,不能对简单类型进行操作2. 使用按类型装配时( byType )必须保障容器中相同类型的 bean 唯一,推荐使用3. 使用按名称装配时( byName )必须保障容器中具有指定名称的 bean ,因变量名与配置耦合,不推 荐使用4. 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
常见的集合类型有哪些 ?数组ListSetMapProperties
集合注入的格式:
100
200
300
itcast
itheima
boxuegu
chuanzhihui
itcast
itheima
boxuegu
boxuegu
china
henan
kaifeng