首页 > 其他分享 >Spring系列之(八)Spring中的AOP

Spring系列之(八)Spring中的AOP

时间:2024-02-27 20:59:25浏览次数:32  
标签:系列 int Spring 切入点 AOP 通知 方法

Spring中的AOP

通过配置(XML/注解)实现AOP

1. AOP相关术语

1.1 连接点

方法,Service接口中的所有方法

1.2 切入点

方法,Service接口中被增强过的方法

Tip:所有的切入点都是连接点

1.3 通知

方法,通常,具有增强功能的方法会放到一个类中,该类中所有用于增强的方法就被称为通知

分类:

  1. 前置通知
  2. 后置通知
  3. 异常通知
  4. 最终通知
  5. 环绕通知

在这里插入图片描述

1.4 目标对象

被代理对象

1.5 织入

过程,把增强方法应用到被代理对象来创建新的代理对象的过程

1.6 代理

代理对象

1.7 切面

描述通知是在切入点执行的具体什么时间点执行的,如切入点之前执行切入点之后执行切入点发生异常时执行....标红的部分就是切面

2. Spring AOP在实际项目开发中要做的事

开发阶段:

  1. 编写核心业务代码,实现业务功能,大部分开发人员都可做
  2. 抽取公共代码,制作成通知(开发最后阶段做),高级开发可做
  3. 在配置文件中,配置切面,高级开发可做

运行阶段:
Spring框架监控切入点的执行,一旦监控到切入点被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

3. Spring基于XML的AOP配置步骤

  1. 导入aop约束
    在这里插入图片描述
    参考网址:Spring Framework 中文文档

  2. 创建业务层接口实现类的Bean对象
    在这里插入图片描述

  3. 创建通知类的Bean对象
    在这里插入图片描述

  4. 使用<aop:config>标签表明开始AOP的配置

  5. 使用<aop:aspect>标签表明配置切面
    id属性:切面的唯一标识
    ref属性:指定通知类Bean的id

  6. <aop:aspect>标签内部配置通知的类型
    <aop:before>:前置通知,在切入点之前执行
    method属性:指定通知类中哪个方法用于前置通知
    pointcut属性:指定切入点表达式,用于指定对业务层中的哪些方法进行增强,也就是设置的通知是用在哪个方法上的
    <aop:after-returning>:后置通知,在切入点正常执行之后执行,后置通知和异常通知只能执行一个
    method属性:指定通知类中哪个方法用于后置通知
    pointcut属性:指定切入点表达式,用于指定对业务层中的哪些方法进行增强,也就是设置的通知是用在哪个方法上的
    <aop:after-throwing>:异常通知,在切入点执行产生异常之后执行
    method属性:指定通知类中哪个方法用于异常通知
    pointcut属性:指定切入点表达式,用于指定对业务层中的哪些方法进行增强,也就是设置的通知是用在哪个方法上的
    <aop:after>:最终通知,无论切入点是否正常执行都会在切入点之后执行
    method属性:指定通知类中哪个方法用于最终通知
    pointcut属性:指定切入点表达式,用于指定对业务层中的哪些方法进行增强,也就是设置的通知是用在哪个方法上的
    <aop:around>:环绕通知
    method属性:指定通知类中哪个方法用于环绕通知
    pointcut属性:指定切入点表达式,用于指定对业务层中的哪些方法进行增强,也就是设置的通知是用在哪个方法上的

​ 【环绕通知好像是完全自己来写各种通知】

切入点表达式

1. 关键字:execution(表达式)
2. 构成:访问修饰符 返回值 包名.包名....类名.方法名(参数列表)
3. 标准的表达式举例:

public void com.itheima.service.impl.AccountServiceImpl.saveAccount(int)
访问修饰符可以省略
void com.itheima.service.impl.AccountServiceImpl.saveAccount(int)
返回值可以使用通配符,表示任意返回值
*&nbsp;com.itheima.service.impl.AccountServiceImpl.saveAccount(int)
包名可以使用通配符,表示任意包,但是有几级包,就需要写几组 \*.
\*&nbsp;\*.\*.\*.\*.AccountServiceImpl.saveAccount(int)
包名可以使用. .表示当前包及其子包
\*&nbsp;\*. .AccountServiceImpl.saveAccount(int)
类名和方法名都可以使用\*来实现通配
\*&nbsp;\*. .\*.\*(int)
参数列表:可以直接写数据类型,基本类型写名称,引用类型写`包名.类名`的方式,可以使用通配符表示任意类型,但是必须有参数;可以使用. .表示有无参数均可,有参数可以是任意类型
\*&nbsp;\*. .\*.\*(\*)
\*&nbsp;\*. .\*.\*(. .)

