聊聊Spring中的AOP(笔面试必问)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 我们在使用Spring框架的过程中,其实就是为了使用IOC和AOP,IoC容器是Spring的核心,AOP也是Spring框架的重要组成部分。之前的一篇文章聊聊Spring中IOC的基本原理介绍了Spring中Ioc的内容。那么这篇文章就来介绍Sping的Aop。

我们在使用Spring框架的过程中,其实就是为了使用IOC和AOP,IoC容器是Spring的核心,AOP也是Spring框架的重要组成部分。之前的一篇文章聊聊Spring中IOC的基本原理介绍了Spring中Ioc的内容。那么这篇文章就来介绍Sping的Aop。




1. 什么是AOP


在说AOP之前,先来聊聊一个和AOP很像的东西——OOP(是不是很像,就差一个字母)。


OOP是Object Oriented Programing的简称,也就是我们最常说的面向对象编程。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合,这也是OOP的三大特性。


1、封装


隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。


2、继承


就是子类自动继承其父级类中的属性和方法,并可以添加新的属性和方法或者对部分属性和方法进行重写。继承增加了代码的可重用性;继承是多态的前提。


3、多态


子类继承了来自父级类中的属性和方法,并对其中部分方法进行重写。于是多个子类中虽然都具有同一个方法,但是这些子类实例化的对象调用这些相同的方法后却可以获得完全不同的结果,这种技术就是多态性。父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提高了程序的拓展性。


由于这三大特性,可以采用OOP的编程思想设计出高内聚、低耦合的系统结构,使得系统更灵活、更容易扩展,而且成本较低。


但是,OOP允许我们定义从上到下的关系,但并不适合定义从左到右的关系。所以当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。比如最常用的日志功能。由于日志代码都是水平地分散在所有的对象层次中,但是又与它所分散到的对象的核心功能并没有什么关系。所以在OOP的设计思想中,它导致了大量代码的重复,而不利于各个模块的重用。


这种分散在各处的又无关的代码被称之为横切(cross-cutting)代码。既然OOP代码也存在不足之处,那么肯定有针对不足之处的解决办法。


AOP(Aspect-Oriented Programming,面向方面编程),可以说是对OOP的补充和完善。AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为 “Aspect”,翻译过来即切面,**方面,**所以AOP称之为面向切面编程。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任(比如日志代码、权限校验)封装起来,作为公共的方法或者接口进行调用。本来十个系统就有十个权限校验、日志的代码,这样进行处理之后就十个系统都调用这一个日志或者权限代码就可以了。这样就有利于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。


所以OOP代表的是一种上下的关系,而AOP代表的是一个横向的关系。


AOP把系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。AOP的作用就是将系统中的各种关注点,核心关注点和横切关注点切开。


2. AOP的一些重要概念


实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的 方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。它们都有一些共同的特性:


**Weaving:**即织入,就是通过动态代理,在目标对象方法中执行处理内容的过程。

Pointcut:即切点,决定公共业务如权限校验、日志记录等在何处切入业务代码中(即织入切面)。切点分为execution方式和annotation方式。前者可以用路径表达式指定哪些类织入切面,后者可以指定被哪些注解修饰的代码织入切面。

execution格式:


以 下面表达式为例:


@Pointcut("execution(* com.jiang.controller..*.*(..)))")
复制代码


第一个 * 号的位置:表示返回值类型,* 表示所有类型。


包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,在本例中指 com.mutest.controller包、子包下所有类的方法。


第二个 * 号的位置:表示类名,* 表示所有类。


*(..):这个星号表示方法名,* 表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。


annotation() 格式:

annotation() 方式是针对某个注解来定义切点,比如我们对具有 @RequestMapping 注解的方法做切面,可以如下定义切面:


@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
复制代码


Advice:处理,又称之为通知。是pointcut的执行代码,是执行“方面”的具体逻辑。包括处理时机和处理内容。处理内容就是要做什么事,比如校验权限和记录日志。处理时机就是在什么时机执行处理内容,分为前置通知(即业务代码执行前)、后置通知(业务代码执行后)等。常见的通知有:


前置通知 :方法执行前调用 ,对应的注解是 @Before


后置通知 ** :方法执行后调用 ,对应的注解是@After**


返回通知 ** :方法返回后调用 ,对应注解是@AfterReturning**


异常通知 :方法出现异常调用,对应注解是**@AfterThrowing**


环绕通知 ** :动态代理、手动推荐方法运行,对应的注解是@Around**


Aspect:即切面,pointcut和advice结合起来就是aspect,它类似于OOP中定义的一个类,但它代表的更多是对象间横向的关系。


Joint point:连接点,是程序执行的一个点。例如,一个方法的执行或者一个异常的处理。在 Spring AOP 中,一个连接点总是代表一个方法执行。

AOP的体系可以总结如下图所示:

e1d62c1544b54f89b7c1849a5ee5ce85~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg

3.举个栗子


这个例子的基础是之前的一篇文章的项目基础,这里就不再赘述,可以参考SpringBoot开发Restful风格的接口实现CRUD功能。在这个项目的基础之上,来演示AOP的使用,创建一个AOP相关类,如下所示:


package com.springboot.springbootdemo.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.SourceLocation;
import org.springframework.stereotype.Component;
/**
 * the simple demo for aop
 * author:jiangxia
 * date:2021-07-13
 */
