第十九讲-动态通知
第十九讲-动态通知调用
所谓的动态和静态是什么意思呢?看下面的代码:
@Aspect
static class MyAspect{
// 静态通知调用
@Before("execution(* foo(...))")
public void before1(){
System.out.println("before1");
}
// 动态通知调用
@Before("execution(* foo(...)) && args(x)")
public void before2(int x){
System.out.printf("before2(%d)%n",x);
}
}
如上面所示,一个是静态调用,一个是动态调用。区别的办法也很简单,那就是看通知方法调用的时候需不需要提供参数,参数在切点表达式中用args
表示。
package org.springframework.aop.framework.autoproxy;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import java.lang.reflect.Field;
import java.util.List;
public class A19 {
@Aspect
static class MyAspect {
@Before("execution(* foo(..))") // 静态通知调用,不带参数绑定,执行时不需要切点
public void before1() {
System.out.println("before1");
}
@Before("execution(* foo(..)) && args(x)") // 动态通知调用,需要参数绑定,执行时还需要切点对象
public void before2(int x) {
System.out.printf("before2(%d)%n", x);
}
}
static class Target {
public void foo(int x) {
System.out.printf("target foo(%d)%n", x);
}
}
@Configuration
static class MyConfig {
@Bean
AnnotationAwareAspectJAutoProxyCreator proxyCreator() {
return new AnnotationAwareAspectJAutoProxyCreator();
}
@Bean
public MyAspect myAspect() {
return new MyAspect();
}
}
public static void main(String[] args) throws Throwable {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(ConfigurationClassPostProcessor.class);
context.registerBean(MyConfig.class);
context.refresh();
AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
List<Advisor> list = creator.findEligibleAdvisors(Target.class, "target");
Target target = new Target();
ProxyFactory factory = new ProxyFactory();
factory.setTarget(target);
factory.addAdvisors(list);
Object proxy = factory.getProxy(); // 获取代理
List<Object> interceptorList = factory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod("foo", int.class), Target.class);
for (Object o : interceptorList) {
showDetail(o);
}
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>");
ReflectiveMethodInvocation invocation = new ReflectiveMethodInvocation(
proxy, target, Target.class.getMethod("foo", int.class), new Object[]{100}, Target.class, interceptorList
) {};
invocation.proceed();
/*
学到了什么
a. 有参数绑定的通知调用时还需要切点,对参数进行匹配及绑定
b. 复杂程度高, 性能比无参数绑定的通知调用低
*/
}
public static void showDetail(Object o) {
try {
Class<?> clazz = Class.forName("org.springframework.aop.framework.InterceptorAndDynamicMethodMatcher");
if (clazz.isInstance(o)) {
Field methodMatcher = clazz.getDeclaredField("methodMatcher");
methodMatcher.setAccessible(true);
Field methodInterceptor = clazz.getDeclaredField("interceptor");
methodInterceptor.setAccessible(true);
System.out.println("环绕通知和切点:" + o);
System.out.println("\t切点为:" + methodMatcher.get(o));
System.out.println("\t通知为:" + methodInterceptor.get(o));
} else {
System.out.println("普通环绕通知:" + o);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
12:42:53.299 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@470e2030
12:42:53.348 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.ConfigurationClassPostProcessor'
12:42:53.638 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'proxyCreator'
12:42:53.638 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.aop.framework.autoproxy.A19$MyConfig'
12:42:53.640 [main] INFO org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'org.springframework.aop.framework.autoproxy.A19$MyConfig' of type [org.springframework.aop.framework.autoproxy.A19$MyConfig$$EnhancerBySpringCGLIB$$a239ae04] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
12:42:53.677 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myAspect'
12:42:53.766 [main] DEBUG org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void org.springframework.aop.framework.autoproxy.A19$MyAspect.before1()
12:42:53.768 [main] DEBUG org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void org.springframework.aop.framework.autoproxy.A19$MyAspect.before2(int)
普通环绕通知:org.springframework.aop.interceptor.ExposeInvocationInterceptor@6f45df59
普通环绕通知:org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@38e79ae3
环绕通知和切点:org.springframework.aop.framework.InterceptorAndDynamicMethodMatcher@68e5eea7
切点为:AspectJExpressionPointcut: (int x) execution(* foo(..)) && args(x)
通知为:org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@291b4bf5
>>>>>>>>>>>>>>>>>>>>>>>>>>
before1
before2(100)
target foo(100)
分类:
Spring 高级49讲
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构