谈谈Spring AOP

简介: AOP,面向切面编程,主要的作用是可以将那些分散在业务系统中相同的代码抽取出来放到一个地方进行管理这么做的好处是减少了重复代码的编写,并且软件的可维护性也强为什么叫做面向切面编程呢?举个例子:假如我们的代码中,有许多以update开头的函数的执行都需要管理员权限。

AOP,面向切面编程,主要的作用是可以将那些分散在业务系统中相同的代码抽取出来放到一个地方进行管理
这么做的好处是减少了重复代码的编写,并且软件的可维护性也强

为什么叫做面向切面编程呢?
举个例子:假如我们的代码中,

  • 有许多以update开头的函数的执行都需要管理员权限。如果不使用AOP,那么我们在每个以update开头的函数中都要进行权限验证,这样导致了大量重复代码的产生
  • 与此同时,万一某天需求有变,不再限制只有管理员才能执行这些函数,那么我们又要将原来代码中和这个部分相关的代码逐行移除,十分的麻烦

引入了AOP之后,这项工作就变得简单了

  • 我们可以将权限验证的代码放在某个地方,然后通过某些特定的配置实现在执行系统中以update开头的函数之前,先执行权限验证的代码
  • 如此,万一需求变了,我们也只要改一个地方的代码。那一个个以update开头的函数就是切点,横向地来看,可以把它们抽象成一个切面,所以AOP被称为面向切面编程。

常见的应用场景:日志记录、性能统计、安全认证、事务处理、异常处理等
我们将这些代码从业务逻辑代码中分离出来,通过对这些行为的分离,我们把它们独立到非指导业务逻辑的代码中,进而改变这些代码的时候不会影响到我们的业务逻辑代码
并且业务逻辑代码也感知不到它们的存在,因为业务逻辑代码“被代理了”。

Spring AOP中代理机制的实现主要使用了了JDK动态代理以及CGLIB动态代理

基本的概念

  • 连接点
    目标被增强的函数即程序执行过程中的行为,比如方法调用或特定异常被抛出
  • Advice通知
    定义在连接点做什么,为切面增强提供织入接口,有Before/After/ThrowsAdvice
    在特定的连接点,AOP 框架执行的动作
    Spring 以拦截器作通知模型,维护一个围绕连接点的拦截器链
  • Pointcut切点
    决定Advice应该作用于哪个连接点,也就是说通过Pointcut来定义需要增强的方法的集合
  • Advisor通知器
    将目标方法的切面增强设计(Advice)和关注点的设计(Pointcut)结合起来。通过Advisor,可以定义该使用哪个通知并在哪个关注点使用它

1 Advice

Advice是AOP中的一个基本接口,BeforeAdvice、AfterAdvice、ThrowsAdvice等都继承于它


img_df3a097fa26fa443b77b23d6fb649bed.png
Advice继承关系图

BeforeAdvice的继承关系中,定义类为待增强的目标方法设置的前置增强接口MethodBeforeAdvice
使用这个前置接口需要实现一个回调函数before,作为回调函数,before方法的实现在Advice中被配置到目标方法后,会在调用目标方法时被回调

img_fc6f3d12fcec545b620d98b91be0c87e.png
MethodBeforeAdvice以及回调函数before

before的参数

  • Method:目标方法的反射对象
  • Object[]:包含目标方法的输入参数

同样的,在AfterAdvice继承体系下的AfterReturningAdvice中也有相似的回调函数

img_50fd86cc3c43f16326470b1a392e7f36.png
图1.3 AfterReturningAdvice及其回调函数afterReturn

2 Pointcut切点

从Pointcut的基本接口定义中可以看到,需要返回一个
MethodMatcher
Point的匹配判断,即

  • 判断是否需要对当前方法调用进行增强
  • 或者是否需要对当前调用方法应用配置好的Advice通知
    img_5593208cc130191d4ea1fe0a06cce0b1.png
    Pointcut的基本接口定义

    而在MethodMatcher接口中,有一个matcher方法
    在匹配连接点的过程中起着至关重要的作用.

