(尚硅谷)2020 版 Spring5 教程笔记

本文档详细介绍了Spring框架的基础知识,包括Spring5的下载、基于maven的项目创建、IOC(控制反转)的概念和原理、Bean管理、注解开发以及AOP(面向切面编程)的原理和实现。内容涵盖BeanFactory和ApplicationContext、注解配置、动态代理等方面,适合初学者系统学习。
摘要由CSDN通过智能技术生成


前言

  1. 尚硅谷这个老师的笔记已经做的非常好了,平时我做笔记就是类似的方法,所以这里只做扩展,具体的笔记可以从尚硅谷公众号获取,老师的源码感觉不是很规范,凑活看吧;
  2. 尚硅谷老师的笔记已经上传,可以直接零资源下载,见Spring5 王老师原版笔记

参考文献

  1. Spring框架教程(非常详细)

1、Spring5 入门案例

1.1 Spring5 下载

由于版本不一致,老师的下载过程和我们的也不太一样,这里本人参考了Spring下载教程,如果使用 maven 的话,可以直接跳过下载 Spring 这一步,但是我们需要知道目前发布的最稳定的 Spring 框架版本是多少。

  1. 进入 Spring 官网https://spring.io/,点击 Spring FrameWork;

在这里插入图片描述

  1. 到页面后点击 learn 一栏,其中看到的后缀为 GA 的就是稳定版,这里我们选 5.3.20 ,即最新的稳定版。

在这里插入图片描述

1.2 创建一个基于 maven 的 Spring 项目

这里老师讲解了最原始的创建 Spring 项目的方法,不过既然学了 maven 的话,就不用自己导包,太麻烦了;而且老师在创建过程中貌似没有使用 module,新讲一块儿内容就创建一个 project,属实是 eclipse 的玩儿法了。

  1. 新建一个空的 project ,用来放整个 Spring 学到的内容:
    在这里插入图片描述
    注意:
  1. 创建一个新的 module 为 maven 工程,命名为 Spring_demo01,这样我们可以通过配置 maven 自动导包,不用自己去下载了。

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

  1. 导入老师要求我们手动导入的那 5 个 jar包,进入网站https://mvnrepository.com/
  2. 从下载 Spring 框架的网站,我们可以知道我们想要的是 5.3.20 版本;
  3. 到这个网站中找到想要的依赖,然后找到对应版本点进去,将 maven 下面的复制粘贴到我们的 pom.xml 文件中就可以了;

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

  1. 导入 Spring5 相关 jar 包,spring包 beans、core、context、expression、commons-logging

在这里插入图片描述
在我们的 pom.xml 文件中配置,这里为了后面方便测试,需要将测试需要的依赖也导入进来:

<!--导入依赖的jar包-->
<dependencies>
    <!-- spring包 beans、core、context、expression、commons-logging-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.3.20</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.3.20</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.20</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>5.3.20</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>

    <!-- Mybatis核心 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.10</version>
    </dependency>
    <!-- junit测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!-- MySQL驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.29</version>
    </dependency>

    <!-- log4j日志 -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
</dependencies>
  1. src/main/java 下新建 com.atguigu.spring5.bean 的子包,在其中新建 User 类以及普通方法:

在这里插入图片描述

public class User {
    public void add() {
        System.out.println("User.add......");
    }
}
  1. src/main/resources 下创建 Spring 配置文件 bean.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">
    <!--配置User对象创建-->
    <bean id="user" class="com.atguigu.spring5.bean.User"></bean>
</beans>
  1. src/test/java 下新建 com.atguigu.spring5.test 的子包,在其中新建 UserTest 类进行测试

在这里插入图片描述

public class UserTest {
    @Test
    public void testAdd() {
        //1 加载spring配置文件
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        //2 获取配置创建的对象
        User user = context.getBean("user", User.class);
        System.out.println(user);
        user.add();
    }
}
  1. 运行测试类,项目运行成功:

在这里插入图片描述

2、IOC - 控制反转

