• Spring-Aop面向切面编程



    一、简介

    • AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构。

      • OOP(Object Oriented Programming)面向对象编程

    1、作用

    • 在不惊动原始设计的基础上为其进行功能增强
    • Spring理念:无入侵式
    • 核心概念
      • 代理(Proxy):SpringAOP的核心本质是采用代理模式实现的
      • 连接点(JoinPoint):在SpringAOP中,理解为任意方法的执行
      • 切入点(Pointcut):匹配连接点的式子,也是具有共性功能的方法描述
      • 通知(Advice):若干个方法的共性功能,在切入点处执行,最终体现为一个方法
      • 切面(Aspect):描述通知与切入点的对应关系
      • 目标对象(Target):被代理的原始对象成为目标对象

    2、AOP核心概念

    • 连接点(JoinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等
      • 在SpringAOP中,理解为方法的执行
    • 切入点(Pointcut):匹配连接点的式子
      • 在SpringAOP中,一个切入点可以描述一个具体方法,也可也匹配多个方法
        • 一个具体的方法:如com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
        • 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
      • 连接点范围要比切入点范围大,是切入点的方法也一定是连接点,但是是连接点的方法就不一定要被增强,所以可能不是切入点。
    • 通知(Advice):在切入点处执行的操作,也就是共性功能
      • 在SpringAOP中,功能最终以方法的形式呈现
    • 通知类:定义通知的类
    • 切面(Aspect):描述通知与切入点的对应关系。

    3、五种(增强)通知类型

    • 1、前置增强:在执行业务方法之前先执行的增强方法
    • 2、后置增强:在执行业务方法之后没有出现异常情况下执行的增强方法
    • 3、异常增强:在执行业务方法的过程中出现了异常的情况下执行的增强方法
    • 4、最终增强:在执行业务方法中不管有没有异常都会执行的增强方法
    • 5、环绕增强(重点)
      • 环绕通知依赖形参ProceedingJoinPoint才能实现对原始方法的调用
      • 环绕通知可以隔离原始方法的调用执行
      • 环绕通知返回值设置为Object类型
      • 环绕通知中可以对原始方法调用过程中出现的异常进行处理

    二、AOP入门小案例(注解版)

    在方法执行前输出当前系统时间。

    在这里插入图片描述

    1.导入坐标(pom.xml)

    <dependencies>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>5.2.10.RELEASEversion>
        dependency>
        <dependency>
        <groupId>org.aspectjgroupId>
        <artifactId>aspectjweaverartifactId>
        <version>1.9.4version>
    	dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 因为spring-context中已经导入了spring-aop,所以不需要再单独导入spring-aop
    • 导入AspectJ的jar包,AspectJ是AOP思想的一个具体实现,Spring有自己的AOP实现,但是相比于AspectJ来说比较麻烦,所以我们直接采用Spring整合ApsectJ的方式进行AOP开发。

    2.制作连接点(原始操作,Dao接口与实现类)

    public interface BookDao {
        public void save();
        public void update();
    }
    
    @Repository
    public class BookDaoImpl implements BookDao {
    
        public void save() {
            System.out.println(System.currentTimeMillis());
            System.out.println("book dao save ...");
        }
    
        public void update(){
            System.out.println("book dao update ...");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3:定义通知类和通知

    public class MyAdvice {
        public void method(){
            System.out.println(System.currentTimeMillis());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4:定义切入点

    public class MyAdvice {
        @Pointcut("execution(void com.itheima.dao.BookDao.update())")
        private void pt(){}
        public void method(){
            System.out.println(System.currentTimeMillis());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    切入点定义依托一个不具有实际意义的方法进行,即无参数、无返回值、方法体无实际逻辑。

    5:制作切面

    public class MyAdvice {
        @Pointcut("execution(void com.itheima.dao.BookDao.update())")
        private void pt(){}
        
        @Before("pt()")
        public void method(){
            System.out.println(System.currentTimeMillis());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    6:将通知类配给容器并标识其为切面类

    @Component
    @Aspect
    public class MyAdvice {
        @Pointcut("execution(void com.itheima.dao.BookDao.update())")
        private void pt(){}
        
        @Before("pt()")
        public void method(){
            System.out.println(System.currentTimeMillis());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    7:开启注解格式AOP功能

    @Configuration
    @ComponentScan("com.itheima")
    @EnableAspectJAutoProxy
    public class SpringConfig {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    8:运行程序

    public class App {
        public static void main(String[] args) {
            ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
            BookDao bookDao = ctx.getBean(BookDao.class);
            bookDao.update();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注:报错解决:Unsupported class file major version 61

    jdk版本过高

    • 目前的最新版本springboot2.5.4最高支持JDK16

    注解1:@EnableAspectJAutoProxy

    名称@EnableAspectJAutoProxy
    类型配置类注解
    位置配置类定义上方
    作用开启注解格式AOP功能

    注解2:@Aspect

    名称@Aspect
    类型类注解
    位置切面类定义上方
    作用设置当前类为AOP切面类

    注解3:@Pointcut

    名称@Pointcut
    类型方法注解
    位置切入点方法定义上方
    作用设置切入点方法
    属性value(默认):切入点表达式

    注解4:@Before

    名称@Before
    类型方法注解
    位置通知方法定义上方
    作用设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法前运行

    三、AOP的工作流程

    1:Spring容器启动
    2:读取所有切面配置中的切入点
    3:初始化bean
    4:获取bean执行方法

    四、AOP配置管理

    1、AOP切入点表达式

    • 切入点:要进行增强的方法
    • 切入点表达式:要进行增强的方法的描述方式

    1.1 格式

    描述方式一:执行com.itheima.dao包下的BookDao接口中的无参数update方法

    execution(void com.itheima.dao.BookDao.update())
    
    • 1

    描述方式二:执行com.itheima.dao.impl包下的BookDaoImpl类中的无参数update方法

    execution(void com.itheima.dao.impl.BookDaoImpl.update())
    
    • 1

    因为调用接口方法的时候最终运行的还是其实现类的方法,所以上面两种描述方式都是可以

    对于切入点表达式的语法为:

    • 切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数) 异常名)

    对于这个格式,我们不需要硬记,通过一个例子,理解它:

    execution(public User com.itheima.service.UserService.findById(int))
    
    • 1
    • execution:动作关键字,描述切入点的行为动作,例如execution表示执行到指定切入点
    • public:访问修饰符,还可以是public,private等,可以省略
    • User:返回值,写返回值类型
    • com.itheima.service:包名,多级包使用点连接
    • UserService:类/接口名称
    • findById:方法名
    • int:参数,直接写参数的类型,多个类型用逗号隔开
    • 异常名:方法定义中抛出指定异常,可以省略

    1.2通配符

    • *:单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
      execution(public * com.itheima.*.UserService.find*(*))
    
    • 1

    匹配com.itheima包下的任意包中的UserService类或接口中所有find开头的带有一个参数的方法

    • ..:多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
      execution(public User com..UserService.findById(..))
    
    • 1

    匹配com包下的任意包中的UserService类或接口中所有名称为findById的方法

    • +:专用于匹配子类类型
      execution(* *..*Service+.*(..))
    
    • 1

    这个使用率较低,描述子类的,咱们做JavaEE开发,继承机会就一次,使用都很慎重,所以很少用它。*Service+,表示所有以Service结尾的接口的子类。

    • 案例:
      在这里插入图片描述
    execution(void com.itheima.dao.BookDao.update())
    匹配接口,能匹配到
    execution(void com.itheima.dao.impl.BookDaoImpl.update())
    匹配实现类,能匹配到
    execution(* com.itheima.dao.impl.BookDaoImpl.update())
    返回值任意,能匹配到
    execution(* com.itheima.dao.impl.BookDaoImpl.update(*))
    返回值任意,但是update方法必须要有一个参数,无法匹配,要想匹配需要在update接口和实现类添加参数
    execution(void com.*.*.*.*.update())
    返回值为void,com包下的任意包三层包下的任意类的update方法,匹配到的是实现类,能匹配
    execution(void com.*.*.*.update())
    返回值为void,com包下的任意两层包下的任意类的update方法,匹配到的是接口,能匹配
    execution(void *..update())
    返回值为void,方法名是update的任意包下的任意类,能匹配
    execution(* *..*(..))
    匹配项目中任意类的任意方法,能匹配,但是不建议使用这种方式,影响范围广
    execution(* *..u*(..))
    匹配项目中任意包任意类下只要以u开头的方法,update方法能满足,能匹配
    execution(* *..*e(..))
    匹配项目中任意包任意类下只要以e结尾的方法,update和save方法能满足,能匹配
    execution(void com..*())
    返回值为void,com包下的任意包任意类任意方法,能匹配,*代表的是方法
    execution(* com.itheima.*.*Service.find*(..))
    将项目中所有业务层方法的以find开头的方法匹配
    execution(* com.itheima.*.*Service.save*(..))
    将项目中所有业务层方法的以save开头的方法匹配
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    Spring AOP的增强处理类型

    增强处理类型特点
    before前置增强处理,在目标方法前织入增强处理
    AfterReturning后置增强处理,在目标方法正常执行(不出现异常)后织入增强处理
    AfterThrowing异常增强处理,在目标方法抛出异常后织入增强处理
    After最终增强处理,不论方法是否抛出异常,都会在目标方法最后织入增强处理
    Around环绕增强处理,在目标方法的前后都可以织入增强处理
  • 相关阅读:
    Windows部署JMeter的压力测试
    【知识】超详细! 论文相关知识科普大全
    Bootstrap Blazor 实战 Menu 导航菜单使用(1)
    数据结构和算法(15):排序
    .NET开源、简单、实用的数据库文档生成工具
    操作系统——死锁及其解决方案(p38-p41王道视频、课本ch6)
    Software caused connection abort: recv failed
    python设计模式_Python六大原则,23种设计模式
    数据结构——排序の选择题整理
    高德POI搜索:地点关键词搜索
  • 原文地址:https://blog.csdn.net/qq_54351538/article/details/127759133