Spring全面详解(学习总结)

  • Spring FrameWork
  • 一、 前言
  • 二、IOC(控制反转)
    • 2.1 对于IOC的理解
    • 2.2如何使用IOC
    • 2.3配置文件的解读
    • 2.4IOC容器创建bean的两种方式
    • 2.5从IOC容器中取bean
    • 2.6bean的属性如果包含特殊字符
  • 三、DI(依赖注入)
  • 四、Spring中的bean
  • 五、Spring中的继承
  • 六、Spring的依赖
  • 七、Spring读取外部资源
  • 八、Spring的p命名空间
  • 九、Spring工厂方法
    • 9.1静态工厂方法
    • 9.2实例工厂方法
  • 十、Spring IOC 自动装配 autowire
    • 10.1自动装配
    • 10.2 Spring IOC基于注解的开发
    • 10.3实际开发中的使用
  • 十一、Spring AOP

📃个人主页: 不断前进的皮卡丘
🌞博客描述: 梦想也许遥不可及,但重要的是追梦的过程,用博客记录自己的成长,记录自己一步一步向上攀登的印记
🔥网站推荐:千里之行,始于足下。每天坚持刷题,巩固所学知识,也为将来找工作,面试做好准备----- 刷题神器
文章是看楠哥的视频写的笔记
这篇博客内容把Spring的基本知识点都讲到了,篇幅比较长,大家可以用于复习,也可以在学习相关知识点的时候,来看看对应内容。对于一些难点,IOC,AOP等,我通过流程图,代码,文字结合来进行讲解,可以更好的理解

Spring FrameWork

一、 前言

  • Spring是当前Java开发的行业标准,第一框架
  • Spring FrameWork已经从最初取代EJB的框架逐步发展成一套完整的生态,最新的版本是5.x
  • Spring架构体系图
    在这里插入图片描述
  • Spring两大核心机制:
    • IOC:工厂模式
    • AOP:代理模式

二、IOC(控制反转)

2.1 对于IOC的理解

传统开发中,需要调用对象的时候,需要调用者手动来创建被调用者的实例,即对象是由调用者new出来的
但是在Spring框架中,创建对象的工作不再由调用者来完成,而是交给IOC容器来创建,再推送给调用者,整个流程完成反转,所以是控制反转
在这里插入图片描述
就比如说假设买东西,以前我们需要自己去超市买东西,但是现在我们可以不用自己去超市,我们只要把购物袋放在家门口,IOC就会自己去把我们想要的东西买回来,然后放在袋子里面,我们打开袋子拿起来用就可以了
IOC的特点是解耦合。
比如说A需要用到B,传统的开发,我们要直接创建B的实例,但是在Spring中,IOC这个容器会创建B的实例,然后把这个B注入到A
在这里插入图片描述

2.2如何使用IOC

  • 创建maven工程,在pom.xml中导入相关依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>springioc</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.18</version></dependency></dependencies></project>
  • 创建实体类Student
public class Student {private long id;private String name;private int age;public long getId() {return id;}public void setId(long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';}
}
  • 在resources路径下创建applicationContext.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="stu" class="com.zyh.pojo.Student"></bean>
</beans>
  • 传统的开发方式:手动new Student
        Student stu =new Student();stu .setAge(25);stu.setId(1001);stu.setName("张三");System.out.println(stu);
  • IOC容器通过读取配置文件,加载配置bean标签来创建对象
  • 就像买菜一样,我们不需要自己亲自买,但是要写一张单子,告诉说要买什么,程序也是类似的,我们要告诉Spring框架要创建哪些对象,怎样创建对象
  • 在这里插入图片描述
  • 调用API,从IOC获取对象
//读取配置文件ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");Student stu = applicationContext.getBean("stu", Student.class);System.out.println(stu);

在这里插入图片描述

2.3配置文件的解读

  • 通过配置bean标签来完成对象的管理
  • id:对象名
  • class:对象的模板类(所有交给IOC容器来管理的类必须要有无参构造函数,因为Spring底层是通过反射机制来创建对象,调用的是无参构造)
  • 对象的成员变量通过property标签完成赋值
    • name:成员变量名
    • value:成员变量值(基本数据类型,String可以直接赋值,如果是其他引用类型不可以通过value赋值)
    • ref:把IOC中的另一个bean赋给当前成员变量(DI)
    • 在这里插入图片描述

2.4IOC容器创建bean的两种方式

