Spring Boot AOP解析

Spring Boot AOP

面向切面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP)。
OOP中模块化的关键单元是类,而在AOP中,模块化单元是方面。

AOP(Aspect Oriented Program) 面向切面编程

在面向切面编程的思想里面,把功能分为核心业务功能和周边功能。

  • 核心业务,比如登陆,增加数据,删除数据都叫核心业务
  • 周边功能,比如性能统计,日志,事务管理等等

周边功能在 Spring Boot 的面向切面编程AOP思想里,即被定义为切面
在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发,然后把切面功能和核心业务功能 "编织" 在一起,这就叫AOP编程

AOP 的目的

AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。

AOP概念

  • 切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。
  • 连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。
  • 通知(Advice):在切面的某个特定的连接点上执行的动作。其中包括了“around”、“before”和“after”等不同类型的通知。许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。
  • 切入点(Pointcut):匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。
  • 引入(Introduction):用来给一个类型声明额外的方法或属性。
  • 目标对象(Target Object): 被一个或者多个切面所通知的对象。也被称做被通知(advised)对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。
  • AOP代理(AOP Proxy):AOP框架创建的对象,用来实现切面契约(例如通知方法执行等等)。在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
  • 织入(Weaving):把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。

通知类型:

  • 前置通知(Before advice):在某连接点之前执行的通知,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常)。
  • 后置通知(After returning advice):在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
  • 异常通知(After throwing advice):在方法抛出异常退出时执行的通知。
  • 最终通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
  • 环绕通知(Around Advice):包围一个连接点的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它自己的返回值或抛出异常来结束执行。

举个栗子

为了更好的说明 AOP 的概念,我们来举一个实际中的例子:

(

aop.png)

在上面的例子中,房东的核心业务就是签合同,收房租,白色底框起来的部分都是重复且边缘的事,交给中介就好了,这就是 AOP 的一个思想:让关注点代码与业务代码分离。

我们来实际用代码感受一下

java代码目录如下:

demo
  +- aop
    +- monitor
      +- Agent.java                                 中介类(切面)
    +- service
      +- Landlord.java                              房东
    +- DemoAopApplication                           启动器

房东类(Landlord)

    @Component
    // 房东只要关心自己的核心业务功能
    public class Landlord {
        @Value("${landlord:某某}")
        private String landlord;

        public void service() {
            System.out.println(landlord + "负责签合同");
            System.out.println(landlord + "负责收房租");
        }
    }

创建切面(中介类)

    @Component
    @Aspect
    //切面类,重复边缘的事情交给中介做
    public class Agent {
        @Value("${agent:某某中介}")
        private String agent;

        @Pointcut("execution(* demo.aop.service.Landlord.service())")
        public void IService() {
        }

        @Before("IService()")
        public void before() {
            System.out.println(agent + "带租客看房");
            System.out.println(agent + "谈价格");
        }

        @After("IService()")
        public void after() {
            System.out.println(agent + "交钥匙");
        }
    }
注意: 被定义为切面的类仍然是一个 Bean ,需要 @Component 注解标注

Spring 中的 AspectJ 注解:

注解 说明
@Before 前置通知,在连接点方法前调用
@Around 环绕通知,它将覆盖原有方法,但是允许你通过反射调用原有方法
@After 后置通知,在连接点方法后调用
@AfterReturning 返回通知,在连接点方法执行并正常返回后调用,要求连接点方法在执行过程中没有发生异常
@AfterThrowing 异常通知,当连接点方法异常时调用

通过上表,我们知道 before() 方法是连接点方法调用前调用的方法,而 after() 方法则相反,这些注解中间使用了定义切点的正则表达式

定义切点

在上面的注解中定义了 execution 的正则表达式,Spring 通过这个正则表达式判断具体要拦截的是哪一个类的哪一个方法:
execution(* demo.aop.service.Landlord.service())

依次对这个表达式作出分析:

