关键词:
说到面向切面编程,想必大家都不会陌生。不就是AOP——Aspect Orient Programming
但是说了那么久,你所理解的面向切面编程,用一句话概括到底是什么呢?
目录
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:环绕... 查看详情