  • 无参构造函数(需要提供对应的set方法)

  • 在这里插入图片描述

  • 有参构造函数

  <bean id="stu1" class="com.zyh.pojo.Student"><constructor-arg name="id" value="1">  </constructor-arg><constructor-arg name="name" value="李四"></constructor-arg></bean>
  <bean id="stu1" class="com.zyh.pojo.Student"><constructor-arg index=0 value="1">  </constructor-arg><constructor-arg index=1 value="李四"></constructor-arg></bean>

2.5从IOC容器中取bean

  • 通过id取值
 Student stu = (Student)applicationContext.getBean("stu");
  • 通过类型取值
 Student stu = applicationContext.getBean(  Student.class);
  • 当IOC容器中存在两个以上Student Bean的时候就会抛出异常,因为此时没有唯一的bean
    在这里插入图片描述
    在这里插入图片描述

2.6bean的属性如果包含特殊字符

在这里插入图片描述

三、DI(依赖注入)

  • DI:指bean之间的依赖注入,设置对象之间的级联关系
  • Classes
public class Classes {private Integer id;private String name;还有对应的get,set方法
}
  • Student
public class Student {private long id;private String name;private int age;private Classes classes;public Student(){System.out.println("使用无参构造创建对象");}public Student(long id,String name){this.id = id;this.name = name;}  public Classes getClasses() {return classes;}public void setClasses(Classes classes) {this.classes = classes;}public long getId() {return id;}public void setId(long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"id=" + id +", name='" + name + '\'' +", age=" + age +", classes=" + classes +'}';}
}

applicationContext-di.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="classes" class="com.zyh.pojo.Classes"><property name="name" value="1班"></property><property name="id" value="1"></property></bean><bean id="student" class="com.zyh.pojo.Student"><property name="id" value="1001"></property><property name="name" value="张三"></property><property name="age" value="22"></property><property name="classes" ref="classes"></property></bean></beans>

在这里插入图片描述

bean之间的级联需要使用ref属性,而不能用value属性,否则会抛出类型转换异常
在这里插入图片描述
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="classes" class="com.zyh.pojo.Classes"><property name="name" value="1班"></property><property name="id" value="1"></property><property name="studentList"><list><ref bean="student"></ref><ref bean="student2"></ref></list></property></bean><bean id="student" class="com.zyh.pojo.Student"><property name="id" value="100"></property><property name="name" value="张三"></property><property name="age" value="22"></property><property name="classes" ref="classes"></property></bean><bean id="student2" class="com.zyh.pojo.Student"><property name="id" value="200"></property><property name="age" value="18"></property><property name="name" value="李四"></property><property name="classes" ref="classes"></property></bean></beans>

在这里插入图片描述

如果把学生装到班级里面,又把班级装到学生里面,就导致无限递归循环装配,最终栈溢出

四、Spring中的bean

bean是根据scope来生成的,表示bean的作用域,scope有4种类型

  • singleton,单例,表示通过Spring容器获取的对象是唯一的,是默认值

    • 在这里插入图片描述

    • 在这里插入图片描述

    • 在这里插入图片描述

  • prototype,原型,表示通过Spring容器获取的对象是不同的

    • 配置文件
<bean id="user" class="com.zyh.pojo.User" scope="prototype"><property name="id" value="1"></property><property name="name" value="张三"></property></bean>

在这里插入图片描述
在这里插入图片描述