2.1 IOC 是什么?

  1. 在传统的 Java 应用中,一个类想要调用另一个类中的属性或方法,通常会先在其代码中通过 new Object() 的方式将后者的对象创建出来,然后才能实现属性或方法的调用。也就是说,调用者掌握着被调用者对象创建的控制权。(存在极大的耦合度)
  2. 在 Spring 应用中,Java 对象创建的控制权是掌握在 IoC 容器手里的,谁想用哪一个对象,就从 IOC 容器中去取;
  3. 对于该对象依赖的属性值,也会在 IOC 容器来负责,通过反射将该对象依赖的属性值注入进去。

2.2 IOC 底层原理

IoC 底层通过工厂模式、Java 的反射机制、XML 解析等技术,将代码的耦合度降低到最低限度,其主要步骤如下:

  1. 在配置文件(例如 bean.xml)中,对各个对象以及它们之间的依赖关系进行配置;
  2. 我们可以把 IoC 容器当做一个工厂,这个工厂的产品就是 Spring Bean;
  3. 容器启动时会加载并解析这些配置文件,得到对象的基本信息以及它们之间的依赖关系;
  4. IoC 利用 Java 的反射机制,根据类名生成相应的对象(即 Spring Bean),并根据依赖关系将这个对象注入到依赖它的对象中。

2.3 IOC 容器的两种实现方式

  1. IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂;
  2. 有两种实现方式(两个接口):BeanFactory 和 ApplicationContext 接口。
  3. 我们主要用的是 ApplicationContext 接口的 ①② 两种实现类;
  4. 接口 ③ 主要包含 BeanFactory 相关的一些扩展功能,以后可能会用到。
    在这里插入图片描述

2.3.1 BeanFactory

  1. BeanFactory 是 IoC 容器的基本实现,也是 Spring 提供的最简单的 IoC 容器,它提供了 IoC 容器最基本的功能,由 org.springframework.beans.factory.BeanFactory 接口定义。

  2. BeanFactory 采用懒加载(lazy-load)机制,容器在加载配置文件时并不会立刻创建 Java 对象,只有程序中获取(使用)这个对对象时才会创建。

2.3.2 ApplicationContext

在这里插入图片描述

  1. 对于实现类①:使用的时候要写从盘符开始的路径,例如 D:\Projects\IdeaProjects\Spring5\Spring5_demo01\src\main\resources\bean.xml
  2. 对于实现类②:写文件在 src 下的路径就可以,例如 bean.xml,这里对于 maven 工程,我放置在 src/main/resources 目录下,也可以这么使用(参考上面实现的第一个 Spring 项目)。

2.4 IOC 操作的 Bean 管理

2.4.1 什么是 Bean 管理

Bean 管理指的是两个操作:

  1. Spring 创建对象:创建 BeanFactory;
    在这里插入图片描述
    注意要创建类的无参构造器,如果没有创建无参构造器,会报错:

在这里插入图片描述

  1. Spirng 注入属性:注入普通属性、注入字面量(null 值、空字符串)、注入 外部 Bean、注入内部 Bean(即一个类的某一属性是自定义类型,比如一对多关联)、注入集合、

2.4.2 Bean 管理操作有两种方式

  1. 基于 xml 配置文件方式实现(可以看尚硅谷笔记)
  2. 基于注解方式实现

2.4.3 注入普通属性需要注意的点

  • 使用 set 方法注入属性的时候,即在 bean 标签内部使用 property 标签进行属性注入要创建对应的 set 方法,然后配置 xml 文件才有效,否则会报错
    在这里插入图片描述
  • 同理,使用有参构造器设置属性的时候,即在 bean 标签内部使用 constructor-arg 标签进行属性注入,要求类中有对应参数的构造器;
  • p名称空间注入,添加p空间约束,在bean标签内部使用“p:属性”来定义(了解)

2.4.4 注入外部 bean 需要注意的点

  • bean 标签创建对象,创建的是某个类的对象,不能用接口,即 class 定位到的全类名到实现类,而不是到接口。
    在这里插入图片描述