MethodMatcher对象是可以配置成

  • JdkRegexpMethodPointcut
    有一个MethodMatcher接口定义的matches方法,用正则表达式来对方法名进行匹配判断
  • NameMatchMethodPointcut
    完成方法的匹配判断

PointCutadvisor 有 两 个 常 用 实 现 类

  • NameMatchMethodPointCutadvisor
    需要注入 mappedname 和 advice 属性,mappedname 指明要拦截的方法名
  • regexMethodPointCutadvisor
    需要注入 pattern 和 advice 属性,pattern 按照正则表达式的方法指明了要拦截的方法名,

advice 定义一个增强,即要加入的操作(需要自己实现 MethodBeforeAdvice、MethodafterAdvice、throwAdvice、Methodinterceptor 接口之一),然后在 ProxyBeanFactory 的拦截器中注入这个 PointCutadvisor。注:一个 ProxyFactoryBean 只能指定一个代理目标。

img_e4d754e163b6ed17865c45f19019944a.png
JdkRegexpMethodPointcut中的matches函数

在NameRegexpMethodPointcut中,给出了matches方法的另一个实现,根据方法的全限定名称进行匹配


img_ba791227d6c16042de3a29d0a82d7067.png
NameRegexpMethodPointcut中matches函数的实现

img_d7a576181545fba03e9c8026db7b46db.png
NameMatchMethodPointcut中matches方法的调用关系链

img_fb8fa8de727f9dede68c818eaab9e214.png
JdkRegexpMethodPointcut中matches方法的调用关系链

从图2.4和图2.5中我们可以看到,在JdkDynamicAopProxy的invoke方法中发出了对matches方法的调用.这个invoke方法就是Proxy对象进行代理回调的入口方法.


img_2066c3ee2634f9f02d608b292257303f.png
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
            }
            if (targetClass.isInterface()) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

    /**
     * Determine whether the supplied {@link AdvisedSupport} has only the
     * {@link org.springframework.aop.SpringProxy} interface specified
     * (or no proxy interfaces specified at all).
     */
    private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
        Class<?>[] interfaces = config.getProxiedInterfaces();
        return (interfaces.length == 0 || (interfaces.length == 1 && SpringProxy.class.equals(interfaces[0])));
    }
}
img_71856d7b6c4bc7bc30f740b6d1e41ec4.png
JdkDynamicAopProxy的类图
// Get the interception chain for this method.
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

            // Check whether we have any advice. If we don't, we can fallback on direct
            // reflective invocation of the target, and avoid creating a MethodInvocation.
            if (chain.isEmpty()) {
                // We can skip creating a MethodInvocation: just invoke the target directly
                // Note that the final invoker must be an InvokerInterceptor so we know it does
                // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
            }
            else {
                // We need to create a method invocation...
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // Proceed to the joinpoint through the interceptor chain.
                retVal = invocation.proceed();
            }
img_c0eb5cf18963ff1c57256990cbaa4dd6.png
img_91c35aad86756ba1911441884b28bd0f.png

img_3ea637155b5414e06aad1f95d3b57f23.png
目录
相关文章
|
9天前
|
XML Java 开发者
Spring Boot中的AOP实现
Spring AOP(面向切面编程)允许开发者在不修改原有业务逻辑的情况下增强功能,基于代理模式拦截和增强方法调用。Spring Boot通过集成Spring AOP和AspectJ简化了AOP的使用,只需添加依赖并定义切面类。关键概念包括切面、通知和切点。切面类使用`@Aspect`和`@Component`注解标注,通知定义切面行为,切点定义应用位置。Spring Boot自动检测并创建代理对象,支持JDK动态代理和CGLIB代理。通过源码分析可深入了解其实现细节,优化应用功能。
|
17天前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
69 8
|
2月前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
2月前
|
监控 安全 Java
什么是AOP?如何与Spring Boot一起使用?
什么是AOP?如何与Spring Boot一起使用?
99 5
|
2月前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
92 8
|
2月前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
2月前
|
XML 监控 安全
深入调查研究Spring AOP
【11月更文挑战第15天】
54 5
|
2月前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
60 4
|
3月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
68 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
2月前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
51 1