Spring AOP名词解释Advice,Pointcut,Advisor,Joinpoint,Advised是什么?

article/2025/10/29 18:18:37

Advice

advice解释为通知,需要执行的增强逻辑方法。

advice规范接口如图,分为了before,after等等,为什么没有around呢,因为是通过interceptor实现的。

这里可以看出,AfterAdvice最终会被转换包装成AfterReturningAdviceInterceptor实现类进行适配桥接,同理BeforeAdvice也会被包装成MethodBeforeAdviceInterceptor最终调用MethodIntercepter#invoke()方法进行适配。

限于图片展示范围以上均是还没有到具体API使用实现类,我们继续探究其实现类

PointCut

pointCut解释为切点,即我们需要给哪些方法进行代理增强,也就是切面定义中的切点表达式,根据这个表达式能匹配到具体需要增强的方法,根据该接口的规范我们可以看到其实现类持有了切点表达式pointcoutExpression,匹配的方法shadowMatchCache缓存。

其接口定义的方法规范:

Advisor

advisor解释为通知者,他是Advice和PointCut的结合,组合了通知和切点那么就能很明确的知道那个方法需要增强什么逻辑,在Advisor中Advice和PointCut是一对一的。

可以看到针对不同类型的切点表达式有具体实现,其侧重点不一样,其中DefaultPointcutAdvisor是全匹配,即匹配所有类的所有方法(默认情况,可以改变表达式)。

而接口方法为:

从接口方法很容易看到Advisor就是Advice和Pointcut的组合,从中可以获取Advice和Pointcut。

Advised

advised可以理解为已经织如的,完成的代理组合体,Advised接口定义了很多操作方法,其实现类持有了多个Advisor,可以向Advised对象中添加Advisor,同时可对Advisor进行增删查改(isFrozen=false时)。

在spring中默认情况下ProxyConfig的opaque=false情况下,生成的所有代理对象无论是JDK代理还是CJLIB代理均实现了Advised接口,也就是说在Spring中我们可以将所有的代理对象转为AdvisedAdvised advised = (Advised)proxy

有一段代码如下:

public static void main(String[] args) {DefaultEchoService defaultEchoService = new DefaultEchoService();// 注入目标对象(被代理)ProxyFactory proxyFactory = new ProxyFactory(defaultEchoService);// 添加 Advice 实现 MethodInterceptor < Interceptor < AdviceproxyFactory.addAdvice(new EchoServiceMethodInterceptor());// 获取代理对象EchoService proxy = (EchoService) proxyFactory.getProxy();System.out.println(proxy.echo("Hello,World"));Advised advised = (Advised) proxy;//直接给代理对象添加通知(会被包装为匹配所有方法的Advisor)advised.addAdvice(new MethodBeforeAdvice() {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("before--------------");}});System.out.println(proxy.echo("hello 2"));//代理对象还可以二次代理ProxyFactory pf1 = new ProxyFactory(proxy);Object proxy2 = pf1.getProxy();System.out.println(proxy2.getClass());
}

我们debug看下代理对象信息:

不难看出JdkDynamicAopProxy持有了一个Advised的实现类ProxyFactory,代理对象调用addAdvice()方法为什么可行,就是因为实际调用的是h对象的advised属性的addAdvice()去执行,将Advice添加到了Advised的Advisor集合中(advisors属性),这里就相当于静态代理模式。

在Spring中每个代理对象都有不同的JDKDynamicAopProxy实例(h对象都是new的),h对象中不同的ProxyFactory对象(advised实现)。这也不难理解,因为每个代理对象的增强逻辑不尽相同,那么其advisors集合中的通知者肯定不同,也就意味着ProxyFactory对象必定不同,也即InvocationHandler对象必定不同。

JdkDynamicAopProxy实现了InvocationHandler接口那么其实现的invoke()方法至关重要,后面我们接着分析。

到这里我们似乎已经很好理解Advised的本意了,他就是已经织如完成的通知者集合,包含在代理对象中,代理对象已经可以直接使用,在被增强的方法上会调用通知方法。

JoinPoint

