目录
spring的概诉:
Spring的概念:
1.Spring是轻量级的开源的JAVA EE框架
2.Spring可以解决企业应用开发的复杂性
3.Spring有两个核心部分:IOC和Aop
a.IOC:控制反转,把创建对象过程交给Spring进行管理
b.Aop:不修改源代码进行功能增强
Spring的特点:
- 方便解耦,简化开发:通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
- AOP编程的支持:通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。
- 声明式事务的支持:在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
- 方便程序的测试:可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。例如:Spring对Junit4支持,可以通过注解方便的测试Spring程序。
- 方便集成各种优秀框架:Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts,Hibernate、Hessian、Quartz)等的直接支持。
- 降低Java EE API的使用难度:Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低。
- https://repo.spring.io/release/org/springframework/spring/
IOC:
什么是IOC:
- 控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理
- 使用IOC的目的:为了耦合度降低
IOC底层原理:
- xml解析,工厂模式,反射
画图讲解IOC底层原理:
IOC(接口):
- IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
- Spring提供IOC容器实现的两种方式:(两个接口)
- BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用
*BeanFactory加载配置文件的时候不会创建对象,在获取对象(使用)才去创建对象
- ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
*ApplicationContext加载配置文件的时候就会把配置文件对象进行创建
- ApplicationContext接口有实现类
- FileSystemXmlApplicationContext:路径名称需要从盘符开始写全路径。
- ClassPathXmlApplicationContext:xml文件在src目录下,只要写出文件名称就可以
IOC的Bean管理:
Bean管理指的是两个操作:
- Spring创建对象
- Spring注入属性
Bean管理操作有两种方式:
- 基于Xml配置文件方式实现
- 基于注释方式实现
IOC操作Bean管理(基于xml):
基于xml方式创建对象:
- 在spring配置文件中,使用bean标签,标签里面添加对应的属性,就可以实现对象创建
<bean id="user" class="com.atguigu.spring5.User"></bean>
- 在bean标签有很多属性,介绍常用的属性
*id属性:对象的标识(别名)
*class属性:类的全路径(包全路径)
*name属性:和id的作用类似,是对象的一个名称,id不可以使用符号,name可以(一般现在不用name属性)
- 创建对象的时候,默认执行无参构造方法完成对象创建
基于xml方式注入属性:
- DI:依赖注入,就是注入属性
使用set方法进行注入(要先创建对象才能注入属性)
使用有参构造进行注入
(不使用constructor-arg的时候class会报错,因为创建对象默认使用无参构造函数,而现在为有参构造函数,constructor-arg还有一个index表示索引值,0表示第一个参数,1表示第二个参数)。
使用p名称空间注入,可以简化xml配置
IOC操作Bean管理(xml注入其他类型属性):
- 字面量:
(1)null值:
(2)属性包含特殊符号:使用CDATA,XML 文档中的所有文本均会被解析器解析,只有 CDATA 区段中的文本会被解析器忽略。
注意:CDATA 部分不能包含字符串 "]]>"。也不允许嵌套的 CDATA 部分。标记 CDATA 部分结尾的 "]]>" 不能包含空格或换行。
- 注入属性-外部bean
public class UserService{
//创建UserfDao类型属性,生成set方法
private UserDao userDao;
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
public void add(){
System.out.println("service add.......");
userDao.update();
}
}
public interface UserDao{
void update();
}
public class UserDaoImpl implements UserDao{
@Override
public void update(){
System.out.println("service add.......");
}
}
- 注入属性-内部bean
(1)一对多关系:部门和员工,一个部门有多个员工,一个员工属于一个部门。部门是一,员工是多
//部门类
public class Dept{
private String dname;
public void setDname(){
this.dname = dname;
}
//员工类
public class Emp{
private String ename;
private String gender;
private Dept depe;
public void setDept(Dept depe){
this.dept = dept;
}
public void setEname(){
this.Ename = Ename;
}
public void setGender(){
this.gender = gender;
}
public void add(){
System.out.print("def......")
}
}
(使用嵌套给公司类赋值)
- 注入属性-级联赋值:
和内部bean相似,改变配置文件即可
或者在员工类中添加dept的get方法,然后dept修改为<property name="dept.dname" value="技术部"></property>
- 注入属性-集合属性:先设置数组,集合类型的属性,然后设置他们的set方法
(1)注入数组类型属性,可以使用array或者list
(2)注入List集合类型属性,使用list
(3)注入Map集合类型属性,使用map和entry
(4)在集合里面设置对象类型值
(5)把集合属性注入部分提取出来变成公共属性
- 把spring配置文件中引入名称空间
- 使用util标签完成List集合注入提取
IOC操作Bean管理(FactoryBean):
Spring有两种不同类型bean,一种普通bean,另外一种工厂bean(FactoryBean)
- 普通bean:在配置文件中定义的类型就是返回的类型(bean标签里面的class里面的类型是什么测试类中返回的就是什么)
- 工厂bean:在配置文件定义bean类型可以和返回类型不一样
(1)创建类,让这个类作为工厂bean,实现接口FactoryBean
(2)实现接口里面的方法,在实现的方法中定义返回的bean类型
IOC操作Bean管理(bean的作用域):
- 在spring里面,设置创建bean实例默认是单例对象。
- 如何设置bean为单实例或多实例
(1) 在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例
(2)scope属性值有多个,常用有两个。第一个默认值是singleton(表示单实例对象),第二个值是prototype(表示是多实例对象)
- singleton和prototype的区别
- singleton是单实例,prototype多实例
- 设置scope值是singleton时候,加载spring配置文件时候就会创建单实例对象。设置scope值是prototype时候,不是在加载spring配置文件的时候创建对象,在调用getBean方法的时候创建多实例对象
IOC操作Bean管理(bean的生命周期):从对象创建到对象销毁的过程
- 创建bean实例对象(无参数构造)
- 注入属性或者引用其他bean(调用set方法)
- 调用bean的初始化方法(需要进行配置初始化的方法,在bean标签里面使用属性init-method)
- 使用bean(对象获取到了)
- 当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法,在bean标签里面使用属性destory-method,在测试类里面写((ClassPathXmlApplicationContext)context).close()或者context.close())。
注意:bean的后置处理器,bean的生命周期有七步
- 创建bean实例对象(无参数构造)
- 注入属性或者引用其他bean(调用set方法)
- 把bean实例传递给bean后置处理器的方法(postProcessBeforeInitialization(Object bean,String beanName))
- 调用bean的初始化方法(需要进行配置初始化的方法,在bean标签里面使用属性init-method)
- 把bean实例传递给bean后置处理器的方法(postProcessAfterInitialization((Object bean,String beanName)))
- 使用bean(对象获取到了)
- 当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法,在bean标签里面使用属性destory-method,在测试类里面写((ClassPathXmlApplicationContext)context).close()或者context.close())。
后置处理器的配置
IOC操作Bean管理(xml自动装配):
- 什么是自动装配:根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值注入属性
根据属性名称注入
根据属性类型注入
IOC操作Bean管理(外部属性文件):
- 直接配置数据库信息
配置德鲁伊连接池,在项目中导入德鲁伊的jar包
- 引入外部属性文件配置数据库连接池
(1)创建外部属性文件,properties格式文件写数据库信息,在项目中导入德鲁伊的jar包
(2)把外部的properties属性文件引入到spring配置文件中
先引入名称空间:
在spring配置文件使用标签引入外部属性文件
IOC操作Bean管理(基于注解方式):
- 使用注解的目的:简化xml配置
- spring针对bean管理中为创建对象提供四种注解
- @Component
- @Service
- @Controller
- @Repository
- 基于注解方式实现对象创建
(1)引入依赖
(2)开启组件扫描,先引入空间名称,然后扫描包(多个可用逗号隔开,或者扫描包上层目录)
注意:开启组件扫描的细节配置,默认扫描全部,可以自己设置哪些扫描哪些不扫描
(3)创建类,在类上面添加创建对象注解(四个里面的任何一个都可以)
- 基于注解方式实现属性注入(四个常用注解)
(1)@AutoWired:根据属性类型进行自动装配
先给类添加创建对象注解,然后再属性什么使用注解
(2)Qualifier:根据属性名称进行注入(要和@AutoWired一起使用)
先在创建对象的注解里面使用value给类添加一个名称,然后在添加属性的注解中给value添加相同的名称
(3)Resource:可以根据属性类型注入,可以根据属性名称注入(是javax中的一个包)
(4)@Value:注入普通类型属性
- 完全注解开发:(完全不使用xml配置文件)
(1)创建配置类,代替xml配置文件
(2)编写测试类(使用AnnotationConfigApplicationContext(自己创建的配置文件))
AOP:
什么是AOP:
- 面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合性降低,提高程序的可重用性,同时提高开发效率
- 画图介绍什么是AOP ,不通过修改源代码方式,在主干功能里面添加新的功能(在不需要这个功能的时候也可以撤走)
AOP的底层原理:
- AOP底层使用动态代理(有两种情况动态代理)
(1)有接口情况,使用JDK动态代理
(2)没有接口情况,使用CGLIB动态代理
AOP(JDK动态代理):
使用JDK动态代理,使用Proxy类里面的方法创建代理对象。调用newProxyInstance(第一个参数:类加载器。第二个参数:增强方法所在的类,这个类实现的接口,支持多个接口。第三个参数:实现这个接口InvocationHandler,创建代理对象,写增强方法)
AOP(术语):
(1)连接点:类里面哪些方法可以被增强,这些方法称为连接点
(2)切入点:实际被真正增强的方法,称为切入点
(3)通知(增强):实际增强的逻辑部分称为通知
注意:通知有多种类型
*前置通知: 在被增强方法之前执行
*后置通知:在被增强方法之后执行
*环绕通知:在被增强方法之前和之后都会执行
*异常通知:被增强方法出现异常的时候执行
*最终通知:类似于finally,不管有没有异常都会执行
(4) 切面:把通知应用到切入点的过程
AOP操作(准备):
Spring框架一般都是基于AspectJ实现AOP操作(AspectJ不是Spring组成部分,是独立的AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作)
- 基于AspectJ实现AOP操作
(1)基于xml配置文件实现
(2)基于注解方式实现
在项目工程里面引入AOP的相关依赖
切入点的表达式
(1)切入点表达式的作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构:execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))
举例1:对com.atguigu.dao.BookDao类里面的add方法进行增强(execution(*com.atguigu.dao.BookDao.add(..) ))
举例2:对com.atguigu.dao.BookDao类里面的所有方法进行增强(execution(*com.atguigu.dao.BookDao.*(..) ))
举例1:对com.atguigu.dao的所有类里面的所有方法进行增强(execution(*com.atguigu.dao.*.*(..) ))
(重点)AOP操作(AspectJ注解):
(1)使用注解创建类对象,在类里面定义方法
(2)创建增强类(编写增强逻辑),创建方法让不同方法代表不同的通知类型,在增强类上面添加注解@Aspect
(3)进行通知的配置,在spring配置文件中,添加context和aop名称空间,开启注解扫描。在spring配置文件中开启生成代理对象
(4)配置不同类型的通知。在增强类里面,在通知方法上面添加通知类型注解,使用切入点表达式配置
//被增强的类
@Component
public class User{
public void add(){
System.out.println("add......");
}
}
//增强的类
@Component
@Aspect//生成代理对象
public class UserProxy{
//前置通知
//before注解作为前置通知
@Before(value="exeuction(* com.atguigu.spring5.aopanno.User.add(..))")
public void before(){
System.out.println("before....");
}
//最终通知,不管有没有异常都执行
//after注解作为前置通知
@After(value="exeuction(* com.atguigu.spring5.aopanno.User.add(..))")
public void after(){
System.out.println("after....");
}
//@AfterReturning有异常就不执行
@AfterReturning(value="exeuction(* com.atguigu.spring5.aopanno.User.add(..))")
public void afterReturning(){
System.out.println("afterReturning....");
}
//@AfterThrowing注解作为异常通知
@AfterThrowing(value="exeuction(* com.atguigu.spring5.aopanno.User.add(..))")
public void afterThrowing(){
System.out.println("afterThrowing....");
}
//环绕通知
//Around注解作为环绕通知
@Around(value="exeuction(* com.atguigu.spring5.aopanno.User.add(..))")
public void around(){
System.out.println("around之前....");
proceedingJoinPoint.proceed();
System.out.println("around之后....");
}
}
(5)相同的切入点抽取
(6)有多个增强类对同一个方法增强,设置优先级。在增强类上面添加注解@Order(数字类型值),数字类型值越小优先级越高
(7)完全使用注解开发,创建配置类,不需要创建xm文件
AOP操作(AspectJ配置文件):
(1)创建两个类,增强类和被增强类,创建方法
(2)在spring配置文件中创建两个类对象
(3)在spring配置文件中配置切入点
public class Book{
public void buy(){
System.out.println("buy....");
}
}
public class BookProxy{
public void before(){
System.out.println("before....");
}
}
JdbcTemplate
什么是JdbcTemplate :Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作
准备工作:引入相关的jar包,配置数据库连接池,配置JdbcTemplate对象注入DataSource
举例操作:创建service类,dao类。在dao注入JdbcTemplate对象
JdbcTemplate操作数据库(添加,修改,删除类似,这里举例添加):
先在对应数据库创建实体类,然后在dao进行数据库添加操作(调用JdbcTemplate对象里面update(第一个参数是sql语句,第二个是可变参数,设置sql语句值)方法实现添加操作)
测试类和测试结果
JdbcTemplate操作数据库(查询返回某个值):使用JdbcTemplate的queryForObject(String sql,Class<T>requiredType)实现查询返回某个值(第一个参数是sql语句,第二个参数是返回类型class)
JdbcTemplate操作数据库(查询返回对象):使用JdbcTemplate的queryForObject(String sql,RowMapper<T> rowMapper,Object... args)方法查询返回对象(第一个参数是sql语句,第二个参数是接口,返回不同类型数据,使用这个接口的实现类完成数据封装。第三个参数是sql语句的参数值)
JdbcTemplate操作数据库(查询返回集合):使用JdbcTemplate的query(String sql,RowMapper<T> rowMapper,Object... args)方法查询返回对象(第一个参数是sql语句,第二个参数是接口,返回不同类型数据,使用这个接口的实现类完成数据封装。第三个参数是sql语句的参数值)
JdbcTemplate操作数据库(批量操作(对多条记录操作)):使用JdbcTemplate的batchUpdate(String sql,List<Object[]> batchArgs)方法(第一个参数为sql语句,第二个参数为List集合,添加多条记录数据)
这里举例批量添加(修改,添加,删除基本一样)
测试类
事务
什么是事务 :事务是数据库操作最基本单元,逻辑上一组操作要么都成功,如果有一个失败所有操作都失败
事务的特性(ACID):
- 原子性:要么都成功,要么都失败
- 一致性:操作之前和操作之后总量都是不变的
- 隔离性:多事务操作的时候,他们之间不会互相影响
- 持久性:数据提交,表中的数据也随着改变
事务操作(搭建事务操作环境):
(1)创建数据库表,添加记录
(2)创建service,搭建dao,完成对象创建和注入关系(在service注入dao,在dao注入JdbcTemplate,在JdbcTemplate注入DataSource)
(3)上面的代码,正常执行没有问题,但如果代码执行过程中出现异常就会产生问题 ,所以用到事务解决这个问题
事务操作(Spring事务管理介绍):
(1)事务添加到JavaEE三层结构里面的service层
(2)在spring进行事务管理操作有两种方式
- 编程式事务管理
- 声明式事务管理(使用)
(3)声明式事务管理
- 基于注解方式(使用)
- 基于xml配置文件方式
(4)在spring进行声明式事务管理,底层使用AOP原理
(5)spring事务管理API,提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
事务操作(注解声明式事务管理):
(1)在spring配置文件配置事务管理器
(2)在spring配置文件开启事务注解
在spring配置文件引入名称空间tx
开启事务注解
(3)在service类上面(获取service类里面方法上面)添加事务注解@Transactional,这个注解可以添加到类上面,也可以添加到方法上面。如果添加到类上面,表示这个类所有方法都添加事务。如果添加到方法上面,表示为这个方法添加事务
事务操作(声明式事务管理参数配置):
(1)在service类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数
- 第一个参数propagation:事务传播行为(多事务方法直接进行调用,这个过程中事务是如何进行管理的)
- 第二个参数isolation:事务隔离级别(多事务操作之间不会产生影响,不考虑隔离性产生很多问题。有三个读问题:脏读,不可重复读,虚读)
脏读:一个未提交事务读取到另一个未提交事务的数据
不可重复读:一个未提交事务读取到另一提交事务修改数据
虚读:一个未提交事务读取到另一提交事务添加数据
解决:通过设置事务隔离级别,解决读问题
- 第三个参数timeout:超时时间(事务需要在一定时间内进行提交,如果不提交进行回滚,默认值是-1,设置时间以秒单位进行计算)
- 第四个参数readOnly:是否只读(读:查询操作,写:添加修改删除操作,设置值为true后只能查询)
- 第五个参数rollbackFor:回滚(设置出现了哪些异常进行事务回滚)
- 第六个参数noRollbackFor:不回滚(设置出现了哪些异常不进行事务回滚)
事务操作(xml声明式事务管理):配置事务管理器,配置通知,配置切入点和切面
事务操作(完全注解声明式事务管理):创建配置类
spring5框架新功能
- 整个spring5框架的代码基于java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除
- spring5框架自带了通用的日志封装,spring5已经移除了Log4jConfigListener,官方建议使用Log4j2
日志封装步骤:引入jar包,创建log4j2.xml配置文件
- spring5框架核心容器支持@Nullable:该注解可以使用在方法上面,属性上面,参数上面。表示方法返回可以为空,属性值可以为空,参数值可以为空
- spring5核心容器支持函数式风格GenericApplicationContext
- spring5支持整合JUnit5
spring5整合JUnit4
(1)引入spring相关针对测试依赖
(2)创建测试类,使用注解方式完成
spring5整合JUnit5
(1)引入JUnit5的jar包
(2)创建测试类,使用注解方式完成
(3)使用复合注解替代上面的两个注解完成整合
- SpringWebFlux介绍
(1)是Spring5添加新的模块,用于web开发,功能SpringMVC类似的。WebFlux使用当前一种比较响应式编程出现的框架
(2)使用传统web框架,比如springMVC,这些基于servlet容器,webflux是一种异步非阻塞的框架,异步非阻塞的框架在servlet3.1以后才支持,核心是基于reactor的相关API实现的
(3)异步非阻塞:
异步和同步:针对调用者,调用者发送请求,如果等着对方回应之后才去做其他事情就是同步。如果发送请求之后不等对方回应就去做其他事情就是异步
阻塞和非阻塞:针对被调用者,被调用者收到请求之后,做完请求任务之后才给出反馈就是阻塞,收到请求之后马上给出反馈再去做其他事情就是非阻塞
(4)Webflux特点
非阻塞式:在有限的资源下提高系统的吞吐量和伸缩性,以Reactor为基础实现响应式编程
函数式编程:spring5框架基于java8,Webflux使用java8函数式编程方式实现路由请求
(5)比较springMVC
第一两个框架都可以使用注解方式,都运行在Tomcat等日期中
第二pringMVC采用命令式编程,Webflux采用异步响应式编程
- 响应式编程
(1)什么是响应式编程:响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便的表达静态或者动态的数据流,而相关的计算机模型会自动将变化的值通过数据流进行传播
(2)提供的观察者模式两个类Observer和Observable
- 响应式编程(Reactor实现)
(1)响应式编程操作中,Reactor是满足Reactive规范的框架
(2)Reactor有两个核心类M,ono和Flux,这两个类实现接口Publisher,提供丰富操作符,Flux对象实现发布者,返回N个元素;Mono实现翻发布者,返回0个或者1个元素。
(3)Mono和Flux都是数据流的发布者,使用Mono和Flux都可以发出三种数据信号量:元素值,错误信号,完成信号,错误信号和完成信号都代表终止信号,终止信号用于告诉订阅者数据流结束了,错误信号终止数据流同时把错误信息传递给订阅者
(4)代码演示Flux和Mono
(5)三种信号特点
错误信号和完成信号都是终止信号,不能共存
如果没有发送任何元素值,而是直接发送错误或者完成信号量,表示是空数据流
如果没有错误信号量,没有完成信号,表示是无限数据流
(6)调用just或者其他方法只是声明数据流,数据流并没有发出,只有订阅之后才会触发数据流,不订阅什么都不会发生
(7)操作符:对数据流进行一道道操作,成为操作符,比如工厂流水线
第一map元素映射为新元素
第二flatMap元素映射为流,把每个元素转换流,把转换之后多个流合并成大的流
- SpringWebflux执行流程和核心API
SpringWebflux基于Reactor,默认使用容器是Netty,Netty是高性能的NIO框架,异步非阻塞的框架
(1)Netty
BIO
NIO
(2)SpringWebFlux执行过程和SpringMVC相似
SpringWebFlux核心控制器DispatchHandler,实现接口WebHandler
接口WebHandler有一个方法
(3) SpringWebFlux里面DispatchHandler,负责请求的处理
HandlerMapping:请求查询到处理的方法
HandlerAdapter:真正负责请求的处理
HandlerResultHandler:响应结果处理
(4) SpringWebFlux实现函数式编程,两个接口:RouterFunction(路由处理)和HandlerFunction(处理函数)
- SpringWebFlux(基于注解编程模型):实现方式有两种(注解编程模型和函数式编程模型)
使用注解编程模型方式和之前的springMVC使用相类似,只需要把相关依赖配置到项目中,springBoot自动配置相关运行容器,默认情况下使用Netty服务器
(1)创建springBoot工程,引入Webflux依赖
(2)配置启动的端口号
(3)创建包和相关的接口和实现类
(3) 说明
springMVC方式实现,同步阻塞的方式,基于springMVC+Servlet+Tomcat
springWebflux方式实现,异步非阻塞方式,基于springWebflux+Reactor+Netty
- SpringWebFlux(基于函数是编程模型)
(1)在使用函数式编程模型操作的时候,需要自己初始化服务器
(2)基于函数式编程模型时候,有两个核心接口:RouterFunction(实现路由功能,请求转发给对应的handler)和HandlerFunction(处理请求生成响应的函数)。核心任务定义两个函数式接口的实现并且启动需要的服务器
(3)springWebflux请求和响应不再是servletRequest和servletResponse,而是serverRequest和serverResponse
复制SpringWebFlux(基于注解编程模型)的创建包和相关的接口和实现类,修改controller。
初始化服务器编写Router,创建服务器完成适配
最终调用
(4)使用WebClient调用