  • request,请求,表示在异常HTTP请求内有效
  • session,会话,表示在一个用户会话内有效
    request和session一般用于web项目
    singleton模式下,只要加载IOC容器,不管是否从IOC种取出bean,配置文件中的bean都会被创建,而且只会创建一个对象
    prototype模式下,如果不从IOC中取出bean,则不创建对象,取一次bean,就会创建一个对象

五、Spring中的继承

Spring中的继承不同于Java中的继承
Java中的继承是针对于类的
Spring中的继承是针对于对象(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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="user1" class="com.zyh.pojo.User"  ><property name="id" value="1"></property><property name="name" value="张三"></property></bean><bean id="user2" class="com.zyh.pojo.User" parent="user1"></bean>
</beans>

在这里插入图片描述

  • 通过设置bean标签的parent属性建立继承关系,同时子bean可以覆盖父bean的属性值
  • Spring的继承是针对对象的,所以子bean和父bean并不需要同一个数据类型,只要其成员变量列表一致即可

六、Spring的依赖

  • 用来设置两个bean的创建顺序
  • IOC容器默认情况下是通过applicationContext.xml中bean的配置顺序来决定创建顺序的,配置在前面的bean会先被创建
  • 在不更改applicationContext.xml配置顺序的前提下,通过设置bean之间的依赖关系来调整bean的创建顺序
  • 在这里插入图片描述

七、Spring读取外部资源

  • 在实际开发中,数据库的配置会一般会单独保存到后缀为properties的文件,方便维护和修改
  • 如果用Spring来加载数据源,就需要在applicationContext.xml中读取properties中的数据,这就是读取外部资源

jdbc.properties

user=root
password=root
url=jdbc:mysql://localhost:3306/spring
driverName=com.mysql.cj.jdbc.Driver

spring-properties.xml

<?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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!--导入外部资源 --><context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder><bean id="dataSource" class="com.zyh.pojo.DataSource"><property name="username" value="${user}"></property><property name="password" value="${password}"></property><property name="url" value="${url}"></property><property name="driveName" value="${driverName}"></property></bean></beans>

在这里插入图片描述
在这里插入图片描述

八、Spring的p命名空间

  • 用来简化xml配置
  • 在这里插入图片描述
<?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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="stu" class="com.zyh.pojo.Student" p:id="1" p:age="10" p:name="张三" p:classes-ref="classes"></bean><bean id="classes" class="com.zyh.pojo.Classes" p:name="一班" p:id="1"></bean></beans>

九、Spring工厂方法

IOC通过工厂模式创建bean有两种方式:

  • 静态工厂方法
  • 实例工厂方法
  • 静态工厂类不需要实例化,实例工厂类需要实例化

9.1静态工厂方法

  1. 创建Car类
public class Car {private Integer num;private String brand;public Car() {}public Car(Integer num, String brand) {this.num = num;this.brand = brand;}public Integer getNum() {return num;}public void setNum(Integer num) {this.num = num;}public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}@Overridepublic String toString() {return "Car{" +"num=" + num +", brand='" + brand + '\'' +'}';}
}
  1. 创建静态工厂类,静态工厂方法
public class StaticCarFactory {private static Map<Integer, Car> carMap;static {carMap = new HashMap<>();carMap.put(1, new Car(1, "奥迪"));carMap.put(2, new Car(2,"奥拓"));}/*** 写一个方法,从map集合取数据*/public static Car getCar(Integer num ){return carMap.get(num);}
}
  1. spring-factory.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="car" class="com.zyh.factory.StaticCarFactory" factory-method="getCar"><constructor-arg  name="num" value="1"></constructor-arg></bean></beans>
  • factory-method 指向静态方法
  • constructor-arg的value属性是调用静态方法传入的参数

9.2实例工厂方法

  1. 创建实例工厂类,工厂方法
public class InstanceCarFactory {private Map<Integer, Car> carMap;public InstanceCarFactory() {carMap = new HashMap<>();carMap.put(1, new Car(1, "奥迪"));carMap.put(2, new Car(2, "奥拓"));}public Car getCar(Integer num){return carMap.get(num);}}
  1. spring.xml
<!--    实例工厂类--><bean id="instanceCarFactory" class="com.zyh.factory.InstanceCarFactory"></bean>
<!--    通过实例工厂获取Car--><bean id="car1"  factory-bean="instanceCarFactory" factory-method="getCar"><constructor-arg value="2"></constructor-arg></bean>

区别:
在这里插入图片描述

  • 静态工厂方法创建Car对象,不需要实例化工厂对象,因为静态工厂的静态方法,不需要创建对象就可以调用了
  • 实例工厂方法创建Car对象,需要实例化工厂对象,因为getCar方法是非静态的,就必须通过实例化对象才能调用,所以 必须创建工厂对象,spring.xml需要配置两个bean,一个是工厂bean,一个是Car Bean
  • spring.xml中 class+factory-method的形式是直接调用类中的工厂方法
  • spring.xml中factory-bean+factory-method的形式是调用工厂bean中的工厂方法,就必须先创建工厂bean

十、Spring IOC 自动装配 autowire

10.1自动装配

  • 自动装载是Spring提供的一种更加简便的方式来完成DI,不需要手动配置property,IOC 容器会自动选择bean来完成注入
  • 自动装载有两种方式:
    • byName:通过属性名完成自动装载
    • byType:通过属性对应的数据类型完成自动装载

byName的操作如下:

  1. 创建Person实体类
public class Person {private Integer id;private String name;private Car car;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Car getCar() {return car;}public void setCar(Car car) {this.car = car;}@Overridepublic String toString() {return "Person{" +"id=" + id +", name='" + name + '\'' +", car=" + car +'}';}
}
  1. 在spring.xml中配置Car和Person对应的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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="car2" class="com.zyh.pojo.Car"><constructor-arg name="num" value="1"></constructor-arg><constructor-arg name="brand" value="奥迪"></constructor-arg></bean><bean id="car" class="com.zyh.pojo.Classes"></bean><bean id="person" class="com.zyh.pojo.Person" autowire="byName" ><property name="name" value="张三"></property><property name="id" value="2"></property></bean></beans>

在这里插入图片描述
注:如果bean的id有多个一致的,会报错,如Bean name 'car' is already used in this <beans> element
byType的操作如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="car2" class="com.zyh.pojo.Car"><constructor-arg name="num" value="1"></constructor-arg><constructor-arg name="brand" value="奥迪"></constructor-arg></bean><bean id="car" class="com.zyh.pojo.Classes"></bean><bean id="person" class="com.zyh.pojo.Person" autowire="byType" ><property name="name" value="张三"></property><property name="id" value="2"></property></bean></beans>

在这里插入图片描述
使用byType进行自动装配的时候,必须保证IOC中有且只有一个符合,如果有多个符合,则报下面的异常:
在这里插入图片描述

10.2 Spring IOC基于注解的开发

Spring IOC的作用是帮助开发者创建项目中所需要的bean,同时完成bean之间的依赖注入关系,DI
实现该功能有两种方式:

  • 基于XML配置
  • 基于注解
    基于注解有两步操作,缺一不可:
  1. 配置自动扫包
  2. 添加注解
<?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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!--    配置自动扫包--><context:component-scan base-package="com.zyh.pojo"></context:component-scan>
<!--    <bean id="repository" class="com.zyh.pojo.Repository"></bean>--></beans>
@Component(value="repository")
public class Repository {private DataSource dataSource;public DataSource getDataSource() {return dataSource;}public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;}@Overridepublic String toString() {return "Repository{" +"dataSource=" + dataSource +'}';}
}

DI
注解默认的beanid是类名以小写开头,我们可以通过value来设置
如果我们想要把datasource也注入进来需要怎么做呢?
首先我们要把DataSource先扫进来

@Component
public class Repository {@Autowiredprivate DataSource dataSource;public DataSource getDataSource() {return dataSource;}public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;}@Overridepublic String toString() {return "Repository{" +"dataSource=" + dataSource +'}';}
}

在这里插入图片描述
在这里插入图片描述

  • @Autowired默认是通过byType进行装配,如果要改为byName,需要配合@Qualifier注解来完成
@Component
public class Repository {@Autowired@Qualifier(value = "datasource")private DataSource dataSource;public DataSource getDataSource() {return dataSource;}public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;}@Overridepublic String toString() {return "Repository{" +"dataSource=" + dataSource +'}';}
}

这表明把IOC中id为datasource的bean注入到repository中
实体类中普通的成员变量(String,包装类等),可以通过@Value注解来赋值

@Component
public class DataSource {@Value("root")private String username;@Value("123456")private String password;@Value("jdbc:mysql://localhost:3306/spring")private String url;@Value("com.mysql.cj.jdbc.Driver")private String driveName;}

10.3实际开发中的使用

实际开发中我们会把程序分成三层:

  • Controller
  • Service
  • Repository(DAO)
  • 关系Controller—>Service---->Repository
  • 在这里插入图片描述
    @Component注解是把标注的类加载到IOC容器中,实际开发中可以根据业务需求分别使用@Controller,@Service,@Repository注解来标注控制层类,业务层类,持久层类

十一、Spring AOP

  • AOP (Aspect Oriented Programming) 面向切面编程
  • OOP (Object Oriented Programming) 面向对象编程,用对象化的思想来完成程序
  • AOP是对OOP的一个补充,是在另外一个维度上抽象出对象
  • 具体指程序运行时动态地把非业务代码切入到业务代码中,从而实现程序的解耦合,把非业务代码抽象成一个对象,对对象编程就是面向切面编程
  • 在这里插入图片描述
  • 上面这种形式的代码维护性很差,代码复用性差
  • 在这里插入图片描述
    AOP的优点:
  • 可以降低模块之间的耦合性
  • 提供代码的复用性
  • 提高代码的维护性
  • 集中管理非业务代码,便于维护
  • 业务代码不受非业务代码影响,逻辑更加清晰