joinpoint就是运行时的连接点,根据接口定义我们知道它包裹了要执行的对象,方法,参数等。spring只支持方法类型的连接点,虽然有构造方法连接点的定义,但是未实现,故不支持构造方法。

我们可以看到这里有两种实现方式,意识基于jdk的动态代理,二是基于cglib实现。

各个接口定义的方法:

joinpoint就是运行时的连接点,根据接口定义我们知道它包裹了要执行的对象,方法,参数等。spring只支持方法类型的连接点,虽然有构造方法连接点的定义,但是未实现,故不支持构造方法。

        我们可以看到这里有两种实现方式,意识基于jdk的动态代理,二是基于cglib实现。 各个接口定义的方法: 在jdk代理模式时,Jointpoint的使用是在InvocationHandler的实现类JdkDynamicAopProxy中的invoke()方法中被创建(new),我们再看invoke方法:

Jointpoint使用

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object oldProxy = null;boolean setProxyContext = false;
​TargetSource targetSource = this.advised.targetSource;Object target = null;
​try {// 省略部分代码...Object retVal;
​// 暴露代理对象,在执行方法中可以通过ThreadLocal获得if (this.advised.exposeProxy) {// Make invocation available if necessary.oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}
​// Get as late as possible to minimize the time we "own" the target,// in case it comes from a pool.target = targetSource.getTarget();Class<?> targetClass = (target != null ? target.getClass() : null);
​
​// 获得通知执行链List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);if (chain.isEmpty()) {Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);} else {//创建连接点实现类,包装了代理对象,目标类,要执行的方法,参数,目标类,拦截器链等等MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);//可以看到MethodInvocation的proceed()至关重要retVal = invocation.proceed();}
​// Massage return value if necessary.Class<?> returnType = method.getReturnType();if (retVal != null && retVal == target &&returnType != Object.class && returnType.isInstance(proxy) &&!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {// Special case: it returned "this" and the return type of the method// is type-compatible. Note that we can't help if the target sets// a reference to itself in another returned object.retVal = proxy;}else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);}return retVal;}finally {if (target != null && !targetSource.isStatic()) {// Must have come from TargetSource.targetSource.releaseTarget(target);}//修改代理对象为上一个,类似于线程池的ThreadLocal设计if (setProxyContext) {// Restore old proxy.AopContext.setCurrentProxy(oldProxy);}}
}

JoinPoint

在JoinPoint中定义了多个方法

public interface Joinpoint {// 继续执行拦截器链@NullableObject proceed() throws Throwable;// 获取当前对象@NullableObject getThis();// @NonnullAccessibleObject getStaticPart();
​
}

MethodInvocation在此基础上增加了method方法的获取,这个方法就是要执行的原始方法,增强逻辑中最后调用。

MethodInvocation

public interface MethodInvocation extends Invocation {@NonnullMethod getMethod();
}

继续扩展了代理信息获取规范接口:

ProxyMethodInvocation

public interface ProxyMethodInvocation extends MethodInvocation {// 返回原始对象的代理对象Object getProxy();
​MethodInvocation invocableClone();MethodInvocation invocableClone(Object... arguments);// 调用方法的参数设置,但是实现类一般通过构造方法设置void setArguments(Object... arguments);
​// 其他属性设置void setUserAttribute(String key, @Nullable Object value);@NullableObject getUserAttribute(String key);
}

实现类ReflectiveMethodInvocation

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {// 代理后的代理对象protected final Object proxy;// 原始对象@Nullableprotected final Object target;// 方法protected final Method method;// 方法参数protected Object[] arguments;// 原始类Class@Nullableprivate final Class<?> targetClass;// 相关属性保存集合@Nullableprivate Map<String, Object> userAttributes;// 查找到的拦截器也就是Advisorsprotected final List<?> interceptorsAndDynamicMethodMatchers;// 运行时执行到哪个拦截器了private int currentInterceptorIndex = -1;// 构造方法protected ReflectiveMethodInvocation(Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
​this.proxy = proxy;this.target = target;this.targetClass = targetClass;this.method = BridgeMethodResolver.findBridgedMethod(method);this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;}
}