2.4.5 注入内部 bean 需要注意的点

  • 注意在打算注入内部 bean 的外层 property 标签上只有 name 标属性,不要使用 value/ref 属性。
    在这里插入图片描述- 级联赋值中第二种写法,记得还要在 property 标签内用 ref 属性引入外部链接,否则是没办法设置 dept.name 的,报错如下:

在这里插入图片描述
没有用 ref 标签级联报错信息如下,表示当前 emp 内部的 dept 属性为空:

Caused by: org.springframework.beans.NullValueInNestedPathException: Invalid property 'dept' of bean class [com.atguigu.spring5.bean.Emp]: Value of nested property 'dept' is null

2.4.6 注入集合属性需要注意的点

  • 在注入数组属性的时候,property 标签内部既可以用 array 标签也可以用 list 标签:

在这里插入图片描述

  • 在将 list 集合注入提取为一个 util 类的时候,这个 id 是自己随便取的,就像 util 工具类中你命名的某个方法一样,只不过引用的时候 ref 标签要写这个 id 。

在这里插入图片描述

2.4.7 FactoryBean

在这里插入图片描述

  • 工厂 bean 定义的时候,只要你这个 bean 是生产哪个类的,你使用的时候传进来的必须是这个类(不管有没有定义泛型,重写方法返回的是不是 Object),否则就会报错:

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

正确的使用方式如下:
在这里插入图片描述

2.4.8 bean 作用域

  • bean 作用域:在 Spring 里面,设置创建 bean 实例是单实例还是多实例:
  • singleton:单例,默认也是这个,加载 spring 配置文件时候就会创建单实例对象
  • prototype:多例,在调用 getBean 方法时候创建多实例对象

在这里插入图片描述

2.4.9 bean 生命周期(从对象创建到对象销毁的过程)

基本的生命周期(5 步):

  1. 通过构造器创建 bean 实例(无参数构造)
  2. 为 bean 的属性设置值和对其他 bean 引用(调用set方法)
  3. 调用 bean 的初始化的方法(需要进行配置初始化的方法)
  4. bean 可以使用了(对象获取到了)
  5. 当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

演示结果:

在这里插入图片描述

加入后置处理器的生命周期(7 步):

  1. 通过构造器创建 bean 实例(无参数构造)
  2. 为 bean 的属性设置值和对其他 bean 引用(调用set方法)
  3. 把 bean 实例传递给 bean 后置处理器的方法 postProcessBeforeInitialization
  4. 调用 bean 的初始化的方法(需要进行配置初始化的方法)
  5. 把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization
  6. bean 可以使用了(对象获取到了)
  7. 当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

演示结果:

在这里插入图片描述

  • 需要注意的是,在配置文件中配置了后置处理器,对当前配置文件中的所有 bean 都有效

2.4.10 xml 自动装配属性

在这里插入图片描述

  • 使用 byName 来装配的话,属性中的 set 方法后面的名称(第一个字母小写之后)要和 id 中配置的一致:
    在这里插入图片描述
  • 使用 byType 来装配的话,不能定义多个,会报错 NoUniqueBeanDefinitionException,没有定义唯一的一个 bean:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.atguigu.spring5.bean.Dept' available: expected single matching bean but found 2: dept,dept1

在这里插入图片描述

2.4.11 配置外部属性文件

演示配置数据库信息

  1. 在 pom.xml 文件中导入 druid 依赖:
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.10</version>
</dependency>
  1. 创建 jdbc.properties 配置文件:
prop.driverClass=com.mysql.cj.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/userDb
prop.userName=root
prop.password=root
  1. 把外部 properties 属性文件引入到 spring 配置文件中:

引入context名称空间:
在这里插入图片描述
在 spring 配置文件使用标签引入外部属性文件:

在这里插入图片描述

2.5 基于注解的开发(推荐)

2.5.1 什么是注解?

(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值..)
(2)使用注解,注解作用在类上面,方法上面,属性上面
(3)使用注解目的:简化 xml 配置

