此篇文章仅记录自己回顾学习笔记,有些许代码不齐,文章可方便学习过的同学快速浏览找到spring5涵盖的基本知识点,如有不足和错误,请大家多多指导
Spring概念
Spring框架概述
1. Spring是轻量级的开源的JavaEE框架
2. Spring可以解决企业应用开发的复杂性
3. Spring有两个核心部分:IOC和AOP
(1)IOC:控制反转,把创建对象过程交给Spring进行管理
(2)AOP:面向切面编程,不修改源代码进行代码增强
4.Spring特点
(1)方便解耦合,简化开发
(2)AOP编程的支持
(3)方便程序的测试
(4)方便和其他框架进行整合
(5)方便进行事务操作
(6)降低API的开发难度
5.选取Spring版本5.x进行学习总结
IOC容器
IOC底层原理
IOC(概念和原理)
1、什么是IOC
(1)控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理
(2)使用IOC的目的:为了耦合度降低
2、IOC底层原理
(1)xml解析、工厂模式、反射
3、画图讲解IOC解析原理
IOC接口(BeanFactory)
1、IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
2、Spring提供IOC容器实现的两种方式:(两个接口)
(1)BeanFactory:IOC容器基本实现,是spring内部的使用接口,一般不提供开发人员进行使用
* 加载配置文件的时候不会创建对象,在获取对象(使用)才去创建对象。
(2)ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
*加载配置文件的时候就会把在配置文件的对象进行创建。(一般把耗时耗资源的在启动之前启动)
3、ApplicationContext接口有两个主要实现类
FileSystemXmlApplicationContext:填写系统磁盘下的xml路径
ClassPathXmlApplicationContext:填写src下的xml路径
IOC操作Bean管理
1、什么是Bean管理
(1)Bean管理指的是两个操作
(2)Spring创建对象
(3)Spring注入属性
2、Bean管理操作有两种方式
(1)基于xml配置文件方式创建
(2)基于注解方式实现
IOC操作Bean管理(基于xml方式)
1、基于xml方式创建对象
(1)在Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
(2)在bean标签有很多属性,介绍常用属性
*id属性:唯一属性
*class属性:类全路径(包类路径)
(3)创建对象的时候,默认也是执行无参数构造方法完成的对象创建
2、基于xml方式注入属性
(1)DI:依赖注入,就是注入属性
第一种注入方式:set方法注入(在Spring配置文件中使用bean创建对象并注入property)
<bean id="book" class="包路径">
<property name="bname" value="zhangsan"></property>
</bean>
第二种注入方式:有参构造注入(constructor-arg)
<bean id="book" class="包路径">
<constructor-arg name="bname" value="zhangsan"></constructor-arg>
<constructor-arg index="1" value="zhangsan"></constructor-arg>
</bean>
(2)p名称空间注入
使用p名称空间注入,可以简化基于xml配置的方式
第一步 添加p名称空间在配置文件中
xmls:p=“http://www.springframework.org/schema/p”
第二步 加入属性
<bean id="book" class="包路径" p:name="" p:author=""></bean>
3、xml注入其他类型属性
(1)字面量
*设置null值
<property name="bname">
<null/>
</property>
*包含特殊符号(<<南京>>)。 1、可以转义,> 2、特殊写到CDATA
<property name="bname">
<value><![CDATA[<<南京>>]]></value>
</property>
4、注入属性---外部bean
(1)创建两个类service类和dao类
(2)在service里调用dao类
(3)在Spring配置文件中配置(name:类中名称,ref其他外部beanid)
<bean id="userService" class="包路径">
<property name="userDao" ref="userDao"></property>
</bean>
<bean id=“userDao” class=“包路径”></bean>
5、注入属性-内部bean
(1)一对多关系:部门和员工(一个部门有多个员工,一个员工属于一个部门,部门是一,员工是多)
(2)在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性表示。
在员工类中有一个属性是部门对象
(3)在Spring配置文件中的配置
<bean id="emp" class="">
<property name="ename" value="lucy"></property>
<property name="egender" value="女"></property>
<property name="dept">
<bean id="dept" class="">
<property name="dname" value="安保部"></property>
</bean>
</property>
</bean>
6、注入属性-级联赋值(自己理解,类似外部bean)
(1)第一种写法
<bean id="emp" class="">
<property name="ename" value="lucy"></property>
<property name="egender" value="女"></property>
<property name="dept" ref=“dept”></property>
</bean>
<bean id="dept" class="">
<property name="dname" value="安保部"></property>
</bean>
(2)第二种写法(此写法需要在emp对象内设置get方法)
<bean id="emp" class="">
<property name="ename" value="lucy"></property>
<property name="egender" value="女"></property>
<property name="dept" ref=“dept”></property>
<property name="dept.dname" value=“财务部”></property>
</bean>
<bean id="dept" class="">
<property name="dname" value="安保部"></property>
</bean>
7、xml注入集合类型
(1)注入数组集合属性
(2)注入List集合属性
(3)注入Map集合属性
第一步 创建类并创建这几种属性
第二部 在Spring配置文件中书写
<bean id="" class="">
<property name="数组名称">
<array>
<value>内容1</value>
<value>内容2</value>
</array>
</property>
</bean>
<bean id="" class="">
<property name="list名称">
<list>
<value>内容1</value>
<value>内容2</value>
</list>
</property>
</bean>
<bean id="" class="">
<property name="map名称">
<map>
<entry key="" value=""></entry>
<entry key="" value=""></entry>
</map>
</property>
</bean>
<bean id="" class="">
<property name="set名称">
<set>
<value>内容1</value>
<value>内容2</value>
</set>
</property>
</bean>
8、在集合里面设置对象类型的值(Spring中配置文件写法)
<bean id="" class="">
<property name="coustLIst">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<bean id="course1" class=“”>
<property name="cname" value="Spring"></property>
</bean>
<bean id="course2" class=“”>
<property name="cname" value="Mybatis"></property>
</bean>
9、把集合类提取出来作为公共。 (将公共部分相当于外部bean注入)
(1)现引入新的命名空间叫做util,可引用其他的复制进行修改
<util:list id="bookList">
<value>西游记</value>
<value>红楼梦</value>
<value>水浒传</value>
</util:list>
<bean id="book" class="">
<property name="list" ref="bookList"></property>
</bean>
IOC操作Bean管理(FactoryBean)
1、Spring中有两种类型Bean,一种是普通bean,另外一种是工厂bean(FactoryBean)
2、普通bean:在配置文件中定义bean类型就是返回类型
3、工厂bean:在配置文件中定义bean类型可以和返回类型不一样
第一步 创建类,让这个类作为工厂bean,实现接口FactoryBean
第二步 实现接口里面的方法,在实现的方法中定义返回的bean类型---泛型
IOC操作Bean管理(bean作用域)
1、在Spring里面设置创建bean实例是单实例还是多实例
2、在Spring默认配置中默认是单实例对象
3、如何设置bean是单实例还是多实例
(1)在Spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例
(2)scope属性值
第一个值 默认值,singleton,表示单实例对象
第二个值 prototype,表示是多实例对象
(3)singleton和prototype区别
第一 singleton单实例,prototype多实例
第二 设置scope值是singleton的时候,加载sping配置文件的时候就会创建单实例对象
设置scope值是prototype的时候,不是在加载spring配置文件的时候创建对象,而是在调用getBean方法的时候创建多实例对象
还有两个属性值
request
session
IOC操作Bean管理(bean的生命周期)
1、生命周期
(1)从对象创建到销毁的过程
2、bean的生命周期
(1)通过构造器创建bean实例(无参数构造)
(2)为bean的属性设置值和对其他bean的引用(调用set方法)
(3)调用bean的初始化的方法
(需要进行配置)在实体类中书写方法,在spring配置文件bean中写init-method=“类中写的初始化方法”
(4)bean可以使用了(对象获取到了)
(5)当容器关闭的时候,调用bean的销毁的方法
(需要配置销毁的方法)在实体类中书写方法,在spring配置文件bean中写destory-method=“类中写的销毁方法”
实际销毁还需要在对象使用完成后主动销毁,在第(4)不调用context.close()方法后,会销毁实例并执行所对应的销毁方法
3、演示生命周期
4、bean的后置处理器,生命周期有7步
添加bean的后置处理器(他会给所有bean都添加上):
实现BeanPostProcessor接口后需要重写2个方法,也就是初始化前(3)和初始化后(5)
(1)通过构造器创建bean实例(无参数构造)
(2)为bean的属性设置值和对其他bean的引用(调用set方法)
(3)把bean实例传递给bean后置处理器的方法(postProcessBeforeInitiallization)
(4)调用bean的初始化的方法
(5)把bean实例传递bean后置处理器的方法(postProcessAfterInitiallization)
(6)bean可以使用了(对象获取到了)
(7)当容器关闭的时候,调用bean的销毁的方法
IOC操作Bean管理(xml自动装配)
1、什么是自动装配
(1)根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
2、自动装配过程
bean标签属性autowire,配置自动装配;autowire属性常用2个值:byName根据属性名称注入,byType根据属性类型注入
(1)根据属性名称自动注入
(2)根据属性类型自动注入
IOC操作Bean管理(引入外部的属性文件)
1、直接配置数据库连接池
(1)配置德鲁伊连接池
(2)导入德鲁伊包,spring配置文件中书bean配置数据库
2、引入外部属性文件配置数据库连接池
(1)创建外部属性文件,properties格式文件,写数据信息
(2)把外部properties属性文件引入spring配置文件中
*引入context命名空间,如上面引入p命名空间一样
*之后在加入如下代码
<context:property-placeholder location="classpath.properties"/>
在配置数据库的bean,value书写${}读取值
IOC操作Bean管理(基于注解方式)
1、什么是注解
(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值...)
(2)使用注解,注解作用在类上面,方法上面,属性上面
(3)使用注解的目的:简化xml配置
2、Spring针对Bean管理中创建对象提供的注解
(1)@Component()
(2)@Service(service)
(3)@Controller(web)
(4)@Repository(dao)
*上面四个注解的功能是一样的,都可以用来创建bean实例
3、基于注解的方式实现对象的创建
第一步 引入依赖 (spring_aop.jar)
第二步 开启组件扫描
*引入context命名空间。然后书写。
<context:component-scan base-package=""></context:component-scan>
base-package书写包名时,可以以多个逗号隔开,或者扫描包上层
第三步 创建类,在类上添加注解
4、开启组件扫描的细节问题
(1)示例1 user-default-filters="false" 表示现在不使用默认filter,自己配置fillter
context:include-filter 设置扫描哪些内容
<context:component-scan base-package="" user-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
(2)示例2。context:exclude-filter 设置不扫描哪些内容
<context:component-scan base-package="">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
5、基于注解方式实现属性注入
(1)@AutoWired:根据属性类型进行自动装配
第一步 把service和dao对象创建,在service和dao类添加创建对象注解
第二步 在service注入dao对象,在service类添加dao类型属性,在属性上面使用注解
(2)@Qualifier:根据名称进行注入
这个注解需要和上面的@AutoWired一起使用
(3)@Resource:可以根据类型注入,可以根据名称注入 是javax中的,建议使用spring同类
(4)@Value:注入普通类型属性
@Value(value="abc")
private String name;
6、纯注解开发. 一般可以用springboot
(1)创建配置类,替代xml配置文件。
@Configuration
@ComponentScan(basePackages={'包名'})
public class SpringConfig(){}
(2)加载配置类
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
AOP
AOP(概念)
1、什么是AOP
(1)面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发效率。
(2)通俗描述:不通过修改源代码的方式,在主干功能里面添加新的功能。(登陆过程中添加权限判断)
AOP(底层原理)
1、AOP底层使用动态代理
(1)有两种情况动态代理
第一种 有接口的情况,使用JDK动态代理
- 创建接口实现动态代理,增强类的方法
第二种 没有接口的情况,使用CGLIB动态代理
- 创建子类的代理对象,增强类的方法
AOP(JDK动态代理)
1、使用JDK动态代理,使用Proxy类里面的方法创建代理对象
(1)调用java.lang.reflect中的Proxy类中的newProxyInstance方法
方法有三个参数:
第一参数,类加载器
第二参数,增强方法所在的类,这个实现的接口,支持多个接口
第三参数,实现这个接口InvocationHandler,创建代理对象,写增强的方法
2、编写JDK动态代理代码
(1)创建接口,书写接口方法
public interface userDao{
public int add(int a,int b);
public String update(String id);
}
(2)创建实现类实现接口
public class userDaoImpl implements userDao{
public int add(int a,int b){
return a+b;
}
public String update(String id){
return id;
}
}
(3)创建Proxy代理对象
public class JDKProxy{
public static void main(String[] args){
//创建接口代理对象
Class[] interfaces = {UserDao.class}
UserDaoImpl userDao = new UserDapImpl();
UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDaoProxy(userDao));
int result = dao.add(1,2);
System.out.println("result:"+result);
}
class UserDaoProxy implements InvocationHander{
//把创建的是谁的代理对象,把谁传过来
//有参数构造传递
private Object obj;
public UserDaoProxy(Object obj){
this.obj = obj;
}
//增强的逻辑
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
System.out.println("方法之前执行。。:"+method.getName()+"传递的参数。。。:"+Arrays.toString(args));
Object res = method.invoke(obj, args);
System.out.println("方法之后执行");
return res;
}
}
}
AOP(术语)
1、连接点(类里面的那些方法可以被增强,这些方法称为连接点)
2、切入点(实际被真正增强的方法,称为切入点)
3、通知(增强)
(1)(实际增强的逻辑部分称为通知(增强))
(2)通知有多种类型
*前置通知
*后置通知
*环绕通知
*异常通知
*最终通知 finally
4、切面(是动作)
(1)把通知应用到切入点的过程
AOP操作(准备)
1、Spring框架中一般基于AspectJ实现AOP操作
(1)什么事AspectJ
*AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作
2、基于AspectJ实现AOP操作
(1)基于xml配置文件实现
(2)基于注解方式实现(使用)
3、在项目工程中引入AOP相关依赖
4、切入点表达式
(1)切入点表达式作用:知道对那个类里面的那个方法进行增强
(2)语法结构
execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))
举例1:对com.hc.dao.bookDao类里面的add进行增强
execution(* com.hc.dao.bookDao.add(..))
举例2:对com.hc.dao.bookDao类里面的所有方法进行增强
execution(* com.hc.dao.bookDao.*(..))
举例3:对com.hc.dao所有类里面的所有方法进行增强
execution(* com.hc.dao.*.*(..))
AOP操作(AspectJ注解)
1、创建类(被增强类),在类里面定义方法
public class User {
void add(){
System.out.println("add...");
}
}
2、创建增强类(编写增强逻辑)
(1)在增强类里面,创建方法,让不同方法代表不同通知类型
//增强的类
public class UserProxy(){
//前置通知
void before(){
System.out.println();
}
}
3、进行通知的配置
(1)在spring配置文件中,开启注解扫描
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop:"http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 开启注解扫描 -->
<context:component-scan base-package="被扫码的包路径"></context:component-scan>
(2)使用注解创建User和UserProxy对象
//被增强的类
@Component
@Aspect //注解的作用是生成代理对象
public class UserProxy{
public void before(){
System.out.println("before......");
}
}
(3)在增强类上面添加注解@Aspect 如(2)中
(4)在spring配置文件中开启生成代理对象
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4、配置不同类型的通知
(1)在增强类里面,在作为
@Component
@Aspect //注解的作用是生成代理对象
public class UserProxy{
//前置通知
@Before(value="execution(* com.hc.dao.User.add(..))")
public void before(){
System.out.println("before......");
}
//返回通知
@AfterReturning(value="execution(* com.hc.dao.User.add(..))")
public void afterReturning(){
System.out.println("afterReturning......");
}
//后置通知
@After(value="execution(* com.hc.dao.User.add(..))")
public void after(){
System.out.println("after......");
}
//异常通知
@AfterThrowing(value="execution(* com.hc.dao.User.add(..))")
public void afterThrowing(){
System.out.println("afterThrowing......");
}
//环绕通知
@Around(value="execution(* com.hc.dao.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
System.out.println("环绕之前......");
proceedingJoinPoint.proceed();
System.out.println("环绕之后.....");
}
}
5、相同切入点的抽取
@Pointcut(value="execution(* com.hc.dao.User.add(..))")
public void pointdemo(){
}
@Before(value="pointdemo()")
public void before(){
System.out.println("before......");
}
6、多个增强类对同一个方法进行增强,设置增强了类优先级
(1)在增强类上面添加注解@Order(数值类型值),数字类型值越小优先级越高
@Component
@Aspect
@Order(1)
public class PersonProxy{}
7、完全使用注解开发
(1)创建配置类,不需要创建xml配置文件
@Configuration
@ComponentScan(basePackages={"com.hc"})
@EnableAspectJAutoProxy(proxyTargetClass= true)
public class ConfigAop{}
AOP操作(AspectJ配置文件-了解)
1、创建两个类,增强类和被增强类,创建方法
2、在Spring配置文件中创建两个类对象
3、在spring配置文件中配置切入点
<aop:config>
<!-- 切入点 -->
<aop:ponintcut id="p" expression="execution(* com.hc.dao.User.add(..))"/>
<!-- 配置切面 -->
<aop:aspect ref=“spring中配置的要增强的类的bean的id”>
<!-- 增强作用在具体方法上 -->
<aop:before method=“before” pointcut-ref=“p”></aop:before>
</aop:aspect>
</aop:config>
Jdbc Template
JdbcTemplate(概念和准备)
1、什么是JdbcTemplate
(1)Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作
2、准备工作
(1)引入依赖(相比之前多出的依赖)
druid.jar;
mysql-connector-java.jar;
spring-jdbc.jar
spring-tx.jar(事务依赖)
spring-orm.jar(若是集成其他框架的依赖)
(2)在spring配置文件中配置数据库连接池
<!-- 数据库连接池配置 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destory-method="close">
<property name="url" value="jdbc:mysql:localhost:3306/user_db"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
</bean>
(3)配置JdbcTemplate对象,注入DataSource
<!-- JdbcTemplate对象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemple">
<property name="dataSource" ref="dataSource"></property>
</bean>
(4)创建service类,创建dao类,在dao注入jdbcTemplate对象
*配置文件中
<context:component-scan base-package="com.hc"></context:component-scan>
@Service
public class BookService{
@Autowired
private BookDao bookDao;
}
@Repository
public class BookDaoImpl implements BookDao{
//注入jdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
}
public interface BookDao(){
}
JdbcTemplate操作数据库(添加修改和删除)
1、对应数据库创建实体类
2、编写service和dao(见上一模块)
(1)在dao进行数据库添加操作
(2)调用JdbcTemplate对象里面update方法实现添加修改和删除操作
jdbcTemplate.update(string sql,object obj)
第一个参数:sql语句--根据书写不同的sql来执行不同的操作
第二个参数:参数值对象,可变参数
JdbcTemplate操作数据库(查询返回某个值)
1、查询表里面有多少条记录,返回是 某个值
2、queryForObject有两个参数,一个是sql语句,一个是查询值的返回类型
jdbcTemplate.queryForObject(string sql,Integer.class);
JdbcTemplate操作数据库(查询返回对象)
1、场景:查询图书详情
2、jdbcTemplate实现查询:调用含有三个参数的queryForObject
RowMapper:是接口,针对返回不同类型数据,使用这个接口里面实现类完成数据封装
jdbcTemplate.queryForObject(sql语句,new BeanPropertyRowMapper<Book> Book.class,sql语句值)
JdbcTemplate操作数据库(查询返回集合)
1、场景:查询图书列表分页
2、jdbcTemplate实现查询:调用query,返回的是list集合
RowMapper:是接口,针对返回不同类型数据,使用这个接口里面实现类完成数据封装
jdbcTemplate.query(sql语句,new BeanPropertyRowMapper<Book> Book.class,sql语句值)
JdbcTemplate操作数据库(批量操作)
1、批量操作:操作表里面多条记录
2、JdbcTemplate实现批量添加
JdbcTemplate.batchUpdate(String sql,List<Object[]> batchArgs)
两个参数:一个sql语句。第二个参数:List集合,添加多条记录数据
3、JdbcTemplate实现批量修改删除
JdbcTemplate.batchUpdate
JdbcTemplate.batchDelete ---传id集合
事务
事务概念
1、什么是事务
(1)事务是数据库操作最基本的单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败
(2)典型场景:银行转账
*lucy转账100元给mary
*lucy少100元,mary多100元
2、事务四个特性(ACID)
(1)原子性(成功都成功,失败都失败)
(2)一致性(总量不变)
(3)隔离性(多个事务之间不会产生影响)
(4)持久性(操作完成后,表中的数据要发生变化)
事务操作(搭建事务操作环境)
转账操作:
Service(业务操作):调用的2个方法
Dao(操作数据库):少钱的方法;多钱的方法
1、创建数据库表,添加记录
2、创建service,搭建dao,完成创建对象和注入关系
(1)service注入dao,在dao注入jdbcTemplate,在jdbcTemplate注入DataSource
3、在dao创建两个方法:多钱和少钱的方法,在service创建方法(转账的方法)
//业务层
@Service
public class UserService {
@Autowried
private UserDao userDao;
public void accountMoney(){
userDao.reduceMoney();
userDao.addMoney();
}
}
//数据库操作层
@Repository
public class UserDaoImpl implements UserDao{
@Autowried
private JdbcTemplate jdbcTemplate;
public void reduceMoney(){
String sql = "update 表名 set user_money = user_money-? where user_name=?";
jdbcTemplate.update(sql,100,"lucy");
}
public void addMoney(){
String sql = "update 表名 set user_money = user_money+? where user_name=?";
jdbcTemplate.update(sql,100,"mary");
}
}
//调用层
@Test
public class test(){
ApplicationContextLocation context = new ClassPathXmlApplicationContext("spring的配置文件在src下的路径");
UserService userService = context.getBean("userService",UserService.class);
userService.accountMoney();
}
4、上面代码,如果正常执行是没有问题的,假如出现异常,
@Service
public class UserService {
@Autowried
private UserDao userDao;
public void accountMoney(){
try{
//第一步 开启事务
//第二步 进行业务操作
userDao.reduceMoney();
//中间模拟异常
int i= 10/0;
userDao.addMoney();
//第三步,没有异常提及事务
}catch{
//第四步,出现异常,事务回滚
}
}
}
事务操作(Spring事务管理介绍)
1、事务添加到javaEE三层结构里面的Service层(业务逻辑层)
2、在Spring进行事务管理操作
(1)有两种方式:声明式事务管理(常用)和编程式事务管理(try catch)
3、声明式事务管理
(1)基于注解方式(常用)
(2)基于xml配置文件方式
4、在Spring进行声明式事务管理,底层使用AOP原理
5、Spring事务管理API
(1)提供了一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
事务操作(注解声明式事务管理)
1、在Spring配置文件中配置事务管理器
<!-- 创建事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.dattaSource.DataSourceTransactionManager">
<!-- 注入数据源 -->
<property name=“dataSource” ref=“dataSource”></property>
</bean>
2、在spring配置文件,开启事务注解
(1)在spring配置文件中引入事务名称空间(详见上面内容)
(2)开启事务注解
<!-- 开启事务注解 -->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
3、在service类上面(获取service类里面方法上面)添加事务注解
(1)@Transactional,这个注解添加到类上面,也可以添加方法上面
(2)如果把这个注解添加类上面,这个类里面的所有方法都添加事务
(3)如果把这个注解添加方法上面,为这个方法添加事务。
@Service
@Transactional
public class UserService{}
事务操作(声明式事务管理参数配置)
1、在service类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数
2、propagation:事务传播行为
(1)多事务方法直接进行调用,这个过程中事务是如何进行管理的
*事务方法:对数据库表数据进行变化的操作
*spring框架事务传播行为有7种
REQUIRED:如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行。
REQUIRED_NEW:当前的方法必须启动新事务,并在它自己的事务内运行。如果有事务正在运行,应该将它挂起
SUPPORTS:如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中
NOT_SUPPORTED:当前的方法不应该运行在事务中,如果有运行的事务,将它挂起
MANDATORY:当前的方法必须运行在事务内部,如果没有正在运行的事务,就抛出异常
NEVER:当前的方法不应该运行在事务中。如果有运行的事务,就抛出异常
NESTED:如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行
3、ioslation:事务隔离级别
(1)事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离型产生很多问题
(2)有三个读问题:脏读、不可重复度、虚(幻)读
(3)脏读:一个未提交事务读取到另一个未提交的事务
(4)不可重复读:一个未提交事务读取到另一个已提交的数据
(5)虚读:一个未提交的事务读取到另一提交事务添加数据
(6)解决:通过设置事物的隔离级别,解决读的问题
脏读 | 不可重复读 | 幻读 | |
---|---|---|---|
READ UNCOMMITTED(读未提交) | 有 | 有 | 有 |
READ COMMITTED(读已提交) | 无 | 有 | 有 |
REPEATABLE READ(可重复读) | 无 | 无 | 有 |
SERIALIZABLE(串行化) | 无 | 无 | 无 |
REPEATABLE READ mysql默认
@Service
@Transactional(propagation = Propagation.REQUIRED,isolation=Isolation.REPEATABLE_READ)
public class UserService{}
4、timeout:超时时间
(1)事务需要在一定的时间内进行提交,如果不提交进行回滚
(2)默认值是-1,设置时间以秒单位进行计算
5、readOnly:是否只读
(1)读:查询操作,写:添加修改删除操作
(2)readOnly默认值false,表示可以查询,可以添加修改删除操作
(3)设置readOnly值是true,设置成true之后,只能查询
6、rollbackFor:回滚
(1)设置查询哪些异常进行事务回滚
7、norollbackFor:不回滚
(1)设置出现哪些异常不进行事务回滚
事务操作(XML声明式事务管理)
1、在Spring配置文件中进行声明
第一步 配置事物管理器
<!-- 创建事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.dattaSource.DataSourceTransactionManager">
<!-- 注入数据源 -->
<property name=“dataSource” ref=“dataSource”></property>
</bean>
第二步 配置通知
<!-- 配置通知 -->
<tx:advice id="txadvice">
<!-- 配置事务参数 -->
<tx:attributes>
<!-- 指定哪种规则的方法上面添加事务 -->
<tx:method name="accountMoney" propagation="REQUIRED"/>
<!--<tx:method name="account*"/>-->
</tx:attributes>
</tx:adivce>
第三步 配置切入点和切面
<!-- 配置切入点和切面 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut id="pt" expression="execution(* com.hc.UserServcie.*(..))"/>
<!-- 配置切面 -->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>
事务操作(完全注解声明式事务管理)
1、创建配置类,使用配置类替代xml配置文件s
Spring5框架
Spring5新功能
1、整个Spring5框架的代码基于Java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除
2、Spring5.0框架自带了通用的日志封装
(1)Spring5已经移除Log4jConfigListener,官方建议使用Log4j2
(2)Spring5框架整合Log4j2
第一步 引入jar包
log4j-api-2.11.2.jar
log4j-core-2.11.2.jar
log4j-slf4j-impl-2.11.2.jar
slf4j-api-1.7.30.jar
第二步 创建log4j2.xml文件
3、Spring5框架核心容器部分支持@Nullable注解
(1)@Nullable注解可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以为空,参数值可以为空
(2)注解用在方法上面,方法返回值可以为空
(3)注解使用在方法参数里面,方法参数可以为空
(4)注解使用在属性上面,属性值可以为空
4、Spring5核心容器支持函数式风格GenericApplicationContext
@Test
public void testGenericApplicationContext(){
//创建GenericApplicationContext对象
GenericApplicationContext context = new GenericApplicationContext();
//调用context的方法对象注册
context.refresh();
context.registerBean("user1",User.class,() -> new User());
//获取在spring注册的对象
User user = (User)context.getBean("user1");
System.out.println(user);
}
5、Spring5支持整合JUnit5
(1)整合Junit4
第一步 引入Spring相关针对测试依赖
spring-test-5.2.6.jar
JUnit4的jar
第二步 创建测试类,使用注解方式完成
@RunWith(SpringJUnit4ClassRunner.class). //单元测试框架
@ContextConfiguration("classpath:bean1.xml") //加载配置文件
public class JTest4{
//这里可以直接注入
}
(2)Sping5整合JUnit5
第一步 引入JUnit5的jar包
第二步 创建测试类,使用注解方式完成
@ExtendWith(SpringExtension.class)
@ContextConfigration("classpath:bean1.xml")
public class JTest5{}
(3)使用一个复合注解替代上面两个注解完成整合
@SpringJUnitConfig(locations = "classpath:bean1.xml")
public class JTest5{}
Spring5Webflux
1、SpringWebflux介绍
基于SpringMVC、SpringBoot、Maven、Java8新特性(不了解的,可以先去了解哈)
(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等容器中
第二 SpringMVC采用命令式编程,Webflux采用异步响应式编程
2、响应式编程
(1)什么是响应式编程
响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。
电子表格程序就是响应式编程的一个例子。单元格可以包含字面值或类似“B1+C1”的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化。
(2)Java8及其之前版本
*提供的观察者模式两个类Observer和Observable
public class ObserverDemo extends Observable{
public static void main(String[] args){
ObserverDemo observer = new ObserverDemo();
//添加观察者
observer.addObserver((o,org)->{
System.out.println("发生变化");
});
observer.addObserver((o,org)->{
System.out.println("手动被观察者通知,准备改变");
});
observer.setChanged(); //数据变化
observer.notifyObservers();//通知
}
}
3、响应式编程(Reactor实现)
(1)响应式编程操作中,Reactor是满足Reactive规范框架
(2)Reactor有两个核心类,Mono和Flux,这两个类实现接口Publisher,提供丰富操作符。Flux对象实现发布者,返回N个元素;Mono实现发布者,返回0或者1个元素
(3)Flux和Mono都是数据流的发布者,使用Flux和Mono都可以发出三种数据信号:元素值,错误信号,完成信号,错误信号和完成信号都代表终止信号,终止信号用于告诉订阅者数据流结束了,错误信号终止数据流同时把错误信息传递给订阅者
(4)代码演示Flux和Mono
第一步 引入依赖
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.1.5.RELEASE</version>
</dependency>
第二步 编程代码
public static void main(String[] args){
//just方法直接声明
Flux.just(1,2,3,4);
Mono.just(1);
//其他的方法
Integer[] array = {1,2,3,4};
Flux.fromArray(array);
List<Integer> list = Arrays.asList(array);
Flux.fromIterable(list);
Stream<Integer> stream = list.stream();
Flux.fromStream(stream);
}
(5)三种信号特点
*错误信号和完成信号都是终止信号,是不能共存的
*如果没有发送任何元素值,而是直接发送错误或者完成信号,表示是空数据流
*如果没有错误信号,没有完成信号,表示是无限数据流
(6)调用just或者其他方法只是声明数据流,数据流并没有发出,只有进行订阅之后才会触发数据流,不订阅什么都不会发生的
//just方法直接声明
Flux.just(1,2,3,4).subscribe(System.out::println);
Mono.just(1).subscribe(System.out::println);
(7)操作符
*对数据流进行一道道操作,成为操作符,比如工厂流水线
第一 map 元素映射为新元素
第二 flatMap元素映射为流
把每个元素转化为流,在整合为一个大流进行返回
4、SpringWebflux执行流程和核心API
SpringWebflux基于Reactor,默认使用容器是Netty,Netty是高性能NIO框架,异步非阻塞的框架
(1)Netty
*BIO
*NIO
(2)SpringWebflux执行过程和SpringMVC相似的
*SpringWebflux核心控制器DispatcherHandler,实现接口WebHandler
*接口WebHandler里面有一个方法
(3)SpringWebflux里面DispatcherHandler,负责请求的处理
*HandlerMapping:请求查询到处理的方法
*HandlerAdapter:真正负责请求处理
*HandlerResultHandler:响应结果处理
(4)SpringWebflux实现函数式编程,两个接口:RouterFunction(路由处理)和HandlerFunction(处理函数)
5、SpringWebflux(基于注解编程模型)
SpringWebflux实现方式有两种:注解编程模型和函数式编程模型
使用注解编程模型方式,和之前SpringMVC使用相似,只需要把相关依赖配置到项目中,SpringBoot自动配置相关运行容器,默认情况下使用Netty容器
第一步 创建SpringBoot项目,引入依赖
第二步 配置启动端口号
第三步 创建包和其他类
https://www.bilibili.com/video/BV1Vf4y127N5?p=58&spm_id_from=pageDriver
*说明
Springmvc方式实现,同步阻塞方式,基于SpringMVC+Servlet+Tomcat
SpringWebflux方式实现,异步非阻塞方式,基于SpringWebflux+Reactor+Netty
6、SpringWebflux(基于函数式编程模型)
(1)在使用函数式编程模型操作的时候,需要自己初始化服务器
(2)基于函数式编程模型的时候,有两个核心接口:RouterFunction(实现路由功能,请求转发给对应的handler)和handlerFunction(处理请求生成响应的函数)。核心任务定义两个函数式接口的实现并且启动需要的服务器。
未完待续。。。