@Aspect
@Component
public class LogInterceptor {
    //抽取公共的切入点表达式
    //1、本类引用
    //2、其他的切面引用
    // 定义一个切点:所有被RequestMapping注解修饰的方法会织入advice
    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public void aopMethod(){
    }
    //@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
    @Before("aopMethod()")
    public void before(){
        System.out.println("aopMethod start");
    }
    @Around("aopMethod()")
    public Object Around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("aopMethod Around");
        SourceLocation sl = jp.getSourceLocation();
        Object ret = jp.proceed();
        System.out.println(jp.getTarget());
        return ret;
    }
    @After("aopMethod()")
    public void after() {
        System.out.println("aopMethod after");
    }
    @AfterReturning("aopMethod()")
    public void AfterReturning() {
        System.out.println("aopMethod AfterReturning");
    }
    @AfterThrowing("aopMethod()")
    public void AfterThrowing() {
        System.out.println("aopMethod AfterThrowing");
    }
}
复制代码


然后启动项目:


8557a37c6db34097a08768bd0b0f3f5e~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


这里以查询所有数据的请求为例,地址栏输入:


微信图片_20220516180828.png


控制台也打印了相关信息:


0bd35e7cf6ed4db5b4d84ad50ebd2f26~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp (1).jpg

4. 总结


Spring中的两大核心就是IOC和AOP。


在传统的程序设计中,当调用者需要被调用者的协助时,通常由调用者来创建被调用者的实例。但在spring里创建被调用者的工作不再由调用者来完成,因此控制反转(IoC);创建被调用者实例的工作通常由spring容器来完成,然后注入调用者,因此也被称为依赖注入(DI),依赖注入和控制反转是同一个概念。关于IOC的具体内容可以参考:聊聊Spring中IOC的基本原理


这篇文章主要介绍了Spring中AOP的编程思想,AOP(面向切面编程)可以看成是对OOP(面向对象编程)的补充和拓展。AOP是以另一个角度来考虑程序结构,通过分析程序结构的关注点来完善OOP。OOP将应用程序分解成各个层次的对象,而AOP将程序分解成多个切面。AOP只实现了方法级别的连接点,这在J2EE应用中就已经足够了。在spring中,为了使IoC方便地使用健壮、灵活的企业服务,需要利用spring AOP实现为IoC和企业服务之间建立联系。


IOC采用的设计模式就是典型的工厂模式,主要通过sessionfactory去注入实例。而AOP就是典型的代理模式的体现。


Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来,降低代码的耦合度,提高代码的可重复性和可拓展性,大大减少代码量。


以上就是我对于AOP的理解。


如果你觉得本文不错,就点赞分享给更多的人吧!


如果你觉得文章有不足之处,或者更多的想法和理解,欢迎指出讨论!

相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
目录
相关文章
|
1月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
314 0
|
5月前
|
监控 安全 Java
Spring AOP实现原理
本内容主要介绍了Spring AOP的核心概念、实现机制及代理生成流程。涵盖切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)等关键概念,解析了JDK动态代理与CGLIB代理的原理及对比,并深入探讨了通知执行链路和责任链模式的应用。同时,详细分析了AspectJ注解驱动的AOP解析过程,包括切面识别、切点表达式匹配及通知适配为Advice的机制,帮助理解Spring AOP的工作原理与实现细节。
|
2月前
|
人工智能 监控 安全
Spring AOP切面编程颠覆传统!3大核心注解+5种通知类型,让业务代码纯净如初
本文介绍了AOP(面向切面编程)的基本概念、优势及其在Spring Boot中的使用。AOP作为OOP的补充,通过将横切关注点(如日志、安全、事务等)与业务逻辑分离,实现代码解耦,提升模块化程度、可维护性和灵活性。文章详细讲解了Spring AOP的核心概念,包括切面、切点、通知等,并提供了在Spring Boot中实现AOP的具体步骤和代码示例。此外,还列举了AOP在日志记录、性能监控、事务管理和安全控制等场景中的实际应用。通过本文,开发者可以快速掌握AOP编程思想及其实践技巧。
|
2月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
2月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
|
4月前
|
设计模式 算法 架构师
京东二面:说下spring中常用的设计模式? (一个 深入骨髓的答案, 面试官跪下了)
京东二面:说下spring中常用的设计模式? (一个 深入骨髓的答案, 面试官跪下了)
京东二面:说下spring中常用的设计模式? (一个 深入骨髓的答案, 面试官跪下了)
|
9月前
|
前端开发 安全 Java
2025春招,Spring 面试题汇总
本文详细整理了2025年春招必备的Spring面试题,分为基础和高级两大部分,帮助求职者全面掌握Spring相关知识点,结合实际项目经验,提升面试成功率。内容涉及Spring框架、AOP、事务管理、数据库集成、Spring Boot、Spring Security、微服务架构等,助力你在春招中脱颖而出。
1647 0
|
8月前
|
XML Java 测试技术
Spring AOP—通知类型 和 切入点表达式 万字详解(通俗易懂)
Spring 第五节 AOP——切入点表达式 万字详解!
414 25
|
8月前
|
XML 安全 Java
Spring AOP—深入动态代理 万字详解(通俗易懂)
Spring 第四节 AOP——动态代理 万字详解!
324 24
|
7月前
|
Java API 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——Spring Boot 中的 AOP 处理
本文详细讲解了Spring Boot中的AOP(面向切面编程)处理方法。首先介绍如何引入AOP依赖,通过添加`spring-boot-starter-aop`实现。接着阐述了如何定义和实现AOP切面,包括常用注解如`@Aspect`、`@Pointcut`、`@Before`、`@After`、`@AfterReturning`和`@AfterThrowing`的使用场景与示例代码。通过这些注解,可以分别在方法执行前、后、返回时或抛出异常时插入自定义逻辑,从而实现功能增强或日志记录等操作。最后总结了AOP在实际项目中的重要作用,并提供了课程源码下载链接供进一步学习。
800 0

热门文章

最新文章