通过一个例子来理解AOP。

  1. 创建一个计算器接口Cal
public interface Cal {public int add(int num1,int num2);public int sub(int num1,int num2);public int mul(int num1,int num2);public int div(int num1,int num2);
}
  1. 创建接口的实现类
public class CalImpl implements Cal {@Overridepublic int add(int num1, int num2) {int res = num1 + num2;return res;}@Overridepublic int sub(int num1, int num2) {int res = num1 - num2;return res;}@Overridepublic int mul(int num1, int num2) {int res = num1 * num2;return res;}@Overridepublic int div(int num1, int num2) {int res=num1/num2;return res;}
}

日志打印

  • 在每个方法开始位置输出参数信息
  • 在每个方法结束位置输出结果信息

对于计算器来说,加减乘除就是业务代码,日志打印就是非业务代码
AOP如何实现? 使用动态代理的方式来实现
代理首先要具备CalImpl的所有功能(实现同一个接口),并且在这个基础上,扩展出打印日志的功能

  1. 删除CalImpl方法中国所有打印日志的代码,只保留业务代码
  2. 创建MyInvocationHandler类(不是动态代理类),实现InvocationHandler接口,生成动态代理类 。动态代理类需要动态生成,需要获取到委托类的接口信息,根据这些接口信息动态生成一个代理类,然后再由ClassLoader用来把动态生成的类加载到JVM
    在这里插入图片描述
    ClassLoader用来把动态生成的类加载到JVM中
    在这里插入图片描述
    代理类需要有和委托类一样的功能,所以委托类和代理类需要实现同样的接口,因此,我们要获取到委托类的接口信息,根据这个接口信息就可以生成一个类,再通过ClassLoader加载到内存里面
public class MyInvocationHandler implements InvocationHandler {//委托对象private Object object = null;//返回代理对象public Object bind(Object object) {this.object = object;return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//实现业务代码和非业务代码的解耦合System.out.println(method.getName()+"方法的参数是:"+ Arrays.toString(args));Object res = method.invoke(this.object, args);System.out.println(method.getName()+"方法的结果是:"+res);return res;}
}

在这里插入图片描述
上述代码通过动态代理机制实现了业务代码和非业务代码的解耦合,这是Spring AOP的底层实现机制,真正使用 Spring AOP进行开发的时候,不需要这么复杂
Spring AOP的开发步骤

  1. 创建切面类 Loggerspect
@Component
@Aspect
public class LoggerAspect {@Before("execution(public int com.zyh.aop.impl.CalImpl.*(..))")public void before(JoinPoint joinPoint) {String name = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println(name + "方法的参数是:" + Arrays.toString(args));}@After("execution(* com.zyh.aop.impl.CalImpl.*(..))")public void after(JoinPoint joinPoint){String name = joinPoint.getSignature().getName();System.out.println(name+"方法执行完毕");}@AfterReturning(value = "execution(* com.zyh.aop.impl.CalImpl.*(..))",returning = "rs")public void afterReturning(JoinPoint joinPoint,Object rs){String name = joinPoint.getSignature().getName();System.out.println(name+"方法执行的结果是:"+rs);}
@AfterThrowing(value = "execution(* com.zyh.aop.impl.CalImpl.*(..))",throwing = "ex")public void afterThrowing(JoinPoint joinPoint,Exception ex){String name = joinPoint.getSignature().getName();System.out.println(name+"方法抛出异常"+ex);
}}
  • @Component,把切面类加载到IOC容器中
  • @Aspect,表示该类是一个切面类
  • @Before,表示方法的执行时机是在业务方法之前,execution表达式表示切入点是CalImpl中的所有方法
  • @After,表示方法的执行时机是在业务方法结束以后,execution表达式表示切入点是CalImpl类中的方法
  • @AfterReturning,表示方法的执行时机是在业务方法返回结果后,execution表达式表示切入点是CalImpl类中的方法,returning是把业务方法的返回值和切面类方法的形参进行绑定
  • @AfterThrowing,表示方法的执行时机是在业务方法抛出异常后,execution表达式表示切入点是CalImpl类中的方法,throwing是把业务方法的异常和切面类方法的形参进行绑定
    在这里插入图片描述
  1. 委托类也需要添加@Component