2.5.2 Spring 针对 Bean 管理中创建对象提供注解

(1)@Component,表示普通注解创建对象
(2)@Service,一般用在业务逻辑层
(3)@Controller,一般用在 web 层上
(4)@Repository,一般用在 DAO 层

  • 上面四个注解功能是一样的,都可以用来创建 bean 实例,但是约定大于配置,配置大于编码,所以为了好区分,最好是遵守规范。

2.5.3 基于注解方式实现对象创建

  1. 引入依赖 spring-aop:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.3.20</version>
</dependency>
  1. 开启组件扫描(这里仍然用 xml 配置文件的方式来实现),需要在配置文件中进行如下 3 步配置:
    在这里插入图片描述
    注意:
  • 如果扫描多个包,多个包使用逗号隔开
<context:component-scan base-package="com.atguigu.spring5.dao,com.atguigu.spring5.service"></context:component-scan>
  • 扫描包上层目录(推荐使用)
<!--开启组件扫描-->
<context:component-scan base-package="com.atguigu.spring5"></context:component-scan>
  1. 创建类,在类上面添加创建对象注解:
//在注解里面value属性值可以省略不写,
//默认值是类名称,首字母小写
//UserService -- userService
//@Component(value = "userService")  //<bean id="userService" class=".."/>
@Service
public class UserService {
    public void add() {
        System.out.println("service add......." + name);
    }
}

注意:

  • 在注解里面 value 属性值可以省略不写,默认值是类名称,首字母小写,即 UserService -- userService

测试注解是否配置成功:

//测试注解开发,需要在配置文件中开启组件扫描
@Test
public void testService1() {
    ApplicationContext context
            = new ClassPathXmlApplicationContext("bean1.xml");
    UserService userService = context.getBean("userService", UserService.class);
    System.out.println(userService);
    userService.add();
}

输出结果,创建成功,执行了其中的 add() 方法:

在这里插入图片描述

2.5.4 Spring 针对 Bean 管理中属性注入提供注解

(1)@Autowired:根据属性类型进行自动装配
(2)@Qualifier:根据属性名称进行注入,必须与 @Autowired 一起使用
(3)@Resource:可以根据类型注入,可以根据名称注入(JDK 11 以后该注解被取消了,如果要使用的话,添加下面的依赖)

<!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api -->
<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
</dependency>

(4)@Value:注入普通类型属性

2.5.5 基于注解方式实现属性注入

  1. 沿用上面的对象创建过程,创建 DAO 层和 service 层,并且在 service 层中新建 DAO 属性,使用注解 @Qualifier@Autowired 进行实现:
@Repository(value = "userDaoImpl1")
public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("dao add.....");
    }
}
@Service
public class UserService {
    //定义dao类型属性
    //不需要添加set方法
    //添加注入属性注解
    @Autowired                          //根据类型进行注入
    @Qualifier(value = "userDaoImpl1")  //根据名称进行注入,和@Autowired 一起使用
    private UserDao userDao;
    public void add() {
        System.out.println("service add.......");
        userDao.add();
    }
}

注意:

  • 使用 @Autowired 注解进行属性注入不需要添加 set 方法;
  • 单独使用 @Autowired 注解,只能有一个实现类,多个实现类会报错;
  • @Qualifier 必须与 @Autowired 一起使用,唯一的确定某类型某实现类的属性;
  1. 使用注解 @Resource 进行实现,记得添加依赖:

在这里插入图片描述
注意:

  • 单单使用一个 @Resource 代表根据类型进行注入,只能有一个实现类;
  • 使用 @Resource(name="实现类名称") 根据名称进行注入,可以有多个实现类,根据名称确定唯一的一个。
  1. 使用 @Value 在 service 层注入普通类型属性,这里演示的是属性值固定了,以后应该不这样用:

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

结果演示:

在这里插入图片描述

2.6 完全注解开发

  1. 创建配置类,替代 xml 配置文件来开启组件扫描:
