(2021.9.25)面向切面编程简述(代码片段)

Mr.DreamerZ Mr.DreamerZ     2022-12-06     772

关键词:

说到面向切面编程,想必大家都不会陌生。不就是AOP——Aspect Orient Programming

但是说了那么久,你所理解的面向切面编程,用一句话概括到底是什么呢?

目录

1.什么是AOP(面向切面编程)

2.AOP相关术语

1.连接点(Joinpoint)

2.切点(Pointcut)

3.增强(Advice)

4.目标对象(Target)

5.引介(Introduction):

6.织入(Weaving):

7.代理(Proxy)

9.切面(Aspect)

3.实践

3.1 简单的自定义注解增强

3.2 通过指定类/方法进行增强


1.什么是AOP(面向切面编程)

在我的理解来说:

在运行时,动态的 将代码 切入到 类的 指定方法。  这种编程思想就称为面向切面编程

 

来举个例子吧,你写了A方法之后,老板想让你看看这段代码的执行时间。ok,那你就在A方法的前后加上代码,查看时间。。。

过了几天,你又完成了B方法之后,老板又想让看你记录这段代码的日志信息。没问题,加上

又过了几天,老板又要让你每个功能都加上日志功能。。。没过几天你就。。。

久而久之,你就发现,你的代码中会出现越来越多与业务无关的东西。后来你发现它们都是有共同点的,于是你将这些公共的代码整体抽成common方法进行调用,想办法降低耦合。但是由于是在方法中进行调用,该污染代码还是会污染,如果严格说来还是有很强的关联系的。比如说一旦涉及到部分参数的传递,那么耦合度还是很高的。

在你想解耦合且方便维护的时候,AOP出现了。

spring提供这个工具,让你能解决上述老板给你提出的这些要求,避免你修改次数太多删库跑路~

2.AOP相关术语

1.连接点(Joinpoint)

程序执行的某个特定位置:如类开始初始化前,类初始化后,类某个方法调用前。一个类或一段代码拥有一些边界性质的特定点,这些代码中的特定点就被称为“连接点”。Spring仅支持方法的连接点,既仅能在方法调用前,方法调用后,方法抛出异常时等这些程序执行点进行织入增强。

连接点由两个信息确定:第一是用方法表示的程序执行点;第二是用相对点表示的方位。如在Test.foo()方法执行前的连接点,执行点为Test.foo(),方位为该方法执行前的位置。Spring使用切点对执行点进行定位,而方位则在增强类型中定义。

2.切点(Pointcut)

每个程序类都拥有多个连结点,如一个拥有两个方法的类,这两个方法都是连接点,既连接点是程序中客观存在的事务。当某个连接点满足指定要求时,就可以被添加Advice,成为切点,比如:

pointcut xxxPorintcut()

:execution(void H*.say*())

每个方法被调用,都只是连接点,如果某个方法属于H开头的类,而且方法一say开头,则该方法就变成了切入点。如何使用表达式定义切入点,是AOP的核心,Spring默认使用AspectJ切入点语法。

3.增强(Advice)

连接上一条,你可以在切点这里做一些事情,有“around”,“before”,“after”等类型。

4.目标对象(Target)

被AOP框架进行增强处理的对象。如果是动态AOP的框架,则对象是一个被代理的对象。

5.引介(Introduction):

引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过AOP的引介功能,我们可以动态的为该事务添加接口的实现逻辑,让业务类成为这个接口的实现类。

6.织入(Weaving):

织入是将增强添加对目标类具体连接点上的过程,AOP象一台织布机,将目标类增强或引介AOP这台织布机天衣无缝的编织在一起。

7.代理(Proxy)

一个类被AOP织入增强后,就产生了一个结果类,它是融合了原类和增前逻辑的代理类。根据不同的代理方式,代理类及可能是和原类具有相同的接口的类,也可能是原类的子类,所以我们可以采用调用原类得相同方式调用代理类。

9.切面(Aspect)

切面由切点和增强(引介)组成,它既包括了横切逻辑的定义,也包括了连接点的定义,Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的链接点中。

以上内容其实一搜一大堆,个人认为需要认识理解的切点、增强、切面即可不需要去死记硬背这些点。使用的多了,会自然的熟悉这些知识点。实践出真理

简单的介绍一下,方便大家来记忆:

有一个方法a,但是这个方法只支持进行A操作。

增强这我想在这个方法a前/后添加一个B动作,那么这个增加的B动作就叫做增强。

切点,你针对这个a方法做了增强操作,那么这个a方法就称为切点

切面,切点和增点组成切面,它是一个大的概念,一个统称

3.实践

先给出控制层代码

@RestController
@RequestMapping(value = "/a")
public class AController 

    @GetMapping(value = "/test1")
    @PermissionAnnotation
    public String test1()
       return "a.test1";
    

    @GetMapping(value = "/test2")
    public String test2()
        return "a.test2";
    