@Component
public class CalcImpl implements Calc{@Overridepublic int add(int a, int b) {int result=a+b;return result;}@Overridepublic int sub(int a, int b) {int result=a-b;return result;}@Overridepublic int mul(int a, int b) {int result= a*b;return result;}@Overridepublic int div(int a, int b) {int result= a/b;return result;}
}

3.spring-aop.xml

<?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 https://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="com.zyh.aop"></context:component-scan>
<!--   为委托对象自动生成代理对象--><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
  • aspectj-autoproxy ,Spring IOC容器会结合切面对象和委托对象自动生成动态代理对象,AOP底层就是通过动态代理机制来实现的

4.测试
在这里插入图片描述
AOP的概念

  • 切面对象:根据切面抽象出来的对象,CalImpl所有方法中需要加入日志的部分LoggerAspect
  • 通知:切面对象具体执行的代码,即非业务代码,LoggerAspect对象打印日志的代码
  • 目标:被横切的对象,即CalImpl,把通知加入其中
  • 代理:切面对象,通知,目标混合后的结果,即我们通过JDK动态代理机制创建的对象
  • 连接点:需要被横切的位置,即通知要插入业务代码的具体位置

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/172365.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【咕咕送书 | 第六期】深入浅出阐述嵌入式虚拟机原理,实现“小而能”嵌入式虚拟机!

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《粉丝福利》 《linux深造日志》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 ⛳️ 写在前面参与规则引言一、为什么嵌入式系统需要虚拟化技术&#xff1f;1.1 专家推荐 二、本书适合谁&#x…

WiFi的CSMA/CA竞争窗口流程简述

1、若站点最初有数据要发送&#xff08;不是发送不成功再进行重传的那种&#xff09;&#xff0c;且检测到信道空闲&#xff0c;在等待DIFS后&#xff0c;就发送整个数据帧。 2、否则&#xff0c;站点执行退避算法。一旦检测到信道忙&#xff0c;就冻结退避计时器。只要信道空…

Less 安装教程

文章目录 前言LESS的系统要求安装LESS例子输出Less编译css工具后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;Sass和Less &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板…

error LNK2038: 检测到“RuntimeLibrary”的不匹配项 解决方法

问题&#xff1a; 我们在使用Visual Studio编程的时候偶尔会遇到以下三种报错&#xff1a; error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MD_DynamicRelease”不匹配值“MDd_DynamicDebug” &#xff08;引用的是release模式&#xff0c;但设置成debug模式了…

操作系统——进程管理

文章目录 进程和线程进程的概念进程和程序的区别PCB(进程控制块)程序是如何运行的进程的特征进程的状态和状态转换五态模型 进程控制进程状态装换为啥需要保证原子性如何实现原语的原子性&#xff1f; 进程控制相关原语进程创建进程终止进程的阻塞和唤醒进程的唤醒进程的切换 进…

1603. 整数集合划分(2016年408数据结构算法题)

一、题目 1603. 整数集合划分https://www.acwing.com/problem/content/description/1605/ 二、算法的基本设计思想 由题意知&#xff0c;将最小的 个元素放在 中&#xff0c;其余的元素放在 中&#xff0c;分组结果即可满足题目要求。仿照快速排序的思想&#xff0c;基于枢…

Vue 2.0源码分析-Virtual DOM

Virtual DOM 这个概念相信大部分人都不会陌生&#xff0c;它产生的前提是浏览器中的 DOM 是很“昂贵"的&#xff0c;为了更直观的感受&#xff0c;我们可以简单的把一个简单的 div 元素的属性都打印出来&#xff0c;如图所示&#xff1a; 可以看到&#xff0c;真正的 DOM …

地铁在线售票vue票务系统uniAPP+vue 微信小程序

功能介绍 管理员 &#xff08;1&#xff09;管理员登录功能 &#xff08;2&#xff09;查看和修改线路信息 &#xff08;3&#xff09;减少线路 &#xff08;4&#xff09;修改价格&#xff08;5站3元 5-10 5元 10-15站6元 往上8元&#xff09; &#xff08;5&#xff09;删除用…

吾爱破解置顶的“太极”,太好用了吧!