@Configuration  //作为配置类,替代xml配置文件
@ComponentScan(basePackages = {"com.atguigu.spring5"})
public class SpringConfig {
}
  1. 编写测试类,调用注解设置的配置类,和调用配置文件使用的函数不同,需要使用 AnnotationConfigApplicationContext(传入配置类)
//测试完全注解开发,需要创建配置类,替代xml配置文件
@Test
public void testService2() {
    //加载配置类
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
    UserService userService = context.getBean("userService", UserService.class);
    System.out.println(userService);
    userService.add();
}

结果:

在这里插入图片描述

3、AOP - 面向切面编程

3.1 AOP 是什么?

  1. 面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
  2. 通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

也可以说是将通用代码抽取出来,作为一个通用功能,但是为了降低耦合度,需要使用动态代理来实现,而不是在类中使用定义好的工具类方法来实现。

3.2 AOP 底层原理和两种实现方式

  1. 、AOP 底层使用动态代理

  2. 动态代理:代理类要指定被代理类什么时候创建,调用什么方法,因为运行的时候才能知道加载了哪一个类,所以还要通过反射获取当前加载的类,然后看你实现了什么接口,我代理类实现和你一样的接口,就可以代理你实现你的功能了,并且在前置、后置等地方添加通用的功能;(此处参考康师傅 Java 基础部分,尚硅谷Java入门视频教程(在线答疑+Java面试真题) P662 - P665,康师傅 yyds)

  3. 当我想实现增强的功能定义在一个接口中的时候,JDK 动态代理

  4. 当我想增强的功能没有在接口中的时候,使用 CGLIB 动态代理

3.3 AOP 常用术语

  1. 连接点,多个可能被增强的方法
  2. 切入点,实际被增强的若干个方法
  3. 通知(增强)
    前置通知:在切入点之前执行的方法
    后置通知:在切入点之后执行的方法
    环绕通知:在切入点前后都会执行的方法
    异常通知:在切入点出现异常的时候执行,相当于 catch 捕获异常其中会执行的方法
    最终通知:相当于 try/actch/finally 的 finally ,一定会被执行的代码
  4. 切面:一个动作,我要在某切入点使用增强方法的过程
    在这里插入图片描述

3.4 JDK动态代理(当想增强的功能有接口的时候)

  1. 定义接口
public interface UserDao {
    public int add(int a,int b);
    public String update(String id);
}
  1. 定义目标类实现接口(被代理类)
public class UserDaoImpl implements UserDao {
    @Override
    public int add(int a, int b) {
        System.out.println("add方法执行了.....");
        return a+b;
    }

    @Override
    public String update(String id) {
        System.out.println("update方法执行了.....");
        return id;
    }
}
  1. 使用 Proxy 类里面的方法创建代理对象(代理类)

在这里插入图片描述
方法有三个参数:(参考康师傅 Java 基础)
参数1:当前被代理类的类加载器;
参数2:增强方法所在的类,这个类实现的接口,支持多个接口;
参数3:接口 InvocationHandler 的一个实现类:该实现类通过 invoke 调用被代理类中想要被增强的方法,并在其中写增强方法。

  1. 定义代理类实现 InvocationHandler 接口
class MyInvocationHandler implements InvocationHandler {

    //1 创建的是谁的代理对象,就把谁传递过来
    //有参数构造传递
    private Object obj;

    public MyInvocationHandler(Object obj) {
        this.obj = obj;
    }

    //增强的逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //方法之前
        System.out.println("方法之前执行...." + method.getName() + " :传递的参数..." + Arrays.toString(args));

        //被增强的方法执行
        Object res = method.invoke(obj, args);

        //方法之后
        System.out.println("方法之后执行...." + obj);
        return res;
    }
}

注意:

  • 这里面需要将被代理类通过有参构造传进来;
  • 当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke(),这时底层实现的。
  • 被代理类要执行的方法a的功能就声明在 invoke() 中
  • invoke 方法里面有你的代理类,你当前想增强的方法,这个方法传进来的参数。
  1. 测试,这里这个老师和康师傅讲的不一样,下面康师傅的代码:

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

