文章目录
- spring5
- 一、spring框架基本概述
- 二、IOC容器
- 1、什么是IOC
- 2、IOC底层原理
- 三、AOP
- 四、事务
- 五、整合日志框架
- 五、整合日志框架
Spring5
一、spring框架基本概述
spring是轻量级的开源javaee框架
spring可以解决企业应用开发的复杂性
二、IOC容器
1、什么是IOC
IOC是控制反转,是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合。把对象创建和对象之间的调用过程,交给Spring进行管理。
2、IOC底层原理
(1)xml解析、工厂模式、反射
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h212ByOL-1661318832244)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220725185523387.png)]
工厂模式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q9ubRSly-1661318832245)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220725191846168.png)]
IOC过程(进一步降低耦合度)
第一步 xml配置文件,配置创建的对象
<bean id="dao" class="com.xue.UserDao"></bean>
第二部 有service类和dao类,创建工厂类
class UserFactory{
public static User getDao(){
//使用xml解析+反射做到
String classValue = class属性值;//1.xml解析
class clazz = Class.forName(classValue);//2.通过反射创建对象
return (UserDao)clazz.newInstance();
}
}
(2) IOC(接口)
1.IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
2.Spring提供IOC容器实现两种方式:(两个接口)
(1)beanfactory:IOC容器基本实现,spring自带的使用接口,一般不提供给我们这些开发人员使用。加载配置文件的时候不会创建对象,而是在获取对象或使用对象
的时候他才去创建对象。
(2)ApplicationContext:Bean Factory的一个子接口,提供了更多更强大的功能,一般由开发人员进行使用。加载配置文件
的时候就会把在配置文件中的对象进行创建。(一般用这个)
3.ApplicationContext接口有实现类
他有两个实现类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PbE3yTM7-1661318832245)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220725195223727.png)]
第一个是全路径 第二个是类路径
(3) Bean管理
注:bean管理就是通过set方法实现的,所以如果某个类的属性没有set方法的话在bean里是找不到这个属性的。
第一种方式:使用set方法进行注入
a、基于xml方式创建对象
<bean id="dao" class="com.xue.UserDao"></bean>
在spring配置文件中,使用bean标签,标签里面添加对应的属性,就可以实现对象创建。创建对象的时候,默认走无参构造函数创建。
id:表示给对象起个别名,通过名字可以得到对象,唯一标识
class:创建对象所在类的全路径(包 类路径)
name:早期的属性,里面可以加特殊符号,id里面不可以
b、基于xml方式注入属性
第一种注入的方式,使用set方法进行注入。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sv1kfYCr-1661318832246)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220725201309558.png)]
User类
public class User {
// public void add(){
// System.out.println("add()");
// }
private String name;
private String author;
public void setName(String name) {
this.name = name;
}
public void setAuthor(String author) {
this.author = author;
}
public void testDemo(){
System.out.println(name+"::"+author);
}
}
注入属性xml
<!-- set注入属性-->
<bean id="user" class="xue.User">
<!-- bean里使用property完成属性的注入-->
<!-- name是类里面属性的名称 value是向属性里注入的值-->
<property name="name" value="bbb"></property>
<property name="author" value="ccc"></property>
</bean>
测试类
public class springTest {
@Test
public void testAdd(){
// ClasspathXmlApplicationContext context = new ClasspathXmlApplicationContext("bean1.xml")类路径
// 2、获取配置创建的对象k
// "user"是xml文件里的id
ApplicationContext context = new ClasspathXmlApplicationContext("bean1.xml");
User user = context.getBean("user", User.class);
// user.add();
System.out.println(user);
user.testDemo();
}
}
第二种方式:使用有参构造进行注入
(2) 在spring文件中进行配置
注意
无参构造注入属性
<!-- 用有参构造注入属性-->
<!-- 这样写是无参构造创建 如果写了有参构造 那无参构造就没了-->
<bean id="orders" class="xue.Orders"></bean>
有参构造注入属性
<bean id="orders" class="xue.Orders">
<constructor-arg name="oname" value="abc"></constructor-arg>
<constructor-arg name="address" value="china"></constructor-arg>
</bean>
<!-- 有参构造函数的第一个属性-->
<constructor-arg index="0" value=""></constructor-arg>
第三种方式:p名称空间注入
(1) 使用p名称空间注入,可以简化基于xml配置方式
xmlns:p="http://www.springframework.org/schema/p"
<bean id="user" class="xue.User" p:name="aaa" p:author="bbb"></bean>
向属性里注入空值
<bean id="user" class="xue.User">
<property name="name">
<null></null>
</property>
</bean>
<bean id="user" class="xue.User">
<property name="name" >
<value>
<![CDATA[
《南京》
]]></value>
</value>
</property>
</bean>
第四种方式:注入属性-外部bean
(1)创建两个类service类和dao类
(3)在spring配置文件中进行配置
配置文件bean.xml
<!--service和dao对象的创建 UserDao是接口 她的路径要找实现类 也就是UserDaoImpl-->
<bean id="userService" class="xue.service.UserService">
<!-- 注入userDao对象 name:类里面属性名称-->
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="userDao" class="xue.dao.UserDaoImpl"></bean>
UserDao接口
public interface UserDao {
public void update();
}
UserDaoImpl实现类
public class UserDaoImpl implements UserDao{
@Override
public void update() {
System.out.println("update");
}
}
UserService
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao){
this.userDao=userDao;
}
public void add(){
System.out.println("add()");
userDao.update();
}
}
测试类
@Test
public void testUser(){
ApplicationContext context = new ClasspathXmlApplicationContext("bean1.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
第五种方式:注入属性-内部bean
(1)一对多关系:部门和员工
部门是一,员工是多
(2)在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示
Dept类
public class Dept {
private String name;
public void setName(String name) {
this.name = name;
}
// 如果这里不重写toString方法的话,那么在输出dept的时候输出的就是一个对象的地址
// 如果写了toString那么她就会按照toString里返回的东西输出
@Override
public String toString() {
return "Dept{" +
"name='" + name + '\'' +
'}';
}
}
Emp类
//员工
public class Emp {
private String name;
private String gender;
// 员工属于某一个部门,使用对象形式表示
private Dept dept;
public void setName(String name) {
this.name = name;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public void add(){
System.out.println("emp=====add()");
System.out.println(name+"=="+gender+"=="+dept);
}
}
配置文件bean.xml
<bean id="emp" class="xue.bean.Emp">
<property name="name" value="lucy" ></property>
<property name="gender" value="nv"></property>
<property name="dept">
<bean id="dept" class="xue.bean.Dept">
<property name="name" value="安保部"></property>
</bean>
</property>
</bean>
测试类
@Test
public void testemp(){
ApplicationContext context = new ClasspathXmlApplicationContext("bean1.xml");
Emp emp = context.getBean("emp", Emp.class);
emp.add();
}
第五种方式:注入属性-级联赋值
<bean id="emp" class="xue.bean.Emp">
<property name="name" value="lucy" ></property>
<property name="gender" value="nv"></property>
<!-- 级联赋值-->
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="xue.bean.Dept">
<property name="name" value="级联赋值"></property>
</bean>
或
<bean id="emp" class="xue.bean.Emp">
<property name="name" value="lucy" ></property>
<property name="gender" value="nv"></property>
<!-- 级联赋值-->
<property name="dept" ref="dept"></property>
<!-- 使用这种方法要写处dept的get方法 在Emp类里写-->
<!-- 因为需要用到getDept.name = xml 里面的value -->
<property name="dept.name" value="aaa"></property>
</bean>
getDet方法:返回dept对象
public Dept getDept() {
return dept;
}
xml注入集合属性
1.注入数组类型的属性
2.注入List集合类型的属性
3.注入Map集合类型的属性
Stu类
public class Stu {
private String[] courses;
private List<String> list;
private Map<String,String> maps;
private Set<String> sets;
public void setSets(Set<String> sets) {
this.sets = sets;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
public void setCourses(String[] courses) {
this.courses = courses;
}
public void test(){
System.out.println("courses:"+ Arrays.toString(courses));
System.out.println("list:"+list);
System.out.println("map:"+maps);
System.out.println("set:"+sets);
}
}
bean.xml
<!-- 集合类型属性的注入-->
<bean id="stu" class="xue.collectionType.Stu">
<property name="courses">
<!-- array、list都可以-->
<array>
<value>语文</value>
<value>数学</value>
</array>
</property>
<property name="list">
<list>
<value>张三</value>
<value>小三</value>
</list>
</property>
<property name="maps">
<map>
<entry key="0" value="aaa"></entry>
<entry key="1" value="bbb"></entry>
</map>
</property>
<property name="sets">
<set>
<value>MysqL</value>
<value>redis</value>
<value>MysqL</value>
</set>
</property>
</bean>
测试类
@Test
public void testStu(){
ApplicationContext context = new ClasspathXmlApplicationContext("bean1.xml");
Stu stu = context.getBean("stu", Stu.class);
stu.test();
}
courses:[语文, 数学]
list:[张三, 小三]
map:{0=aaa, 1=bbb}
set:[MysqL, redis]
在集合里面设置对象类型值
Stu类多加属性
// 学生所学的多门课程
private List<Course> courseList;
public void setCourseList(List<Course> courseList) {
this.courseList = courseList;
}
xml配置文件
<!-- 集合类型属性的注入-->
<bean id="stu" class="xue.collectionType.Stu">
<!-- 注入list集合类型 但是她的值是对象类型-->
<property name="courseList">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<!-- 定义多个course对象-->
<bean id="course1" class="xue.collectionType.Course">
<property name="name" value="Spring5框架课程"></property>
</bean>
<bean id="course2" class="xue.collectionType.Course">
<property name="name" value="mybatis框架课程"></property>
</bean>
把集合注入的部分提取出来
<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/beans/spring-util.xsd">
book类
public class Book {
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
}
<util:list id="bookList">
<value>book1</value>
<value>book2</value>
<value>book3</value>
</util:list>
<!-- 提取list集合类型属性注入使用-->
<bean id="book" class="xue.collectionType.Book">
<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类型
MyBean类
public class MyBean implements factorybean<Course> {
// 定义返回bean的对象
// 虽然是MyBean类但是通过重写getobject方法,可以返回一个course对象 这样就更改了他的返回值类型
@Override
public Course getobject() throws Exception {
Course course = new Course();
course.setName("aaa");
return course;
}
}
<!-- 虽然这里写的是MyBean的对象但是返回的时候确是Course对象 可以看MyBean的类 -->
<bean id="myBean" class="xue.factorybean.MyBean"></bean>
测试类
@Test
public void testBean(){
ApplicationContext context = new ClasspathXmlApplicationContext("bean1.xml");
//这里的getBean的第二个参数也要改成需要返回的对象的类型
Course course = context.getBean("myBean", Course.class);
System.out.println(course);
}
IOC操作Bean管理(bean作用域)
1、在spring里面,设置创建bean实例是单例还是多例
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-choWbhjI-1661318832247)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220727133607086.png)]
3、如何设置单实例还是多实例
(1)spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例
第二个值 prototype,表示是多实例对象
<bean id="myBean" class="xue.factorybean.MyBean" scope="prototype"></bean>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ile6uCOi-1661318832247)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220727134202856.png)]
(3)singleton和prototype区别
第一 singleton是单实例,prototype是多实例
第二 设置scope值是singleton时候,加载spring配置文件时候就会创建单实例对象
设置scope的值为prototype时,不是在加载spring配置文件时创建对象,而是在调用getBean方法的时候创建对象
request
session
4、bean生命周期
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ixKBfSP5-1661318832248)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220727135815252.png)]
销毁IOC容器的方法
context.close()
<!-- 初始方法和销毁方法 -->
<bean id="myBean" class="xue.factorybean.MyBean" scope="singleton" init-method="a()" destroy-method="b()"></bean>
(1)创建类,实现接口BeanPostProcessor,创建后置处理器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BLMZMKum-1661318832248)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220727150217632.png)]
MyBeanPost方法
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之前执行的方法 ");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之后执行的方法 ");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
<bean id="myBeanPost" class="xue.bean.MyBeanPost"></bean>
IOC操作Bean管理(xml自动装配)
1、什么是自动装配
(1)根据指定装配规则(属性名称或者属性类型),spring自动将匹配的属性值进行注入
2、演示自动装配的过程
<!--实现自动装配-->
<!-- bean标签属性autowire,配置自动装配-->
<!-- autowire属性常用两个值:
byName根据属性名称注入:注入值bean的id值和类属性名称一样,
byType根据属性类型注入-->
<bean id="emp" class="xue.autowire.Emp" autowire="byName">
<!-- <property name="dept" ref="dept"></property>-->
</bean>
<bean id="dept" class="xue.autowire.Dept"></bean>
<bean id="emp" class="xue.autowire.Emp" autowire="byType">
<!-- <property name="dept" ref="dept"></property>-->
</bean>
<bean id="dept" class="xue.autowire.Dept"></bean>
IOC操作Bean管理(外部属性文件)
1、直接配置数据库信息
(1)配置德鲁伊连接池
<!--直接配置连接对象-->
<bean id="druid" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.MysqL.jdbc.Driver"></property>
<property name="url" value="jdbc:MysqL://localhost:3306/userDb"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
(2)引入德鲁伊连接池依赖jar包
(1)创建外部属性文件,properties格式文件,写数据库信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JpWrFole-1661318832248)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220727170423854.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bJZIVp8r-1661318832249)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220727173009130.png)]
IOC操作Bean管理(基于注解方式)
注解默认是单例
创建bean实例 也就是创建对象
@Component
@Service
@Controller
@Repository
这四个都是一样 的作用,作用在类上面,只是使用的位置不一样,方便使用者分清角色
基于注解方式实现创建对象
第一步 引入依赖 aop依赖
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5khjM3er-1661318832249)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220727174043451.png)]
第二步 开启组件的扫描
只有开启组件的扫描,spring才知道哪里有注解
<!-- 开启组件扫描-->
<!-- component-scan组件扫描-->
<!-- base-package=""基于哪个包-->
<!-- 如果要扫描多个包,那么多个包之间用逗号隔开-->
<!-- 扫描xue下的所有文件-->
<context:component-scan base-package="xue"></context:component-scan>
例如:
//在注解里面value属性值可以不写,默认值是类名称,首字母小写
@Component(value = "userService")//<bean id="userService" class=""/>是等价的
public class UserService {
public void add(){
System.out.println("add()");
}
}
开启组件扫描细节配置
1、配置哪些类扫描哪些类不扫描
use-default-filters="false"表示现在不使用默认filter,自己配置filter context:include-filter,设置扫描哪些内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GY7BkWAD-1661318832250)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220728095029130.png)]
只扫描Controller注解
2、设置哪些内容不去扫描[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iMzRYa8u-1661318832250)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220728095224564.png)]
基于注解方式实现属性注入
(1)@Autowired
(2)@Qualitiler
@Service
public class UserService {
// 添加注入属性注解 不需要添加set方法
@Autowired
// 一个接口有多个实现类,她不知道该找哪个实现类,所以加个名字
// 如果不写的话,默认就是她首字母小写的实现类
@Qualifier(value = "userDaoImpl")
private UserDao userDao;
public void add(){
System.out.println("service----add()");
userDao.add();
}
}
(3)@Resource
- 可以根据类型注入,也可以根据名称注入
(4)@Value
- 注入普通类型属性
@Value(value = "aaa")
private String name;
纯注解开发
(1)创建配置类,替代xml配置文件
@Configuration//作为配置类,替代xml配置文件
@ComponentScan(basePackages = "xue")//相当于xml配置扫描某个包
public class SpringConfig {
}
(2)编写测试类
@Test
public void test(){
// 代替了之前的bean.xml文件
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
// 如果不写@Component(value = "userService"),那么getBean的第一个参数就是类名的首字母小写
UserService userservice = context.getBean("userService", UserService.class);
userservice.add();
}
三、AOP
1、什么是AOP
面向切面(方面)编程,可以对业务逻辑的各个部分进行隔离,从而使业务逻辑各个部分进行隔离,从而使业务逻辑各个部分之间的耦合度降低,降低程序的可重用性。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uHyFjYqb-1661318832251)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220728131622563.png)]
2、底层原理
AOP底层使用动态代理
第一种 有接口情况,使用JDK动态代理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FQJvPzQx-1661318832252)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220728133122594.png)]
第二种 没有接口情况,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b9FbyTXv-1661318832253)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220728133633200.png)]
AOP(jdk动态代理)
使用jdk动态代理,使用Proxy类里面的方法创建代理对象 调用newProxyInstance方法
这个方法里有三个参数,第一个类加载器classLoader,第二个增强方法所在的类,这个类实现的接口支持多个接口,第三个InvocationHandler(interface)实现这个接口创建代理的对象,写增强的方法。
编写jdk动态代理代码
(1)创建接口,定义方法
public interface UserDao {
public int add(int a ,int b);
public void update(String id);
}
(2)创建接口实现类,实现方法
@Repository
public class UserDaoImpl implements UserDao{
@Override
public int add(int a, int b) {
return a+b;
}
@Override
public String update(String id) {
return id;
}
}
JDKProxy代理类
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
// Proxy.newProxyInstance(
// JDKProxy.class.getClassLoader(),
// interfaces,
// new InvocationHandler() {
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// return null;
// }
// }
// );
UserDaoImpl userDao = new UserDaoImpl();
Proxy.newProxyInstance(
JDKProxy.class.getClassLoader(),
interfaces,
new UserDaoProxy(userDao)
);
}
}
//创建代理对象的代码
class UserDaoProxy implements InvocationHandler{
// 把创建的是谁的代理对象,把谁给传递过来
// 通过一个有参构造进行传递
private Object obj;
public UserDaoProxy(Object obj){
this.obj = obj;
}
// 写增强的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 写增强的逻辑
// 方法之前执行
System.out.println("qian");
// 被增强的方法执行
// 方法之后
return 1;
}
}
3、AOP(术语)
1、连接点
2、切入点
实际被真正增强的方法,成为切入点
3、通知(增强)
(1)实际增强的逻辑部分成为通知(增强)
(2)通知有多种类型
4、切面
是动作
(1)把通知应用到切入点的过程
4、AOP操作(准备)
1、Spring框架一般基于AspectJ实现AOP操作
(1)什么是AspectJ
- AspectJ不是spring组成部分,独立AOP框架,一般把AspectJ和spring框架一起使用,进行AOP操作
2、基于AspectJ实现AOP操作
(1)基于xml配置文件实现
(2)基于注解方式实现(使用)
3、在项目的工程里面先引入AOP相关依赖
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BlOusJPb-1661318832254)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220729105045645.png)]
主要是
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.7.0</version>
</dependency>
4、切入点表达式
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构:
Execution([权限修饰符] [返回类型] [类全路径] ([参数列表]))
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M3SOeqBX-1661318832254)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220729105816764.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2S4l6r7w-1661318832254)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220729105953869.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-igNHbteF-1661318832255)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220729110131579.png)]
5、AOP操作(AspectJ注解)
-
创建类 在类里面增强方法
//被增强的类
public class User {
public void add(){
System.out.println("add====");
}
}
//增强的类
public class UserProxy {
// 前置通知 在add()方法前执行
public void before(){
System.out.println("before======");
}
}
-
通知的配置
如果切面不起作用的话,在User类上加注解:@EnableAspectJAutoproxy(exposeProxy = true)
(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="xue.aopanno"></context:component-scan>
</beans>
(2)使用注解创建User和UserProxy对象
@Component
public class UserProxy {}
@Component
public class User {}
(3)在你的增i强的类上面添加注解@Aspect
@Component
@Aspect
public class UserProxy {}
<!-- 开启AspectJ生成代理对象-->
<!-- 找包里有@Aspect注解的类并把他设置成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
-
配置不同类型的通知
(1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
//增强的类
@Component
@Aspect
public class UserProxy {
// 前置通知 在add()方法前执行
// @Before表示作为前置通知
// 后置@After
// @AfterReturning在方法返回结果后执行,最终通知
// 异常通知@AfterThrowing
// 环绕通知@Around
@Before(value = "execution(* xue.aopanno.User.add(..))")
public void before(){
System.out.println("before======");
}
}
环绕通知:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hZltFGdA-1661318832255)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220729135254694.png)]
结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ScxQ7z89-1661318832255)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220729135537861.png)]
测试
public class TestAop {
@Test
public void testAopAnno(){
ApplicationContext context = new ClasspathXmlApplicationContext("bean2.xml");
User user = context.getBean("user", User.class);
user.add();
}
}
注意:这个test必须要引入依赖包
<dependency> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.7.0</version>
</dependency>
before==
add====
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CeuRgLYK-1661318832256)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220729145734408.png)]
(1)在增强类上面添加注释@Order(数组型值),数字型值越小优先级越高
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jZlyYibY-1661318832256)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220729150305371.png)]
AOP操作(AspectJ注解)
ConfigAop.java
@Configuration
@ComponentScan(basePackages = {"xue"})
//开启Aspect生成代理对象
@EnableAspectJAutoproxy(proxyTargetClass = true)
public class ConfigAop {
}
四、事务
概念
1、什么是事务
(1)事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败
(2)典型场景:银行转账
2、事务四个特性ACID
(1)原子性
(2)一致性
(3)隔离性
(4)持久性
搭建事务操作环境
转账环境
web:
service:业务操作(创建转账的方法1.调用dao两个方法)
dao:数据库操作不写业务(创建两个方法:1.少钱的方法2.多钱的方法)
spring任务管理介绍
spring事务管理api,提供一个接口代表事务管理器,这个接口针对不同的框架提供不同的实现类。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kfQqCg6M-1661318832256)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220801132956230.png)]
注解声明式事务管理
1、在spring配置文件中,配置事务管理器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fOYZ4Jar-1661318832257)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220801133313388.png)]
2、开启事务注解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tgq79NOY-1661318832257)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220801133419035.png)]
(2)开启事务注解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kb0HuU3D-1661318832257)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220801133523391.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z6UBAAmU-1661318832258)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220801150948242.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kgYkhBvH-1661318832258)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220801151515618.png)]
3、在service类上面(获取service类里面方法上面)添加事务注解
(1)@Transactional这个注解添加到类上面,也可以添加方法上面
(2)如果把这个注解添加类上面,这个类里面所有的方法都添加事务
(3)如果把这个注解添加方法上面,为这个方法添加事务[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dkvoaksS-1661318832258)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220801133840496.png)]
Transactional第一个属性-propagation:事务传播行为
@Transactional(propagation= Propagation.SUPPORTS)
当一个事务的方法被另外一个事务方法调用的时候,这个事务方法如何执行
required:如果有事务在运行,那当前方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3amAaU4q-1661318832259)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220801134622879.png)]
required_NEW:当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应将他挂起
SUPPORTS:如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中。
https://blog.csdn.net/wojiaoxubo/article/details/85158445
Transactional第二个属性-ioslation:事务隔离级别
1、事务有特性成为隔离性,多事务操作之间不会产生影响,不考虑隔离性产生很多问题
2、有三个读问题:脏读、不可重复读、虚(幻)读
3、脏读:多事务之间,一个未提交的事务,读取到了另一个未提交事务的数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2Mb1z5b2-1661318832260)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220801141215452.png)]
4、不可重复读:在同一次事务中前后查询不一致的问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uTWxDWRn-1661318832260)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220801141153029.png)]
5、幻读:一次事务中前后数据量发生变化,用户产生不可预料的问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l1Qu8Z0d-1661318832261)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220801141122224.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3dxYGpG5-1661318832262)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220801141406392.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mSnWcUxg-1661318832262)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220801142030428.png)]
Transactional第三个属性-timeout
(1)事务需要在一定时间内进行提交,如果不提交进行回滚
(2)默认值是-1,设置时间以秒单位进行计算
Transactional第四个属性-readOnly是否只读
(2)readOnly默认值false,表示可以查询,可以添加修改删除操作
Transactional第五个属性-roobackFor回滚
(1)设置出现哪些异常进行事务的回滚
Transactional第六个属性-norollbackFor-不回滚
(1)设置出现哪些异常进行事务的不进行回滚
五、整合日志框架
整个Spring5框架的代码基于java8,运行时兼容jdk9,旭东不建议使用的类和方法在电脑中删除,建议log4j2
整合log4j2日志
片转存中…(img-dkvoaksS-1661318832258)]
Transactional第一个属性-propagation:事务传播行为
@Transactional(propagation= Propagation.SUPPORTS)
当一个事务的方法被另外一个事务方法调用的时候,这个事务方法如何执行
required:如果有事务在运行,那当前方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行
[外链图片转存中…(img-3amAaU4q-1661318832259)]
required_NEW:当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应将他挂起
SUPPORTS:如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中。
https://blog.csdn.net/wojiaoxubo/article/details/85158445
Transactional第二个属性-ioslation:事务隔离级别
1、事务有特性成为隔离性,多事务操作之间不会产生影响,不考虑隔离性产生很多问题
2、有三个读问题:脏读、不可重复读、虚(幻)读
3、脏读:多事务之间,一个未提交的事务,读取到了另一个未提交事务的数据
[外链图片转存中…(img-2Mb1z5b2-1661318832260)]
4、不可重复读:在同一次事务中前后查询不一致的问题
[外链图片转存中…(img-uTWxDWRn-1661318832260)]
5、幻读:一次事务中前后数据量发生变化,用户产生不可预料的问题
[外链图片转存中…(img-l1Qu8Z0d-1661318832261)]
[外链图片转存中…(img-3dxYGpG5-1661318832262)]
[外链图片转存中…(img-mSnWcUxg-1661318832262)]
Transactional第三个属性-timeout
(1)事务需要在一定时间内进行提交,如果不提交进行回滚
(2)默认值是-1,设置时间以秒单位进行计算
Transactional第四个属性-readOnly是否只读
(2)readOnly默认值false,表示可以查询,可以添加修改删除操作
Transactional第五个属性-roobackFor回滚
(1)设置出现哪些异常进行事务的回滚
Transactional第六个属性-norollbackFor-不回滚
(1)设置出现哪些异常进行事务的不进行回滚
五、整合日志框架
整个Spring5框架的代码基于java8,运行时兼容jdk9,旭东不建议使用的类和方法在电脑中删除,建议log4j2
整合log4j2日志
原文地址:https://www.jb51.cc/wenti/3284368.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。