4. 全通配写法
   \*&nbsp;&nbsp;*. . * . *(. .)
5. 实际开发中切入表达式的通常写法

\*&nbsp;com.itheima.service.impl.\*.\*(. .)
  1. 通用化切入点表达式(抽取出切入点表达式,使用时通过id调用)
    <aop:pointcut>标签:用于定义切入点表达式,可供调用
    id属性:表达式的唯一标识
    expression属性:表达式
    <aop:pointcut>标签的位置:位于<aop:aspect>标签内部,只能用于当前切面;位于<aop:config>标签内部,可以用于所有切面
    在这里插入图片描述
    Tip:<aop:pointcut>标签放在<aop:config>标签内部,必须放在<aop:aspect>标签之前

4. Spring基于XML的AOP实例

4.1 pom中导入坐标

在这里插入图片描述

4.2 业务层接口和实现类

IAccountService

package com.itheima.service;

/**
 * @author 商务小本本
 */
public interface IAccountService {

    void selectAccount();

    void saveAccount(int account);

    int updateAccount();

    int deleteAccount(int account);
}

AccountServiceImpl实现类

package com.itheima.service.impl;

import com.itheima.service.IAccountService;

/**
 * @author 商务小本本
 */
public class AccountServiceImpl implements IAccountService {
    public void selectAccount() {
        System.out.println("selectAccount方法");
    }

    public void saveAccount(int account) {
        System.out.println("saveAccount方法");
    }

    public int updateAccount() {
        System.out.println("updateAccount方法");
        return 0;
    }

    public int deleteAccount(int account) {
        System.out.println("deleteAccount方法");
        return 0;
    }
}

4.3 通知所在的类

package com.itheima.logger;

/**
 * @author 商务小本本
 */
public class Logger {

    void beforeAdvice(){
        System.out.println("前置通知");
    }

    void afterReturnAdvice(){
        System.out.println("后置通知");
    }

    void afterThrowAdvice(){
        System.out.println("异常通知");
    }

    void afterAdvice(){
        System.out.println("最终通知");
    }
}

4.4 配置文件

  1. 引入AOP约束
<?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: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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
  1. 创建Service对象
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
  1. 创建通知类对象
<bean id="logger" class="com.itheima.logger.Logger"></bean>
  1. 配置切面
<aop:config>
        <aop:pointcut id="pt1" expression="execution(void com.itheima.service.impl.AccountServiceImpl.saveAccount(..))"/>
        <aop:aspect id="loggerAdvice" ref="logger">
            <aop:before method="beforeAdvice" pointcut-ref="pt1"></aop:before>
            <aop:after-returning method="afterReturnAdvice" pointcut-ref="pt1"></aop:after-returning>
            <aop:after-throwing method="afterThrowAdvice" pointcut-ref="pt1"></aop:after-throwing>
            <aop:after method="afterAdvice" pointcut-ref="pt1"></aop:after>
        </aop:aspect>
    </aop:config>

4.5 测试

import com.itheima.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AopTest {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        IAccountService as = applicationContext.getBean("accountService", IAccountService.class);

        as.saveAccount(1);
    }
}

在这里插入图片描述

5. 环绕通知

Spring框架提供的一种可以在代码中手动控制增强方法何时执行的方式

Spring框架提供了一个接口,ProceedingJoinPoint,该接口的proceed方法相当于明确调用切入点方法,该接口可以作为环绕通知的方法参数,程序执行时,Spring框架会提供该接口的实现类供我们使用。

继续补充Spring基于XML的AOP实例的环绕通知部分

  1. 通知类中增加环绕通知,环绕通知的返回值要与切入点的返回值保持一致
Object arroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
    Object result = null;
    try {
        Object[] args = proceedingJoinPoint.getArgs();
        System.out.println("前置通知");
        result = proceedingJoinPoint.proceed(args);
        System.out.println("后置通知");

        return result;
    }catch (Throwable t){
        System.out.println("异常通知");
        throw new RuntimeException(t);
    }finally {
        System.out.println("最终通知");
    }
}
  1. bean.xml中配置环绕通知
    在这里插入图片描述
  2. 测试类
import com.itheima.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AopTest {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        IAccountService as = applicationContext.getBean("accountService", IAccountService.class);

        as.updateAccount();
    }
}
  1. 测试结果
    在这里插入图片描述

6. Spring基于注解的AOP实例