其实两个代码同理:

① 表示被代理类对象
② 表示根据该代理类生成了一个代理类对象
③ 代理类调用 被代理类中的某方法 a,那么执行该方法,和 MyInvocationHandler 中定义的增强方法或者通用方法。

执行结果:

在这里插入图片描述

3.5 CGLIB动态代理(当想增强的功能没有接口的时候)

3.5.1 准备工作

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

3.5.2 使用注解实现基于 AspectJ 的 AOP 操作

  1. 引入 AspectJ 依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.3.20</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.20</version>
</dependency>

<!-- https://mvnrepository.com/artifact/net.sourceforge.cglib/com.springsource.net.sf.cglib -->
<dependency>
    <groupId>net.sourceforge.cglib</groupId>
    <artifactId>com.springsource.net.sf.cglib</artifactId>
    <version>2.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aopalliance/com.springsource.org.aopalliance -->
<dependency>
    <groupId>org.aopalliance</groupId>
    <artifactId>com.springsource.org.aopalliance</artifactId>
    <version>1.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/com.springsource.org.aspectj.weaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>com.springsource.org.aspectj.weaver</artifactId>
    <version>1.7.2.RELEASE</version>
</dependency>

  1. 创建被增强类,其中有切入点 add() 方法
//被增强的类
public class User {
    public void add() {
        System.out.println("add.......");
    }
}
  1. 创建增强类(编写增强逻辑)
//增强的类
public class UserProxy {
    //前置通知
    public void before() {
        System.out.println("before.........");
    }
}
  1. 配置文件(注解)实现:

(1)开启组件扫描,xml文件中,别忘了增加 xml 文件开头的 aop 和 context 约束:

<context:component-scan base-package="com.atguigu.spring5.aopanno"></context:component-scan>

(2)创建增强类和被增强类的对象:@Component
(3)增强类上加 @Aspect 注解:生成代理对象
在这里插入图片描述

(4)开启生成代理对象,xml 文件中:

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  1. 配置不同类型的通知:

前置通知:@Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
后置通知:@AfterReturning,返回值之后执行
环绕通知:@Around,//被增强的方法执行,proceedingJoinPoint.proceed();
异常通知:@AfterThrowing
最终通知:@After,在方法之后执行,不管有没有异常都执行

//增强的类
@Component
@Aspect  //生成代理对象
public class UserProxy {

    //相同切入点抽取
    @Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void pointdemo() {

    }

    //前置通知
    //@Before注解表示作为前置通知
    @Before(value = "pointdemo()")
    public void before() {
        System.out.println("before.........");
    }

    //后置通知(返回通知)
    @AfterReturning(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void afterReturning() {
        System.out.println("afterReturning.........");
    }

    //最终通知
    @After(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void after() {
        System.out.println("after.........");
    }

    //异常通知
    @AfterThrowing(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void afterThrowing() {
        System.out.println("afterThrowing.........");
    }

    //环绕通知
    @Around(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕之前.........");

        //被增强的方法执行
        proceedingJoinPoint.proceed();

        System.out.println("环绕之后.........");
    }
}
  1. 相同切入点抽取:@Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))"),在配置注解之后使用 value = "pointdemo()" 来调用切入点方法即可,上述 前置增强已经使用。

  2. 测试

@Test
public void testAopAnno() {
    ApplicationContext context =
            new ClassPathXmlApplicationContext("bean1.xml");
    User user = context.getBean("user", User.class);
    user.add();
}

没有异常的时候:

在这里插入图片描述

有异常的时候:
在这里插入图片描述

3.5.3 设置增强类优先级

在这里插入图片描述
默认的 Order 值,非常大,即优先级非常低,所以只要设置了数字就会先执行:

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

3.5.4 完全注解开发

在这里插入图片描述
测试:

//测试完全注解开发
@Test
public void testAopFullyAnno() {

    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigAop.class);
    User user = context.getBean("user", User.class);
    user.add();
}

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值