@RestController
@RequestMapping(value = "/b")
public class BController 

    @GetMapping(value = "/test1")
    public String test1()
        return "b.test1";
    

    @GetMapping(value = "/test2")
    public String test2()
        return "b.test2";
    

3.1 简单的自定义注解增强

引入pom

   <!-- 引入aop切面支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

创建一个注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PermissionAnnotation 


创建对应的切面

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class TestAspect 

    @Pointcut("@annotation(com.example.aspectdemo.annotation.PermissionAnnotation)")
    private void permissionCheck() 

    

    @Before("permissionCheck()")
    public void doBefore() 
        System.out.println("doBefore");
    


    @Around("permissionCheck()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable 
        System.out.println("do something。。。before");
        return joinPoint.proceed();
    

    @After("permissionCheck()")
    public void doAfter() 
        System.out.println("doAfter");
    

调用方法: 直接调用方法,http://localhost:8888/a/test1

打印结果:

 让我们加断点进去看看

 从上面的几张图,我们可以看到一个较为详细的执行流程,为了加深印象大家可以自己创建之后跟进去试试看。这样会有更深的印象。

下面用一段代码来总结一下执行的流程。但是注意不管是前置通知还是后置通知,一定是要进入proceed()这个方法之后才会执行的,下面这样写只是为了方便去理解执行的流程

 try 
        //前置通知@Before
        System.out.println("环绕前置通知");
        //目标方法执行
        result = proceedingJoinPoint.proceed(args);
        //环绕返回通知@AfterReturning
        System.out.println("环绕返回通知");
     catch (Throwable throwable) 
        //环绕异常通知@AfterThrowing
        System.out.println("环绕异常通知");
        throw new RuntimeException(throwable);
     finally 
        //最终通知@After
        System.out.println("环绕最终通知");
    

其实也可以有多个@Before、@After联合使用。

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class TestAspect 

    @Before("permissionCheck()")
    public void doBeforeY() 
        System.out.println("doBeforeY");
    

    @Before("permissionCheck()")
    public void doBeforeX() 
        System.out.println("doBeforeX");
    

    @Before("permissionCheck()")
    public void doBeforey() 
        System.out.println("doBeforey");
    

    @Before("permissionCheck()")
    public void doBeforex() 
        System.out.println("doBeforex");
    

    @Before("permissionCheck()")
    public void doBefore2() 
        System.out.println("doBefore2");
    

    @Pointcut("@annotation(com.example.aspectdemo.annotation.PermissionAnnotation)")
    private void permissionCheck() 

    

    @Before("permissionCheck()")
    public void doBefore1() 
        System.out.println("doBefore1");
    


    @Around("permissionCheck()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable 
        System.out.println("do something。。。before");
        return joinPoint.proceed();
    

    @After("permissionCheck()")
    public void doAfter() 
        System.out.println("doAfter");
    

这段代码,我们就加入了很多的前置处理和后置处理。那它的运行结果是啥呢?大家可以猜猜看,是按照代码的顺序来执行呢?还是怎么来执行呢?

 可以明显的看一些端倪,当前执行的优先级:数字>大写字母>小写字母

其实执行顺序还有很多有趣的地方,这里就不再做过多的描述了。有兴趣的可以去看看aop从加载到执行的spring源码。

3.2 通过指定类/方法进行增强

不了解表达式的同学可以参考下这位大佬写的博客:spring AOP切面表达式详解_人有匪气,代码才能飞起-CSDN博客_切面表达式

下面列出一些常见的,方便大家进行对比实践

execution(public * *(..))  // 匹配任意公共方法
execution(* set*(..))      // 匹配任意名称为 set 开头的方法
execution(* com.xyz.service.AccountService.*(..))    // 匹配 AccountService 类中的任意方法
execution(* com.xyz.service.*.*(..))    // 匹配 com.xyz.service 包下的任意类的任意方法
execution(* com.xyz.service..*.*(..))    // 匹配 com.xyz.service 包及子包下的任意类的任意方法
​
within(com.xyz.service.*)    // 匹配 com.xyz.service 包下的任意类的任意方法
within(com.xyz.service..*)   // 匹配 com.xyz.service 包及子包下的任意类的任意方法

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class TestAspect 

    @Pointcut("execution(* com.example.aspectdemo.controller.BController.*(..))")
    private void pointCut() 

    

 
    @Around("pointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable 
        System.out.println("do something。。。before");
        return joinPoint.proceed();
    

    @Before("pointCut()")
    public void doBefore1() 
        System.out.println("doBefore1");
    

    @After("pointCut()")
    public void doAfter() 
        System.out.println("doAfter");
    

直接调用方法,http://localhost:8888/b/test1

得到结果:

(2021.9.25)面向切面编程简述(代码片段)

说到面向切面编程,想必大家都不会陌生。不就是AOP——AspectOrientProgramming但是说了那么久,你所理解的面向切面编程,用一句话概括到底是什么呢?目录1.什么是AOP(面向切面编程)2.AOP相关术语1.连接点(... 查看详情

aop面向切面编程(个人笔记1.1)(代码片段)

AOP面向切面编程AOP面向切面编程存在的实现方式经典的基于代理的AOP:AspectJAOP面向切面编程AOP(Aspect-OrientedProgramming:面向切面编程)将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权... 查看详情

面向切面编程(aop)(代码片段)

结合设计模式,通过代码理解面向切面编程通过,结构型设计模式,装饰器模式来实现AOP///<summary>///装饰器模式实现静态代理///AOP在方法前后增加自定义的方法///</summary>publicclassDecoratorAOPpublicstaticvoidShow()Useruser=newUser()Name="... 查看详情

spring框架--aop面向切面编程(代码片段)

...)–SpringBean管理Spring框架(三)–SpringJDBCSpring框架(四)–AOP面向切面编程Spring框架(五)–Spring事务管理和Spring事务传播行为AOP(AspectOrientedProgramming面向切面编程)不使用AOP的开发方式的例子先定义好接口与一个实现类 查看详情

spring详解------面向切面编程(代码片段)

、AOP什么?  AOP(AspectOrientedProgramming),通常称为面向切面编程。它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面"... 查看详情

什么是面向切面编程?(代码片段)

...#x1f498;一、前言💔二、专栏推荐💕三、初次见面-面向切面编程💖四、面向切面编程的作用 查看详情

springaop面向切面编程--准备工作(代码片段)

引言1.创建一个SomeService接口类publicinterfaceSomeServicevoiddoSome();voiddoOther();2.创建一个SomeService接口类的实现类SomeServiceImpl选择对目录👇publicclassSomeServiceImplimplementsSomeService@Overridepublicvoi 查看详情

面试题思考:解释一下什么叫aop(面向切面编程)(代码片段)

...将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。AOP是Spring提供的关键特性之一。AOP即面向切面编程,是OOP编程的有效补充。使用AOP技术,可以将一些系统性相关的编程工作,独立提取出来,独立实现,... 查看详情

springaop——spring中面向切面编程(代码片段)

...程思想1.1什么是AOPAOP(AspectOrientProgramming),直译过来就是面向切面编程。AOP是 查看详情

aop面向切面编程(代码片段)

概念AOP(AspectOrientedProgramming)称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等等。AOP利用一种称为"横切"的技术,将那些影响了多个类的公共行... 查看详情

aop面向切面编程(代码片段)

概念AOP(AspectOrientedProgramming)称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等等。AOP利用一种称为"横切"的技术,将那些影响了多个类的公共行... 查看详情

springaop面向切面编程,监听某个方法(代码片段)

1、单独监听某一个方法,方法的参数名称必须与args定义的参数名称一致@AfterReturning(pointcut="execution(*com.gmall88.server.manager.superapp.SuperAppServerManager.notifyRefund(..))&&args(notifyUrl,refundId,batchNo,callResult) 查看详情

springaop面向切面编程-异常+最终通知(了解)(代码片段)

...做通知注解。@Before:前置通知👉【Spring】AOP面向切面编程-前置通知(掌握)@AfterRetunring&# 查看详情

基于标注的aop面向切面编程(代码片段)

...是AOP  Aspect Orientied  Programming的简称,即面向(方面)切面编程,不改变一个组件源代码的情况下可以对组件功能进行增强。 例如:servlet中的过滤器,继承,装饰者模式,代理模式,JDK的代理必须有统一接口目标类和代... 查看详情

前端解读面向切面编程(aop)(代码片段)

前言面向对象(OOP)作为经典的设计范式,对于我们来说可谓无人不知,还记得我们入行起始时那句经典的总结吗-万事万物皆对象。是的,基于OOP思想封装、继承、多态的特点,我们会自然而然的遵循模块化、组件化的思维来设计... 查看详情

spring面向切面编程(aop)(代码片段)

Spring系列教程Spring框架介绍Spring框架模块Spring开发环境搭建(Eclipse)创建一个简单的Spring应用Spring控制反转容器(InversionofControl–IOC)理解依赖注入(DI–DependencyInjection)BeanXML配置(1)-通过XML配置加载BeanBeanXML配置(2)-Bean作... 查看详情

aop面向切面编程aop简介(aspectj简介|aspectj下载)(代码片段)

...三、AspectJ下载一、AOP简介AOP是AspectOrientedProgramming的缩写,面向切面编程;利用AOP面向切面编程,可以将业务逻辑的各个部分进行隔离,每个业务逻辑部分放在一个切面中实现,降低了各个业务逻辑之间的耦合程度,提高了程序的灵活性,... 查看详情

springaop面向切面编程-前置通知(代码片段)

总结:Aspectj表示切面执行时间,用的通知(Advice)。这个通知可以使用注解表示。5个注解表示切面的5个执行时间,这些注解叫做通知注解。@Before:前置通知@AfterRetunring:后置通知@Around:环绕... 查看详情