将上面基于XML的实例改为基于注解的实例

  1. bean.xml中引入注解相关的名称空间和约束
    在这里插入图片描述

  2. bean.xml中配置包扫描(扫描注解)和注解AOP支持
    在这里插入图片描述

  3. 使用注解配置Service创建和通知了创建
    在这里插入图片描述
    在这里插入图片描述
    Tip:Logger类不属于Web三层架构的任意一层,所以使用注解@Component
    作用等同于
    在这里插入图片描述

  4. 通用化切入点表达式的注解配置
    在这里插入图片描述
    作用等同于
    在这里插入图片描述

  5. 切面的注解配置
    在这里插入图片描述
    作用等同于
    在这里插入图片描述

  6. 测试类不变,测试结果如下
    在这里插入图片描述

  7. 接下来是配置环绕通知
    在这里插入图片描述
    作用等同于
    在这里插入图片描述
    Tip:注解AOP中尽量使用环绕通知,其他通知类型的执行顺序可能会出问题

7. Spring纯注解(不存在bean.xml)的AOP

配置类中使用注解@EnableAspectJAutoProxy
作用等同于
在这里插入图片描述

标签:系列,int,Spring,切入点,AOP,通知,方法
From: https://www.cnblogs.com/wzzzj/p/18038229

相关文章

  • Spring系列之(七)动态代理
    动态代理1.特点字节码随用随创建,随用随加载2.作用不修改类的源码基础上对类的方法进行增强3.分类基于接口的动态代理基于子类的动态代理4.基于接口的动态代理4.1涉及的类Proxy4.2提供者JDK官方4.3如何创建代理对象Proxy的newProxyInstance方法4.4创建代......
  • Spring系列之(六)Spring整合Junit
    Spring整合Junit上面部分的内容是把8.3.7节的第一个问题给解决了,我们来看第二个问题(测试代码开发和测试部分耦合度高,图中标红部分一般测试人员无法完成)pom中导入Spring整合Junit的坐标使用Junit提供的@RunWith注解把Junit原有的main方法替换成Spring提供的main方法告知Sprin......
  • Spring系列之(五)Spring基于注解的IOC
    Spring基于注解的IOC1.构建注解环境在beans.xml中加入context名称空间和约束<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&......
  • Spring系列之(四)Spring的依赖注入
    Spring的依赖注入在当前类需要用到其他类的对象,其他类的对象也是由Spring创建并将引用传递给当前类的对象的,我们只需要在配置文件中说明,说白了就是为当前类填充(也叫注入)其他类的对象1.能够注入的数据能够注入的数据是指支持注入的这部分数据是可以被Spring填充(注入)到当前类的......
  • Spring系列之(三)Spring对Bean的管理细节
    Spring对Bean的管理细节1.创建Bean的三种方式使用默认构造函数创建bean标签仅配置id和class,即标识和全限定类名,同时保证要创建的类是有无参构造函数的如果没有无参构造函数,将会报错使用某个类中的方法创建对象,该方法的返回值是某个类的对象以新建的Factory类为例,需......
  • Spring系列之(二)Spring基于XML的IOC实例
    Spring基于XML的IOC实例将改进后的工厂模式通过Spring来实现,解析配置文件、创建仓库,将对象存入仓库的过程都由Spring来做,我们只需要配置好配置文件,获取仓库中的对象即可1.在pom中引入Spring环境<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.o......
  • Spring系列之(一)Spring概述
    Spring概述1.程序的耦合耦合:程序间的依赖关系解耦:降低程序间的依赖关系分类类之间的依赖方法之间的依赖2.类之间的依赖问题的实例2.1JDBC操作数据库存在的耦合问题首先正常编写一个jdbc查询操作的类packagecom.itheima.jdbc;importjava.sql.*;publicclass......
  • spring boot 中使用MybatisPlus的自动填充createTime和updateTime
    首先需要在实体类的字段上加上注解,并且将类型更改为LocalDateTime@TableField(fill=FieldFill.INSERT)@JsonInclude(value=JsonInclude.Include.NON_NULL)@JsonFormat(pattern="yyyy-MM-ddHH:mm:ss")privateLocalDateTimecreateTime;@TableFie......
  • springboot学习过程中的特殊错误
     这是我在学习使用springboot过程中遇到的一个小问题,询问了gpt但是并没有解决我的报错,在网上浏览信息后最终知道了是哪里出了问题 就如这个好哥哥说的一样,mybatis自带的方法不会出现问题,所以问题出在了实体类定义上面,加了@Tableld的注解就解决了问题。......
  • 简单看下最近的Spring Secrurity、Spring漏洞(CVE-2024-22234、CVE-2024-22243)
    最近的这两个cve我看国内很多情报将其评为高危,所以想着去看看原理,看完发现都比较简单,利用要求的场景也相对有限(特别是第一个),所以就随便看下就行了SpringSecurity用户认证绕过(CVE-2024-22234)先看下官网的公告(https://spring.io/security/cve-2024-22234)InSpringSecurit......