spring5

文章目录

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方法进行注入
  • 创建对象:基于xml配置文件方式实现
  • 注入属性:基于注解方式实现
a、基于xml方式创建对象
<bean id="dao" class="com.xue.UserDao"></bean>

在spring配置文件中,使用bean标签标签里面添加对应的属性,就可以实现对象创建。创建对象的时候,认走无参构造函数创建。

id:表示给对象起个别名,通过名字可以得到对象,唯一标识

class:创建对象所在类的全路径(包 类路径)

name:早期的属性,里面可以加特殊符号,id里面不可以

b、基于xml方式注入属性

DI:依赖注入,就是注入属性,是IOC的一个具体实现。

第一种注入的方式,使用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();
}
}
第二种方式:使用有参构造进行注入

(1) 创建类,定义属性,创建属性对应的有参数的构造方法

(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配置方式

第一步 添加p名称空间在配置文件

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>

属性值包含特殊符号:把特殊符号内容写到CDATA中去

<bean id="user" class="xue.User">
    <property name="name" >
        <value>
            <![CDATA[
            《南京》
            ]]></value>
        </value>
    </property>
</bean>
第四种方式:注入属性-外部bean

(1)创建两个类service类和dao类

(2)在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>
把集合注入的部分提取出来

在spring配置文件中引入名称空间util

<?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实例是单例还是多例

2、在spring里认情况下,bean是一个单实例对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-choWbhjI-1661318832247)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220727133607086.png)]

3、如何设置单实例还是多实例

(1)spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例

(2)scope属性

一个认值,singleton,表示单实例对象

第二个值 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>

5、演示添加后置处理器效果

(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>

(2)根据属性类型自动装配

<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包

2、引入外部属性文件配置数据库连接池

(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注解)

  1. 创建类 在类里面增强方法
//被增强的类
public class User {
    public void add(){
        System.out.println("add====");
    }
}
  1. 创建增强类,编写增强逻辑

(1)在增强类里面创建方法,让不同方法代表不同通知类型

//增强的类
public class UserProxy {
//    前置通知 在add()方法前执行
    public void before(){
        System.out.println("before======");
    }
}
  1. 通知的配置

如果切面不起作用的话,在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 {}

(4)在spring的配置文件中开启生成代理对象

<!--    开启AspectJ生成代理对象-->
<!--    找包里有@Aspect注解的类并把他设置成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  1. 配置不同类型的通知

(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====

  1. 抽取相同的切入点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CeuRgLYK-1661318832256)(C:\Users\28908\AppData\Roaming\Typora\typora-user-images\image-20220729145734408.png)]

  1. 多个增强类对同一个方法进行增强,设置增强类优先级

(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、开启事务注解

(1)在spring配置文件引入名称空间

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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是否只读

(1)读:查询操作,写:添加修改删除操作

(2)readOnly认值false,表示可以查询,可以添加修改删除操作

(3)设置成true,只能查询,不可以添加修改删除操作

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是否只读

(1)读:查询操作,写:添加修改删除操作

(2)readOnly认值false,表示可以查询,可以添加修改删除操作

(3)设置成true,只能查询,不可以添加修改删除操作

Transactional第五个属性-roobackFor回滚

(1)设置出现哪些异常进行事务的回滚

Transactional第六个属性-norollbackFor-不回滚

(1)设置出现哪些异常进行事务的不进行回滚

五、整合日志框架

整个Spring5框架的代码基于java8,运行时兼容jdk9,旭东不建议使用的类和方法在电脑中删除,建议log4j2

整合log4j2日志

相关文章

显卡天梯图2024最新版,显卡是电脑进行图形处理的重要设备,...
初始化电脑时出现问题怎么办,可以使用win系统的安装介质,连...
todesk远程开机怎么设置,两台电脑要在同一局域网内,然后需...
油猴谷歌插件怎么安装,可以通过谷歌应用商店进行安装,需要...
虚拟内存这个名词想必很多人都听说过,我们在使用电脑的时候...