java框架学习之spring基础
文章目录
前言
自己学习spring时总结的一些知识点笔记
内容来源于动力节点王妈妈,带你走进spring,学会spring的简单使用
一、容器中的对象
- 放入容器中的对象:
- dao类,service类,controller类,工具类
- String中的对象默认都是单例的,在容器中叫这个名字的对象只有一个
- 不放入容器中的对象:
- 实体类对象,实体类数据来自于数据库
- servlet,listener,filter是由tomcat服务器这个容器进行创建的
- 把对象放入容器中的方法:
- 使用xml的配置文件,使用bean标签
- 注解
二、关于IOC的理解
- 目的:减少对代码的改动,实现不同的功能
- ioc的使用实现技术为:di(依赖注入):只需要提供对象的名称,对象的查找,创建,赋值都是交给容器来完成
- 控制反转,把对象的创建,赋值,管理工作都交给代码之外的容器去实现,也就是对象的创建由其他的外部资源进行实现
- 控制:创建对象,对象的属性赋值,对象之间的关系管理
- 反转:原来的开发人员管理,创建对象的权限转移给代码之外的容器去实现,由容器来管理对象的创建以及给属性赋值
三,spring的实现步骤:
-
新建maven项目
-
加入maven的依赖
- spring的依赖
- junit的依赖
-
创建类
-
创建spring需要使用的配置文件
- 声明类的信息,这些信息由spring创建和管理
-
spring配置文件的介绍(applicationContext.xml):
-
<!-- 声明bean,告诉spring创建某个类的对象 id :对象的自定义名称,唯一值(Spring通过这个名称找到对象) class :类的全限定名称,(不能是接口也,因为spring底层用的反射来创建的对象) 创建对象:SomeService someService = new ServiceImpl(); spring 把创建好的对象放入map集合中, 一个bean声明一个对象 --> <bean id="someService" class="org.powernode.service.impl.ServiceImpl"/>
-
spring创建对象的步骤:
-
spring创建非自定义类的对象:
- 在spring配置文件中指定id和class=“类的全限定类名”,就可以
-
在创建spring容器对象时,会创建配置文件中所有的对象
-
// 1,指定spring配置文件的名称 String config = "beans.xml"; // 2,创建表示spring容器的对象,ApplicationContext(表示spring容器,通过这个容器可以获取对象) ApplicationContext application = new ClassPathXmlApplicationContext(config); // 3,new ClassPathXmlApplicationContext(“文件的路径”); 表示从类路径中加载spring配置文件,创建出来的对象需要指定其类型 // * application.getBean("someService"); 参数为配置文件中id值 SomeService someService =(SomeService) application.getBean("someService");
-
-
获取容器中java对象信息的api
-
// 获取容器中对应的对象的数量 int count = application.getBeanDefinitionCount(); // 获取每个定义的对象的名称 String[] applicationName = application.getBeanDefinitionNames();
在spring的配置文件中,给java对象赋值:
- di: 依赖注入,表示创建对象,给属性赋值。
- di的实现语法有两种:
- 在spring的配置文件中,使用标签和属性完成,基于xml的di实现
- 在spring中的注解,完成对属性的赋值。
- di的语法分类:
set注入(设置注入):spring调用类的set方法,在set方法中实现对属性的赋值
-
在spring的配置文件中:
-
<bean id="myStudent" class="org.powernode.service.SomeService" > <!--多个属性,多个property标签--> <property name="属性名字" value="属性值"/> <!--找的时name属性对应的set方法--> </bean> ----------------------------- 一个bean代表一个java对象
-
设值注入的注意事项:
- 属性的类型是简单类型
- 需要在java类中设置set方法(set方法在无参构造方法执行之后执行的)
- 方法不管是不是程序员自己写的,只要有set方法在spring配置文件中,就会被执行
-
引用数据类型的赋值:
-
<!-- <bean id="xxx" class="yyy"> <properties name="属性名称" ref="bean的id(就是对象的名称)"/> </bean> -->
-
例子:
-
<!-- 引用类型的set注入--> <bean id="myStudent" class="org.powernode.service.impl.StudentImpl"> <property name="name" value="lisi"/> <property name="age" value="22"/> <property name="school" ref=""/> </bean> <bean id="mySchool" class="org.lirunxin.powernode.service.impl.SchoolImpl"> <property name="name" value="海淀"/> <property name="address" value="xxx"/> </bean>
构造注入,spring调用有参类的构造方法,创建对象,在构造方法中完成对属性的赋值
-
spring调用类的带参构造方法的同时,在创建对象的同时,在构造方法中给属性赋值。
-
<!--构造注入在bean中使用<constructor-arg>标签 一个该标签表示一个构造方法的一个参数--> <constructor-arg>标签的属性: name : 表示构造方法的形参名 index : 表示构造方法参数的位置,参数下标从0开始 index可以省略,但是省略以后必须按照顺序写 value :构造方法的形参类型是简单类型,使用value赋值 ref : 构造方法的形参是引用类型 ,使用ref来进行赋值 ----------------------------------------------------------------- <bean id="myStudent" class="org.powernode.service.impl.StudentImpl"> <constructor-arg name="myName" value="张三"/> <constructor-arg name="myAge" value="20"/> <constructor-arg name="mySchool" ref="mySchool"/> </bean> <bean id="mySchool" class="org.powernode.service.impl.SchoolImpl"> <property name="name" value="海淀"/> <property name="address" value="xxx"/> </bean>
-
构造注入创建文件对象:
-
<bean id="myFile" class="java.io.File"> <constructor-arg name="parent" value="C:\Users\Desktop"/> <constructor-arg name="child" value="chengyu.txt"/> </bean>
-
引用类型的自动注入:
-
只对引用类型的数据有效
-
byName(按名称注入)
- Java类中引用类型的属性名和spring容器中(配置文件)的bean中的id值一样
- 并且数据类型一致,这样的容器中的bean,spring能够赋值给引用类型
-
语法:
-
<bean id="xx" class="yyy" autowire="byName"> 简单数据类型的属性赋值 </bean> --------------------------------------------------- <bean id="myStudent" class="org.powernode.service.impl.StudentImpl" autowire="byName"> <constructor-arg name="name" value="张三"/> <constructor-arg name="age" value="20"/> <!--<constructor-arg name="school" ref="mySchool"/>--> </bean> <!--必须保证属性名和id值一样---> <bean id="school" class="org.powernode.service.impl.SchoolImpl"> <property name="name" value="海淀"/> <property name="address" value="xxx"/> </bean>
-
byType(按照类型进行注入):
-
java类中引用数据类型和spring容器中(配置文件)bean的class属性是同源关系的,这样的bean能够赋值给引用数据类型
-
同源
- java类中的引用数据类型的数据类型和bean中的class值是一样的
- java类中的引用数据类型的数据类型和bean的class的值是父子关系的
- java类中的引用数据类型的数据类型和bean的class的值是接口和实现类关系的
-
语法:
-
<bean id="xx" class="yyy" autowire="byType"> 简单数据类型的属性赋值 </bean>
注意: 在xml配置文件中,声明bean只能有一个符合条件的
-
-
配置文件的使用:
使用多配置文件的原因:
-
每个文件的大小比一个文件的要小,效率高
-
避免多人竞争带来的冲突
-
多文件的分配方式:
- 按功能模块,一个模块一个配置文件
- 按类的功能,数据库相关的配置一个配置文件,做事务的功能一个配置文件,做service的一个配置文件
- 按功能模块,一个模块一个配置文件
-
total.xml表示主配置文件:
-
主配置文件是包含其他的配置文件,并且主配置文件一般不定义对象
-
语法:
-
<import resource="其他配置文件的路径"/> 关键字: "classpath:" 表示类路径,(class文件所在的目录), 在spring的配置文件要指定其他配置文件的位置 需要使用classpath,告诉spring到哪里去加载读取文件 ---------------------------------------------------------------------- 实例: <import resource="classpath:ba06/spring-school.xml"/> 在包含关系的配置文件中,可以使用通配符("* : 表示任意字符") <import resource="classpath:ba06/spring-*.xml"/>
-
基于注解的DI:
-
使用注解的步骤:
- 加入maven的依赖,加入spring-context的同时,间接的加入了spring-aop的依赖,使用注解必须使用spring-aop依赖
- 在spring中加入注解,(多个不同功能的注解)
- 在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你项目中的位置。
-
注解类型:
-
@Component(value = "myStudent") 注解的作用: 创建对象,相当于xml文件中的bean的功能 属性:value(可以省略)指明对象的名称,就是bean的id值,value值是唯一的 创建的对象在整个spring容器中就只有一个 位置:在实体类的上边,表示创建创建本类的对象 @Component : 没有指定value的话spring会提供默认的对象名称: 类名的首字母小写 然后在applicationContext.xml文件中声明组件扫描器 base-package : 指定注解在你项目中的包名 <context:component-scan base-package=""/>
-
和@Component功能相似的其他几个:
-
@Repository(持久层):放在dao的实现类上面,表示创建dao对象,dao是对象是能够访问数据库的。
-
@Service(业务层) :放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务等功能的。
-
@Controller(用在控制器上面的) :放在控制器类的上面,创建控制器对象。能够接收用户提交的参数,显示请求的处理结果
以上的三个注解使用的语法和@Component一样的,都能创建对象,但是三个注解还有额外的作用
-
-
扫描多个包的方式:
-
使用多次的组件扫描器标签,指定不同的包
-
使用分隔符(;或者,)分隔多个包名
-
<context:component-scan base-package="com.powernode.ba01;com.powernode.ba02"/>
-
指定父包:
-
<context:component-scan base-package="com.powernode"/>
-
-
-
简单类型的属性赋值:
-
@value(简单类型的属性赋值):
-
属性: value是String类型的,表示简单数据类型的属性值
-
位置:在属性定义的上面,无需set方法(常用)或者是在set方法的上面
-
例子:
-
@Value(value = "李四") private String name; @Value(value = "29") private Integer age;
-
-
-
-
引用类型
-
/** * 给引用类型赋值 * @Autowired : spring 框架提供的注解,实现引用数据类型的赋值 * spring中通过注解给引用类型赋值,使用的是自动注入原理 * 默认使用的是byType自动注入 * 位置:在属性定义的上面,无需set方法, 推荐使用 * 在set方法上 */ @Autowired private School school; ======================== @Autowired的byName 1,在属性的上面加入@Autowired 2,需要在属性的上面加入@Qualifier(value="bean的id") : 表示使用的指定的名称完成赋值 例子: @Autowired @Qualifier(value = "mySchool") private School school;
-
引用类型Autowired的required属性:
- required是一个bool类型的,默认为true : 引用类型赋值失败,程序报错,并且终止执行(在项目中使用,可以暴露错误,尽快的解决问题)。
- 当required=false时, 引用类型赋值失败,程序不会报错,但是输出结果中引用类型的结果为null
-
JDK中的注解@Resource自动注入
-
来自jdk中的注解,spring框架提供了注解的功能支持,可以使用她给引用类型进行赋值,使用的原理为自动注入 支持byName,byType,默认的是byName 位置:1,在属性的上面,无需set方法 2,在set方法上面 先使用byName进行自动注入,如果byName赋值失败,再使用byType @Resource private School school; // 只使用byName的方式 @Resource(name="mySchool") private School school;
配置文件和注解的方式的选择:
需要经常修改的就使用xml文件配置,不需要经常修改的使用注解
动态代理:
- 动态代理:
- 在程序执行的过程中,创建代理对象,通过代理对象执行方法,给目标的类的方法增加额外的功能。
- 动态代理的作用:
- 在目标源代码不变的情况下,增加功能。
- 减少代码的重复。
- 让开发专注于逻辑业务。
- 解耦合,让业务功能和非业务功能分开。
aop
-
使用时机:
- 当要给系统本来存在的类修改功能,但是类的功能不完善,并且我们没有源代码,使用aop增强功能
- 要给系统的多个类增加一个相同的功能,使用aop
- 给业务方法增加事务,日志输出
-
面向切面编程,基于动态代理的,可以使用jdk,cglib两种动态代理的方式。
-
aop就是动态代理的规范化,把动态代理的实现方式和步骤定好了,我们使用统一的方式。
-
面向切面编程:
- 给目标类额外增加的功能,就是切面。切面的特点是:一般都是非业务方法,独立使用的。
- 在分析项目的功能时,找到切面 。合理的安排切面的执行时间(在目标方法的前后问题)。合理安全切面执行的位置。
-
aop实现框架:
-
spring:spring在内部实现了aop规范,但是因为比较笨重,所以很少使用
-
aspectj: 专门做aop的框架,spring集成了aspectJ
- aspectj实现aop有两种方式:
- 使用配置文件。
- 使用注解(常用)
- aspectj实现aop有两种方式:
-
aspect框架的使用:
-
切面的执行时间,在规范中叫做Advance(增强),在aspectj中使用注解来表示(一个注解代表一个时间点)
- @Before : 在目标方法执行前执行的功能
- @AfterReturning
- @Around
- @AfterThrowing
- @After
-
表示切面执行的位置,使用的是切入点表达式:
- 使用步骤:
-
新建maven项目
- 加入spring依赖
- 加入aspectj依赖
-
创建目标类(包括接口和他的实现类),给类中的方法增强功能
-
创建切面类,普通类
-
在类的上面加入注解:@Aspect
-
/** * @Aspect :是aspectj框架中的注解 * 作用 :表示当前类是切面类 * 切面类:用来给业务方法增加功能的类,这个类中有切面的功能代码 * 位置; 在类定义的上边 */ @Aspect public class MyAspect { }
-
在类中定义方法,方法就是切面要执行的功能代码
-
在方法的上面要加入aspectj中的时间注解,例如:@Before
-
指定切入点表达式excution();
-
-
例子:
-
/** * 定义方法: 方法是实现切面功能 * 方法的定义要求: * 公共方法 * 方法没有返回值 * 方法名自定义 * 方法的参数可有可无 * 如果有参数,参数不是自定义的,有几个参数类型可以使用 */ /** * @Before("") : * 属性: value :是切入点表达式,表示切面功能的执行位置 * 位置; 在方法的上边 * 特点: * 在目标方法执行之前执行的 * 不会改变目标方法的执行结果 * 不会影响目标方法的执行 */ @Before(value = "execution(public void com.lirunxin.powernode.ba01.SomeServiceImpl.doSome(String,Integer))") public void myBefore() { System.out.println("切面的前置功能:" + new Date()); }
-
切面表达式的多种写法:
-
@Before(value = "execution(void com.lirunxin.powernode.ba01.SomeServiceImpl.doSome(String,Integer))") @Before(value = "execution(void *..SomeServiceImpl.doSome(String,Integer))") @Before(value = "execution(* *..SomeServiceImpl.doSome(..))") @Before(value = "execution(* *..SomeServiceImpl.do*(..))") @Before(value = "execution(* do*(..))")
-
一个业务方法可以有多个增强的功能方法
-
创建spring的配置文件:声明对象,把对象交给容器统一管理。
-
声明对象可以使用注解或者xml文件配置bean标签。
-
声明目标对象,声明切面对象,声明aspectj框架中的自动代理生成器标签
-
自动代理生成器:用来完成代理对象的自动创建功能的。
-
<!-- 自动代理生成器--> <!-- 创建目标对象的代理对象,创建代理对象是在内存中实现的,修改目标对象的内存中的结构,创建为代理对象 所以目标对象就是被修改后的代理对象 <aop:aspectj-autoproxy/> : 这个标签会一次性生成spring容器中所有的代理对象 --> <aop:aspectj-autoproxy/>
-
-
-
- 使用步骤:
-
-
JoinPoint
-
指定通知方法中的参数 : joinPoint :业务方法,要加入切面功能的业务方法,
-
作用:可以在通知方法中获取方法执行时的信息,例如:方法名称,方法的实参
如果你的切面功能中需要用到方的信息,就加入joinpoint -
这个joinpoint参数的值是由框架赋予的,必须是第一位置的参数。
@Before(value = "execution(void *..SomeServiceImpl.doSome(String ,Integer))") public void myBefore(JoinPoint pj ) { // JoinPoint必须是方法的第一个参数 System.out.println("切面的前置功能:" + new Date()); } // 当我们在执行测试目标方法的时候,这个方法的所有信息全部保存在pj中 // 获取方法的信息 System.out.println("获取方法的定义" + pj.getSignature()); System.out.println("方法的名称:" + pj.getSignature().getName()); Object[] args = pj.getArgs(); for (Object arg: args) { System.out.println("方法的实参" + arg); }
-
后置通知:
-
后置通知的定义方法:
- 要求:
- 公共方法public
- 方法没有返回值
- 方法名自定义
- 方法有参数,推荐是Object,参数名为自定义
- 要求:
-
后置通知:AfterReturning
-
属性:
-
value ,切入点表达式
-
returning ,自定义的变量,表示目标方法的返回值。自定义的变量名必须和通知方法的形参名一致(和方法参数的名字一样)。
-
例子:
-
@AfterReturning(value = "execution(* *..SomeServiceImpl.doSome(..)))",returning = "res") public void myAfterReturning(Object res) { // Object res:是目标方法执行以后的返回值,根据返回值做切面功能的处理 System.out.println("后置通知,在目标方法执行之后执行的,获取的返回值为:" + res); }
-
-
位置:在方法的定义的上边
-
特点:
- 在目标方法执行之后执行的
- 能够获取到目标方法的返回值,可以根据返回值做出不同的功能。
- 可以修改返回值
-
joinPoint在所有的通知中都可以使用,并且都是位于参数列表的第一位。
环绕通知:
-
经常做事务,在目标方法执行前开启事务,在目标方法结束后关闭事务
-
方法的定义格式:
-
public ,必须有返回值,返回值类型为Object,方法名称自定义,方法名称必须有参数,并且参数是固定的。
-
@Around:环绕通知
- 属性:value : 切入点表达式
- 位置:在方法定义的上边,它是功能最强的通知,在目标方法的前后都可以加功能
- 控制目标方法是否被执行
- 修改原来的目标方法的执行结果。影响最后的调用结果
-
增强方法中的参数:ProcessdingJoinPoint 作用是执行目标方法
-
public Object myAround(ProceedingJoinPoint pjp) { //ProceedingJoinPoint 返回值就是目标方法的返回结果,可以被修改 // ProceedingJoinPoint 继承于 JoinPoint 所以前者可以当作后者使用, // 获取增强方法的信息 // 在目标方法执行前加的功能代码 //目标方法的调用: Object result = pjp.proceed(); // 在目标方法执行之后加的功能代码 return result; }
-
异常通知:
- @AfterThrowing :
- 定义格式:
- public
- 没有返回值
- 方法名称自定义
- 方法可以没有参数,如果有的话就是JoinPoint,Exception
- 属性:
- value是切入点表达式
- throwing 自定义的变量,表示目标方法抛出的异常对象。变量名必须和方法的参数的名字一样
- 特点:
- 在目标方法出现异常时执行,可以做异常的监控程序,监控目标方法执行时是不是有异常,如果有异常,我们发送邮件或者短信进行通知
- 定义格式:
最终通知:
- @After
- 一般是进行清除操作的
- 定义格式
- public
- 没有返回值
- 方法名称自定义
- 方法没有参数, 如果有的话就是JoinPoint
- 属性:
- value 切面表达式
- 位置在方法的上边
- 特点:
- 总是会执行
- 在目标方法执行之后执行
PointCut注解:
-
定义和管理切入点的,如果你的项目中有多个切入点表达式是重复的,可以复用的,可以使用@PointCut
-
属性:
- value : 切入点表达式
- 位置:在自定义的方法的上边
-
特点:
- 当我们在自定义方法的使用@PointCut时,此时的这个方法的名称就是切入点表达式的别名,其他的通知中,value属性就可以使用这个方法的名称,代替切入点表达式
-
没有接口的是cglib动态代理,但是有接口也可以使用cglib动态代理。
-
如果希望目标类有接口,那么声明自动代理生成器时需要设置:
-
<aop:aspectj-autoproxy proxy-target-class="true"/> <!-- proxy-target-class="true" 就是告诉框架使用cglib动态代理 -->
spring整合mybatis
-
新建maven项目
-
加入maven的依赖
-
spring依赖
-
mybatis依赖
-
mysql驱动
-
spring的事务依赖
-
mybatis和spring集成的依赖
-
-
<dependencies> <!-- 单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- spring核心ioc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.5.RELEASE</version> </dependency> <!-- spring事务--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.5.RELEASE</version> </dependency> <!-- mybatis依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!-- mybatis和spring集成的依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency> <!-- mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.26</version> </dependency> <!-- ali连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> </dependencies> <build> <!-- 目的是将src/main/java目录中的xml文件包含到输出结果中,输出到classes目录中--> <resources> <resource> <!-- 文件所在的目录--> <directory>src/main/java</directory> <includes> <!-- 目录下的.properties.xml文件都会被扫描到--> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> <!--指定jdk的版本--> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>
-
创建实体类
-
创建mapper接口和mapper.xml文件
-
mapper接口
-
package com.powernode.mapper; import com.powernode.pojo.Student; import java.util.List; public interface StudentMapper { int insertStudent(Student student); List<Student> selectStudents(); }
-
Studentmapper.xml文件
-
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.powernode.mapper.StudentMapper"> <insert id="insertStudent"> insert into student values (#{s_no},#{class_no},#{s_name},#{s_sex}); </insert> <select id="selectStudents" resultType="com.powernode.pojo.Student"> select * from student order by s_no desc; </select> </mapper>
-
创建mybatis核心配置文件
-
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource=""/> <!-- 设置日志--> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <!-- 设置别名--> <typeAliases> <!-- 实体类所在的包名--> <package name="com.powernode.pojo"/> </typeAliases> <mappers> <package name="com.powernode.mapper"/> </mappers> </configuration>
-
-
创建service接口和实现类,属性是mapper
-
service接口
-
package com.powernode.service; import com.powernode.pojo.Student; import java.util.List; public interface StudentService { int addStudent(Student student); List<Student> queryStudent(); }
-
实现类:
-
package com.powernode.service.impl; import com.powernode.mapper.StudentMapper; import com.powernode.pojo.Student; import com.powernode.service.StudentService; import java.util.List; public class StudentServiceImpl implements StudentService { // 引用类型 private StudentMapper studentMapper; //使用set注入来赋值 public void setStudentMapper(StudentMapper studentMapper) { this.studentMapper = studentMapper; } @Override public int addStudent(Student student) { int count = studentMapper.insertStudent(student); return count; } @Override public List<Student> queryStudent() { List<Student> students = studentMapper.selectStudents(); return students; } }
-
-
-
创建spring的配置文件:声明mybatis 的对象交给spring来创建
-
数据源
<!-- 声明数据源DataSource,作用:连接数据库--> <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close" > <!-- set注入给DruidDataSource提供连接数据库的信息--> <property name="url" value="jdbc:mysql://localhost:3306/student"/> <property name="username" value="root"/> <property name="password" value="xxxx"/> <property name="maxActive" value="20"/> </bean> <!--配置完成表示Connection对象已经创建成功-->
-
SqlSessionFactory对象
-
<!--声明sqlSessionFactoryBean类,这个类内部创建SqlSessionFactory的--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" > <!-- set注入,把数据量的连接池赋给了DataSource--> <property name="dataSource" ref="myDataSource"/> <!--mybatis主配置文件的位置 configLocation : 读取配置文件的 使用value进行赋值,指定配置文件的路径,使用classPath:表示文件的位置 --> <property name="configLocation" value="classpath:mybatis-config.xml"/> </bean>
-
mapper对象
-
<!-- 创建mapper对象,使用SqlSession的getMapper(StudentMapper.class) MapperScannerConfigurer :在内部调用getMapper()生成每个Mapper接口的代理对象 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- 指定SqlSessionFactory对象的id--> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <!-- 指定包名 MapperScannerConfigurer :会扫描这个包中的所有接口,把每个接口都执行一次getMapper()方法,得到每个接口的mapper对象 创建好的mapper对象放入spring容器中的。 --> <property name="basePackage" value="com.powernode.mapper"/> </bean>
-
声明自定义的service
-
<!-- 声明service对象--> <bean name="studentService" class="com.powernode.service.impl.StudentServiceImpl"> <property name="studentMapper" ref="studentMapper"/> </bean>
-
-
测试service:
-
/** * 测试service */ @Test public void test03() { String config = "ApplicationContext.xml"; ApplicationContext ctx = new ClassPathXmlApplicationContext(config); StudentServiceImpl studentMapper = (StudentServiceImpl) ctx.getBean("studentService"); Student student = new Student(); student.setS_no(64); student.setClass_no("194541"); student.setS_sex("女"); student.setS_name("蔡徐坤"); int count = studentMapper.addStudent(student); System.out.println("count = " + count); }
处理事务的问题
-
在spring中事务放在service类的业务方法上,因为业务方法会调用多个mapper方法,执行多个sql语句。
-
spring统一处理事务的方式:
-
使用统一的步骤,方式完成多种不同的数据库访问技术的事务处理
-
声明式事务:把事务相关的资源和内容提供给spring,spring就能处理事务提交,回滚。
-
步骤:
- 事务管理器对象,完成commit,和rollback。事务管理器是一个接口和他众多的实现类。
- 接口:PlatformTransactionManger,定义了事务的重要方法,commit,rollback
- 实现类:spring将每一种数据库访问技术的事务处理类都创建好了
- 声明数据库访问技术对应的实现类,在spring的配置文件中使用bean标签声明
- 例子: : 声明的是mybatis访问数据库
- 说明需要的事务的类型:
- 事务的隔离级别:
- READ_UNCOMMITTED : 读未提交。未解决任何的并发问题。
- READ_COMMITTED : 读已提交。解决脏读,存在不可重复读和幻读
- REPEATABLE_READ : 可重复读。解决了脏读和不可重复读,存在幻读
- SERIALIZABLE :串行化,不存在并发的问题。
- 事务的超时时间:
- 表示一个方法最长的执行时间,如果方法执行时超过了时间,事务就进行回滚,单位为s,默认为-1(无限长)。
- 事务的传播行为:
- 控制业务方法是否是有事务的
- 7个传播行为:表示业务方法调用时,事务在方法之间是如何进行使用的(重点的三个)。
- PROPAGATION_REQUIRED :
- 指定的方法必须在事务内进行,如果当前存在事务,就加入到当前的事务中,如果当前没有事务,则创建一个新的事务。是spring默认的事务传播行为。
- PROPAGATION_REQUIRES_new :
- 总是创建一个新的事务,若当前存在事务,就将当前事务挂起,直到新的事务执行完毕。
- PROPAGATION_SUPPORTS :
- 指定的方法支持事务,但若当前没有事务,也可以已非事务方式执行。
- PROPAGATION_REQUIRED :
- 事务的隔离级别:
- 事务提交,回滚的时机:
- 当你的业务方法执行成功,没有异常抛出,当方法执行完毕,spring在方法执行后自动提交事务。
- 事务管理器对象,完成commit,和rollback。事务管理器是一个接口和他众多的实现类。
-
给方法添加事务:
-
spring框架的事务处理注解(适合中小项目使用):
-
@Transactional 这个注解放在public方法的上面,表示当前的方法具有事务。
-
可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等。
-
使用@Transactional 的可选的属性:
-
propagation :用于设置事务传播属性,该属性的类型是Propagation 枚举类型。默认值为:
Propagation .REQUIRED
-
isolation : 用于设置事务的隔离级别,该类型为isolation枚举,默认值为Isolation.DEFAULT
-
readonly:用于设置该方法对数据库的操作是否为只读的。默认值为false
-
timeout:用于设置本操作与数据库连接的超时时限。默认值为-1,即没有时限。
-
rollbackFor:指定回滚的异常类,类型为:Class[] ,默认值为空数组,只有一个异常类时,可以不适用数组。
-
rollbackForClassName:指定需要回滚的异常类类名。类型为String[] ,默认为空数组。
-
noRollbackFor:指定不需要回滚的异常类,类型为Class[] 。
-
noRollbackForClassName:指定不需要回滚的异常类类名
-
-
-
-
使用@Transactional的步骤:
-
1,声明事务管理器对象
-
<bean id="xxx" class="DataSourceTransactionManger"/>
-
2,开启事务注解驱动,告诉spring框架,要使用注解的方式管理事务,spring使用aop机制,创建注解所在类的代理对象,给方法加入事务的功能。
- 在ApplicationContext.xml文件中配置
-
<!-- 声明事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 连接数据库的信息--> <property name="dataSource" ref="myDataSource"/> <!-- 开启事务注解驱动 transaction-manager:事务管理器对象的id--> <tx:annotation-driven transaction-manager="transactionManager"/> </bean>
-
spring给业务方法加入事务:
-
在业务方法执行之前开启事务,在方法执行之后提交或者回滚事务。使用的是aop的环绕通知
-
/** * rollbackFor;表示发生的异常一定回滚 处理逻辑: spring框架会首先检查方法抛出的异常是不是在rollbackFor的属性值中, 如果异常在rollbackFor列表中,不管什么类型的异常,一定执行回滚。 2,如果抛出的异常不在rollbackFor列表中,spring会判断异常是不是runtimeExecption,如果 是就一定进行回滚 * @return */ @Transactional( propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false, rollbackFor = { NullPointerException.class,NotEnoughExpection.class } ) // 另外一种直接在方法上边添加@Transactional就等同上边的 public void buy(Integer goodsId,Integer nums) { }
-
-
aspectj配置aop
-
适合大型的项目,有很多的类,方法。需要大量的配置事务,使用aspectj框架功能,在spring配置文件中声明类,方法需要的事务。这种方式实现了业务方法和事务的配置的完全分离。
-
实现步骤(在xml配置文件中实现的):
-
在pom文件中加入sapectj依赖
-
<!-- aspectj依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.5.RELEASE</version> </dependency>
-
-
-
声明事务管理器
-
<!-- 声明事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 连接数据库的信息 ,声明数据源--> <property name="dataSource" ref="myDataSource"/> </bean>
-
-
-
声明方法需要的事务类型:(配置方法的事务属性:隔离级别,传播行为,超时设置)
-
<!-- 声明业务方法的他的事务属性:(隔离级别,传播行为,超时时间) id: 自定义名称,来表示tx:advance这个标签的中的配置内容 transaction-manager:事务管理器对象的id --> <tx:advice id="myAdvance" transaction-manager="transactionManager"> <!-- tx:attributes : 配置事务属性--> <tx:attributes> <!-- tx:method : 给具体的方法配置事务属性,method可以有多个,分别给不同的方法设置事务属性 name : 方法的名称: 完整的方法名称,不带有包和类, 方法可以使用通配符 * 表示任意字符 propagation : 传播行为 isolation : 隔离级别 no-rollback-for : 指定的异常类类名 :全限定类名。发生异常时一定回滚。 --> <tx:method name="" propagation="" isolation="" no-rollback-for=" "/> </tx:attributes> </tx:advice>
-
配置aop,指定哪些类需要创建代理。
-
<!-- 配置aop--> <aop:config> <!-- 配置切入点表达式 : 指定哪些包中的类,要使用事务 id : 切入点表达式的名称,唯一值 expression : 切入点表达式,aspectj会创建代理对象 com.bjpowernode.service com.crm.service com.service --> <aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/> <!-- 配置增强器:关联advice和pointcut : advice-ref : 通知,上面tx:advice那里的配置 pointcut-ref : 切入点表达式的id : 将tx:advice和切入点表达式相关联 --> <aop:advisor advice-ref="myAdvice" pointcut-ref="servicePt"/> </aop:config>
-
-
-
配置监听器:
-
- web项目中的容器对象只需要创建一次,将容器对象放入到全局变量作用域ServletContext中
-
使用监听器当全局作用域对象被创建的时候,创建容器,放入ServletContext
-
监听器的作用:
-
创建容器对象:
-
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
- 把容器对象放入到ServletContext。
-
-
监听器可以自己创建,也可以使用框架提供的ContextLoaderListener。
-
加入依赖:
-
<!-- 监听器依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.2.5.RELEASE</version> </dependency>
-
-
在web.xml文件中注册监听器:
-
<listener> <listener-class>...ContextLoaderListener</listener-class> </listener>
-
监听器创建对象后,会读取/WEB—INF/applicationContext.xml文件
-
在监听创建ApplicationContext对象,需要加载配置文件
-
修改默认的文件位置:
-
<context-param> <!-- contextConfigLocation : 表示配置文件的路径 --> <param-name>contextConfigLocation</param-name> <!--自定义配置文件的路径--> <param-value>classpath:applicationContext.xml</param-value> </context-param>
-
-
使用监听器(自己写的):
-
WebApplicationContext ctx = null; String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE; Object attr = getServletContext().getAttribute(key);
-
-
-
工具类的使用:
-
ServletContext sc = getServletContext(); WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
-
配置监听器
- 目的:创建容器对象,创建了容器对象,就能把spring.xml文件中所有的对象都创建好