execution:代表执行方法的时候会触发

    • :代表任意返回类型的方法
  • demo.aop.service.Landlord.service():被拦截的方法名称

通过上面的表达式,Spring 就会知道应该拦截 demo.aop.service.Landlord 类下的 service() 方法。重复定义正则表达式很麻烦,例子中使用 @Pointcut 注解来定义一个切点来避免重复写正则表达式:

application.properties配置房东和中介名称

    landlord:bigValiant
    agent:中介小姐姐

执行DemoAopApplication启动器效果如下

    中介小姐姐带租客看房
    中介小姐姐谈价格
    bigValiant负责签合同
    bigValiant负责收房租
    中介小姐姐交钥匙

Spring还支持XML配置AOP编程

资料

原文地址:https://www.cnblogs.com/tqlin/p/10999345.html

时间: 2024-08-01 08:39:33

Spring Boot AOP解析的相关文章

Spring Boot AOP之对请求的参数入参与返回结果进行拦截处理

Spring Boot AOP之对请求的参数入参与返回结果进行拦截处理 本文链接:https://blog.csdn.net/puhaiyang/article/details/78146620 本文链接:https://blog.csdn.net/puhaiyang/article/details/78146620 spring Aop切面中的@Before @Around等执行顺序与请求参数统一解码 https://www.cnblogs.com/newAndHui/p/11771035.h

spring boot aop打印http请求回复日志包含请求体

一.引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>

spring cloud zipkin sleuth与spring boot aop结合后,启动慢

问题描述: 引入了spring cloud的监控starter,间接引入jooq. 又引入了 spring-boot-starter-web,所以间接引入aop. 参考下面资料后:https://github.com/jOOQ/jOOQ/issues/5902 发现可以通过修改aop表达式解决. 于是修改aop表达式如下: 问题解决. 原文地址:https://www.cnblogs.com/grey-wolf/p/8296026.html

Spring Boot AOP Demo

什么是AOP? AOP面向切面,切面将那些与业务无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性. 实现策略JAVA SE动态代理 CGLib 相关注解 @Aspect(方面) @Pointcut(切入点) @Before(之前) @After(之后) pom.xml <!--引用AOP--> <dependency> <groupId>org.springframework.boot</gro

Spring Boot AOP 简易操作日志管理

AOP (Aspect Oriented Programming) 面向切面编程. 业务有核心业务和边缘业务. 比如用户管理,菜单管理,权限管理,这些都属于核心业务. 比如日志管理,操作记录管理,这些都是边缘业务,可以统一的提出来. 尝试使用SpringBoot +AOP 提出操作记录业务. github aop_demo package com.lick.aspect.lang.annotation; import com.lick.aspect.lang.enums.BusinessType

spring boot aop日志管理(MongoDB)

aop拦截的是controller层请求,正常的请求用@Before来拦截, 异常的请求用@AfterThrowing来拦截 1.引用aop jar包 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>2.0.3.RELEASE</version>

spring boot aop

这里要做就是利用aop 来打印请求的日志,返回结果,简单的异常处理 一:使用@Aspect注解创建切面,类名是 RquestAspect import javax.servlet.http.HttpServletRequest; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.as

spring boot aop 报错

1.控制台报错 Pointcut is not well-formed: expecting 'name pattern' at character position 33 execution(com.stu.controller.*.*(..)) 2.eclipse提示 Pointcut is malformed: Pointcut is not well-formed: expecting 'name pattern' at character position 33 execution(c

面试那点小事,你从未见过的spring boot面试集锦(附详细答案)

一, 什么是spring boot? 多年来,随着新功能的增加,spring变得越来越复杂.只需访问页面https://spring.io/projects,我们将看到所有在应用程序中使用的不同功能的spring项目.如果必须启动一个新的spring项目,我们必须添加构建路径或maven依赖项,配置application server,添加spring配置.因此,启动一个新的spring项目需要大量的工作,因为我们目前必须从头开始做所有事情.Spring Boot是这个问题的解决方案.Sprin