聊聊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的理解。


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


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

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
87 2
|
1月前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
54 2
|
2月前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
1月前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
2月前
|
监控 安全 Java
什么是AOP?如何与Spring Boot一起使用?
什么是AOP?如何与Spring Boot一起使用?
73 5
|
2月前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
77 8
|
2月前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
2月前
|
XML 监控 安全
深入调查研究Spring AOP
【11月更文挑战第15天】
49 5
|
2月前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
49 4
|
2月前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
45 1