ReflectiveMethodInvocation是Jointpoint最核心实现,从代码上看也是非常的简单,它在代理对象执行方法时被创建。


http://chatgpt.dhexx.cn/article/DTGHhwVP.shtml

相关文章

Advised,Advisor,Advice,Pointcut

2019独角兽企业重金招聘Python工程师标准>>> Advised->在Spring中创建了AOP代理之后&#xff0c;就能够使用org.springframework.aop.framework.Advised接口对它们进行管理。 任何AOP代理都能够被转型为这个接口&#xff0c;不论它实现了哪些其它接口 Advisor-&g…

Spring AOP编程官方文档解读之操作Advised对象

Spring AOP编程官方文档解读目录 文章目录 org.springframework.aop.framework.Advised是啥&#xff1f;看一下下面这个类结构图 可以看到无论是ProxyFactoryBean还是ProxyFactory最终都实现了这个接口、这个接口中的方法非常的多&#xff0c;我们随便看一下 public interfac…

arduino知识点梳理(二)——INPUT_PULLUP模式

参考文章1 参考文章2 arduino的引脚模式有三种&#xff1a; INPUT——输入模式OUTPUT——输出模式INPUT_PULLUP——输入上拉模式 Arduino 微控制器自带内部上拉电阻。如果需要使用内部上拉电阻&#xff0c;则应使用pinMode()将引脚设置为输入上拉&#xff08;INPUT_PULLUP&am…

Pull Up Field(字段上移)

两个子类拥有形同的字段 重构&#xff1a;将该字段移至超类

HAL库 output level 和 pull up/ pull down 的区别

从标准库过来的朋友可能对这两个选型有点分不清除 GPIO output level 即输出模式下初始化后端口的电位(高或低) GPIO Pull-up/Pull-down 即输入模式下的电位&#xff0c;例如按键检测

处理概括关系之一 :Pull Up Field(值域上移)

两个subclasses 拥有相同的值域。 将此一值域移至superclass。 动机&#xff08;Motivation&#xff09; 如果各个subclass 是分别开发的&#xff0c;或者是在重构过程中组合起来的&#xff0c;你常会发现它们拥有重复特性&#xff0c;特别是值域更容易重复。这样的值域有时拥有…

Push pull, open drain circuit, pull up, pull down resistor

Push pull 就以下面這個 電路來說&#xff0c; 因為沒有 pull up resistor&#xff0c; 所以 output voltage 由 low 往 high 的速度會較快。有兩個電晶體&#xff0c;一個on&#xff0c;一個 off&#xff0c; 可以 current sourcing&#xff0c;也可以 current sinking&#x…

上拉(Pull Up )或下拉(Pull Down)电阻详解

上拉&#xff08;Pull Up &#xff09;或下拉&#xff08;Pull Down&#xff09;电阻&#xff08;两者统称为“拉电阻”&#xff09;最基本的作用是&#xff1a;将状态不确定的信号线通过一个电阻将其箝位至高电平&#xff08;上拉&#xff09;或低电平&#xff08;下拉&#x…

BetterScroll 2.x 的 pulldown 使用、pullup使用

官方文档&#xff1a;https://better-scroll.github.io/docs/zh-CN/plugins/ BetterScrol滚动原理 有唯一的子节点子节点必须超出包裹的高度new BScroll&#xff08;‘容器名’&#xff09; html内容必须已经渲染完成 绿色部分为 wrapper&#xff0c;也就是父容器&#xff…

【超详细】output level 和 pull up/ pull down 的真正区别

目录 【超详细】output level 和 pull up/ pull down 的真正区别1. Output Level2. Pull up/ Pull down3. 两者的区别1&#xff09;对于Output口来说2&#xff09;而对于Input口来说 总结参考资料 【超详细】output level 和 pull up/ pull down 的真正区别 今天在使用stm32f1…

OUTPUT,INPUT,INPUT_PULLUP三种模式的区别

