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

article/2025/10/30 5:46:17

Spring AOP编程官方文档解读目录


文章目录


org.springframework.aop.framework.Advised是啥?看一下下面这个类结构图
无论是基于JDK动态代理还是基于
可以看到无论是ProxyFactoryBean还是ProxyFactory最终都实现了这个接口、这个接口中的方法非常的多,我们随便看一下

public interface Advised extends TargetClassAware {/*** Return whether the Advised configuration is frozen,* in which case no advice changes can be made.*/boolean isFrozen();/*** Are we proxying the full target class instead of specified interfaces?*/boolean isProxyTargetClass();/*** Return the interfaces proxied by the AOP proxy.* <p>Will not include the target class, which may also be proxied.*/Class<?>[] getProxiedInterfaces();...
}

是否非常熟悉?其实在Spring AOP中,无论是基于JDK动态代理的代理对象,还是基于CGLIB的代理对象,他们最终都实现了这个接口。通过这个接口可以很方便的针对代理对象进行编程。

在这里插入图片描述

比如

ProxyFactory factory = new ProxyFactory(new DemoServiceImpl());
factory.addAdvice(new SimpleBeforeAdvice());
DemoService demoService = (DemoService) factory.getProxy();
User user = demoService.findById(9527L);
System.out.println("++++++++++++++++++++++++++++++++++++++++++++");
1.强制类型转换
Advised advised = (Advised) demoService;
advised.addAdvice(new AnotherBeforeAdvice());
advised.addAdvisor(new SimpleAdvisor());
demoService.findById(9527L);

在创建好了代理对象之后再通过Advised添加了AdviceAdvisor.
在这里插入图片描述
通过org.springframework.aop.framework.Advised#getAdvisors接口可以获取到所有的切面,在上面通过addAdvice添加的会自动包装为切点永远返回为true的 Advisor对象。
在这里插入图片描述
源码如下

@Override
public void addAdvice(Advice advice) throws AopConfigException {int pos = this.advisors.size();addAdvice(pos, advice);
}/*** Cannot add introductions this way unless the advice implements IntroductionInfo.*/
@Override
public void addAdvice(int pos, Advice advice) throws AopConfigException {Assert.notNull(advice, "Advice must not be null");if (advice instanceof IntroductionInfo) {// We don't need an IntroductionAdvisor for this kind of introduction:// It's fully self-describing.addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));}else if (advice instanceof DynamicIntroductionAdvice) {// We need an IntroductionAdvisor for this kind of introduction.throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");}else {addAdvisor(pos, new DefaultPointcutAdvisor(advice));}
}@Override
public void addAdvisor(int pos, Advisor advisor) throws AopConfigException {if (advisor instanceof IntroductionAdvisor) {validateIntroductionAdvisor((IntroductionAdvisor) advisor);}addAdvisorInternal(pos, advisor);
}private void addAdvisorInternal(int pos, Advisor advisor) throws AopConfigException {Assert.notNull(advisor, "Advisor must not be null");if (isFrozen()) {throw new AopConfigException("Cannot add advisor: Configuration is frozen.");}if (pos > this.advisors.size()) {throw new IllegalArgumentException("Illegal position " + pos + " in advisor list with size " + this.advisors.size());}this.advisors.add(pos, advisor);updateAdvisorArray();adviceChanged();
}

可以看到其实在内部维护了一个List数据结构的容器advisors

/*** List of Advisors. If an Advice is added, it will be wrapped* in an Advisor before being added to this List.*/
private List<Advisor> advisors = new ArrayList<Advisor>();

在添加完成之后,会执行adviceChanged操作,然后清除内部的一个缓存methodCache.这是一个32个大小的ConcurrentHashMap对象。在构造代理对象的时候进行初始化。

/** Cache with Method as key and advisor chain List as value */
private transient Map<MethodCacheKey, List<Object>> methodCache;public AdvisedSupport() {initMethodCache();
}/*** Initialize the method cache.*/
private void initMethodCache() {this.methodCache = new ConcurrentHashMap<MethodCacheKey, List<Object>>(32);
}

清除了这个缓存怎么会影响到代理对象的呢?
参考如下代码(org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice

/*** Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects* for the given method, based on this configuration.* @param method the proxied method* @param targetClass the target class* @return a List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)*/
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {MethodCacheKey cacheKey = new MethodCacheKey(method);List<Object> cached = this.methodCache.get(cacheKey);if (cached == null) {cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);this.methodCache.put(cacheKey, cached);}return cached;
}

当清空缓存之后,会重新构造增强链。
在前面介绍代理方法执行的时候应该对这个方法不陌生。可以去查看源码org.springframework.aop.framework.JdkDynamicAopProxy#invoke。或者参考上一章关于动态匹配和静态匹配部分的内容。

这里的缓存看来不仅仅是为了性能问题,而且也方便在内部属性修改之后通过清除缓存来达到刷新的目的

By default, it’s possible to add or remove advisors or interceptors even once a proxy has been created. The only restriction is that it’s impossible to add or remove an introduction advisor, as existing proxies from the factory will not show the interface change. (You can obtain a new proxy from the factory to avoid this problem.)

根据创建代理的方式,通常可以设置一个冻结的标志,在这种情况下,Advised isFrozen()方法将返回true,并且通过添加或删除来修改建议的任何尝试都将导致AopConfigException。

Exception in thread "main" org.springframework.aop.framework.AopConfigException: Cannot add advisor: Configuration is frozen.at org.springframework.aop.framework.AdvisedSupport.addAdvisorInternal(AdvisedSupport.java:365)at org.springframework.aop.framework.AdvisedSupport.addAdvisor(AdvisedSupport.java:266)at org.springframework.aop.framework.AdvisedSupport.addAdvice(AdvisedSupport.java:415)at org.springframework.aop.framework.AdvisedSupport.addAdvice(AdvisedSupport.java:396)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:179)at com.sun.proxy.$Proxy0.addAdvice(Unknown Source)at com.example.aop.advice.TestMain.main(TestMain.java:36)

在这里插入图片描述

冻结Adviised对象状态的功能在某些情况下很有用,例如,防止调用代码删除安全拦截器。 如果已知不需要修改运行时建议。

在这里插入图片描述


http://chatgpt.dhexx.cn/article/6O29xgrf.shtml

相关文章

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的卓…

java卸载2503,无法安装msi格式软件提示错误代码2502、2503怎么办?

无法安装msi格式软件提示错误代码2502、2503怎么办?一遇英文界面&#xff0c;就感觉心里没底&#xff0c;偏偏薄名女偏逢薄命郎&#xff0c;安装msi格式软件&#xff0c;出现了下面界面&#xff1a; The installer has encountered an unexpected error installing this packa…

python错误2503_Win10卸载python总是提示error2503失败各种解决办法

最近win10的电脑装了python的3.4,然后想卸载,就总是提示error 2053,类似于这种: 下面是我的坎坷解决之路: 1、网上说,任务管理器 --> 详细信息 --> explorer.exe结束任务,结束资源管理器,然后,文件--运行新任务 -- 如下图所示: 然后重复卸载操作,然后还是失败…