日常工作和娱乐&#xff0c;都需要用到不同类型的软件&#xff0c;哪怕软件体积不大&#xff0c;也必须安装&#xff0c;否则到用时找不到就非常麻烦了。 其实&#xff0c;很多软件不一定一样不剩地全部安装一遍&#xff0c;一方面原因是用的不多&#xff0c;另一方面多少有点…

Android设计模式--外观模式

弈之为术&#xff0c;在人自悟 一&#xff0c;定义 外观模式要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。提供一个高层次的接口&#xff0c;使得子系统更易于使用。 外观模式在开发中的使用频率是非常高的&#xff0c;尤其是在第三方的SDK里面&#xff0…

Django之admin页面样式定制(Simpleui)

好久不见&#xff0c;各位it朋友们&#xff01; 本篇文章我将向各位介绍Django框架中admin后台页面样式定制的一个插件库&#xff0c;名为Simpleui。 一&#xff09;简介 SimpleUI是一款简单易用的用户界面&#xff08;UI&#xff09;库&#xff0c;旨在帮助开发人员快速构建…

清华提出 SoRA,参数量只有 LoRA 的 70%,表现更好!

现在有很多关于大型语言模型&#xff08;LLM&#xff09;的研究&#xff0c;都围绕着如何高效微调展开。微调是利用模型在大规模通用数据上学到的知识&#xff0c;通过有针对性的小规模下游任务数据&#xff0c;使模型更好地适应具体任务的训练方法。 在先前的工作中&#xff…

基于驾驶训练算法优化概率神经网络PNN的分类预测 - 附代码

基于驾驶训练算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于驾驶训练算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于驾驶训练优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

Robots 元标签与 X-Robots 标签

Robots Meta Tag 和 X-Robots-Tag 是两个常用的 HTML 标签&#xff0c;它们对观察机动爬虫和其他网络机器人很有启发性。这些标签可以控制您的网页如何被记录和显示。 什么是机器人元标记&#xff1f; 机器人元标记是一个 HTML 标签&#xff0c;它提供信息来查看电机爬虫和其…

Figma 插件学习(二)- 常用属性和方法

一. 如何调试figma插件 Plugins > Development > Show/Hide console 打开控制台即可开始调试 二.节点类型 根据不同的节点类型&#xff0c;也是会有不同的方法和属性&#xff0c;介绍几个常用节点类型 1.FrameNode 框架节点是用于定义布局层次结构的容器。它类似于HTM…

GWAS:plink进行meta分析

之前教程提到过Metal是可以做Meta分析&#xff0c;除了Metal&#xff0c;PLINK也可以进行Meta分析。 命令如下所示&#xff1a; plink --meta-analysis gwas1.plink gwas2.plink gwas3.plink logscale qt --meta-analysis-snp-field SNP --meta-analysis-chr-field CHR --me…

BrokerChain

BrokerChain: A Cross-Shard Blockchain Protocol for Account/Balance-based State Sharding 我总感觉这篇文章不完整&#xff0c;缺少一些东西。或者说有些地方并没有详细说。比如状态图的构建&#xff0c;网络重分片的的配置过程。都直接忽略了。 Motivation 1 跨片交易不…

流程图是什么,用什么软件做?

在工作流程中&#xff0c;经常会遇到需要图形化呈现整个流程的情况。流程图就是一种一目了然的图形化表现方式&#xff0c;便于人们理解、沟通和管理整个流程。 1.Visio Visio是一款微软公司的图表软件&#xff0c;可以用于创建各种类型的流程图、组织结构图、网络图、平面图…

编译原理词法分析器

算法描述 对于给出的源代码&#xff0c;我们按行将其读入&#xff0c;对于每一行单独进行词法分析。 过滤行前后空格对字符串进行词语的分割 有空格则把空格前的字符归为一个词比较上一个字符和当前字符是否需要进行分割 检查词语是否合法词语合法则按 [待测代码中的单词符号…

常见树种(贵州省):019滇白珠、杜茎山、苍山越桔、黄背越桔、贵州毛柃、半齿柃、钝叶柃、细枝柃、细齿叶柃木、土蜜树、山矾、胡颓子、檵木

摘要&#xff1a;本专栏树种介绍图片来源于PPBC中国植物图像库&#xff08;下附网址&#xff09;&#xff0c;本文整理仅做交流学习使用&#xff0c;同时便于查找&#xff0c;如有侵权请联系删除。 图片网址&#xff1a;PPBC中国植物图像库——最大的植物分类图片库 一、滇白珠…