一&#xff0c;首先三种模式都需要由pinMode()函数来设置。 &#xff08;1&#xff09;设置引脚 为输出&#xff08;OUTPUT&#xff09;模式&#xff0c;此时引脚为低阻抗状态&#xff0c;可以向其他电路原件提供电流&#xff08;通常为40mA以内&#xff09; &#xff08;2&a…

Pull Up Method(函数上移)

动机 避免行为重复是很重要的。尽管重复的两个函数也可以各自工作得很好&#xff0c;但重复自身只会成为错误的滋生地&#xff0c;此外别无价值。无论何时&#xff0c;只要系统之内出现重复&#xff0c;你就会面临“修改其中一个却未能修改另一个”的风险。通常&#xff0c;找…

GPIO_PULLUP,PULLDOWN, NOPULL

NOPULL: 对于输出IO&#xff0c;配置为NOPULL&#xff0c;当IO输出高电平时&#xff0c;IO为1&#xff0c; 当IO输出低电平时&#xff0c;IO为0&#xff1b; PULLUP&#xff1a; 对于输入IO, 默认为高电平&#xff0c;当需要改变为低电平时配置为PULLUP。 比如&#xff1a;K…

pullup和pulldown在verilog中的使用方法

0 前言 这段时间涉及到了IO-PAD&#xff0c;在IO-PAD的RTL的时候注意到了pullup和pulldown&#xff0c;对这个知识比较好奇&#xff0c;就研究了一下&#xff0c;顺便记录下来&#xff0c;IO-PAD的内容等我再研究研究再考虑记录吧 >_< 1 pullup和pulldown的介绍 pullu…

电阻(4)之上拉电阻与下拉电阻详解

原文地址点击这里: 上拉(Pull Up )或下拉(Pull Down)电阻(两者统称为“拉电阻”)最基本的作用是:将状态不确定的信号线通过一个电阻将其箝位至高电平(上拉)或低电平(下拉),无论它的具体用法如何,这个基本的作用都是相同的,只是在不同应用场合中会对电阻的阻值…

解决安装文件时2502、2503错误

在安装文件时有时会出现2502、2503错误&#xff0c;重复安装也不会有什么改变&#xff0c;让人很是头疼。这种问题一般是权限的问题导致的&#xff0c;一般有两种解决办法&#xff0c;第一种就是提升当前用户的权限&#xff0c;第二种就是直接使用CMD安装&#xff0c;这里主要说…

java卸载错误2503_修复控制面板卸载程序时提示错误代码2502、2503的方法

在平常生活中大家是如何卸载软件的呢&#xff1f;有的用户会使用第三方工具&#xff0c;例如软件管家等来进行卸载&#xff0c;这样操作的用户占大多数&#xff0c;但是无法将软件卸载干净。有的用户会直接将安装目录全部删掉&#xff0c;这样操作的用户较少。最理想的卸载软件…

联发科MT2503D处理器详细参数介绍

MT2503D集成了一个ARM7EJ-STM内核&#xff0c;它是运行高级gsm协议软件的主处理器&#xff0c;以及多媒体应用程序、单数字信号处理器核&#xff0c;它管理低层 层次调制解调器和先进的音频功能&#xff0c;嵌入式处理器运行蓝牙基带和链路控制协议和蓝牙无线电控制。 MT 2503…

java内部错误2503_win10安装和卸载Java jdk错误出现2503,2502错误

本人android studio3.0运行helloworld都报错,打开不了守护进程,然后看网上说java版本可能不对,想卸载java,发现任务管理器怎么都卸载不了,网上说的两个办法都试了没用,一天的挣扎,终于找到下面网址的解决办法。 在使用java安装程序时,有时候会出现安装和卸载失败的问题…

MT2503D完整规格书,MT2503D daatsheet资料下载

MT2503D SOC Processor Datasheet MT2503D是一种基于低功耗CMOS工艺的集成前沿电源管理单元、模拟基带和无线电电路的单片芯片。 MT2503D是一个功能丰富和功能非常强大的单芯片解决方案&#xff0c;用于高端GSM/GPRS能力。基于32位ARM7EJ-STMRISC处理器&#xff0c;MT2503D的卓…