当前位置: 首页 > news >正文

[spring6: IntroductionAdvisor IntroductionInterceptor]-源码分析

推荐阅读:[spring6: PointcutAdvisor & MethodInterceptor]-简单介绍

源码

IntroductionAdvisor

public interface IntroductionAdvisor extends Advisor, IntroductionInfo {ClassFilter getClassFilter();void validateInterfaces() throws IllegalArgumentException;}

DefaultIntroductionAdvisor

DefaultIntroductionAdvisor 是 Spring AOP 中的一个 IntroductionAdvisor 实现,它不仅将给定的通知(Advice)与接口引入机制结合,还支持通过 Ordered 接口定义执行顺序。

@SuppressWarnings("serial")
public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFilter, Ordered, Serializable {private final Advice advice;private final Set<Class<?>> interfaces = new LinkedHashSet<>();private int order = Ordered.LOWEST_PRECEDENCE;public DefaultIntroductionAdvisor(Advice advice) {this(advice, (advice instanceof IntroductionInfo introductionInfo ? introductionInfo : null));}public DefaultIntroductionAdvisor(Advice advice, @Nullable IntroductionInfo introductionInfo) {Assert.notNull(advice, "Advice must not be null");this.advice = advice;if (introductionInfo != null) {Class<?>[] introducedInterfaces = introductionInfo.getInterfaces();if (introducedInterfaces.length == 0) {throw new IllegalArgumentException("IntroductionInfo defines no interfaces to introduce: " + introductionInfo);}for (Class<?> ifc : introducedInterfaces) {addInterface(ifc);}}}public DefaultIntroductionAdvisor(DynamicIntroductionAdvice advice, Class<?> ifc) {Assert.notNull(advice, "Advice must not be null");this.advice = advice;addInterface(ifc);}public void addInterface(Class<?> ifc) {Assert.notNull(ifc, "Interface must not be null");if (!ifc.isInterface()) {throw new IllegalArgumentException("Specified class [" + ifc.getName() + "] must be an interface");}this.interfaces.add(ifc);}@Overridepublic Class<?>[] getInterfaces() {return ClassUtils.toClassArray(this.interfaces);}@Overridepublic void validateInterfaces() throws IllegalArgumentException {for (Class<?> ifc : this.interfaces) {if (this.advice instanceof DynamicIntroductionAdvice dynamicIntroductionAdvice &&!dynamicIntroductionAdvice.implementsInterface(ifc)) {throw new IllegalArgumentException("DynamicIntroductionAdvice [" + this.advice + "] " +"does not implement interface [" + ifc.getName() + "] specified for introduction");}}}@Overridepublic ClassFilter getClassFilter() {return this;}@Overridepublic boolean matches(Class<?> clazz) {return true;}// ...
}

DeclareParentsAdvisor

DeclareParentsAdvisor 是 Spring AOP 中用于“引介”(Introduction)的一个特殊 Advisor,它允许在不修改目标类的情况下,声明性地为其代理对象引入一个新的接口,并由独立的委托对象提供该接口的实现。

// @DeclareParents
public class DeclareParentsAdvisor implements IntroductionAdvisor {private final Advice advice;private final Class<?> introducedInterface;private final ClassFilter typePatternClassFilter;public DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, Class<?> defaultImpl) {this(interfaceType, typePattern, new DelegatePerTargetObjectIntroductionInterceptor(defaultImpl, interfaceType));}public DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, Object delegateRef) {this(interfaceType, typePattern, new DelegatingIntroductionInterceptor(delegateRef));}private DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, IntroductionInterceptor interceptor) {this.advice = interceptor;this.introducedInterface = interfaceType;// Excludes methods implemented.ClassFilter typePatternFilter = new TypePatternClassFilter(typePattern);ClassFilter exclusion = (clazz -> !this.introducedInterface.isAssignableFrom(clazz));this.typePatternClassFilter = ClassFilters.intersection(typePatternFilter, exclusion);}@Overridepublic ClassFilter getClassFilter() {return this.typePatternClassFilter;}@Overridepublic void validateInterfaces() throws IllegalArgumentException {// Do nothing}@Overridepublic Advice getAdvice() {return this.advice;}@Overridepublic Class<?>[] getInterfaces() {return new Class<?>[] {this.introducedInterface};}}

IntroductionInterceptor

public interface IntroductionInterceptor extends MethodInterceptor, DynamicIntroductionAdvice {}

DelegatingIntroductionInterceptor

DelegatingIntroductionInterceptor 是 Spring AOP 中一个方便的基类,用于实现引介(Introduction),它通过将引入接口的方法调用** “委托” **给一个独立的(或它自身作为)实现对象来处理,从而简化了引介拦截器的编写。

@SuppressWarnings("serial")
public class DelegatingIntroductionInterceptor extends IntroductionInfoSupport implements IntroductionInterceptor {@Nullableprivate Object delegate;public DelegatingIntroductionInterceptor(Object delegate) {init(delegate);}protected DelegatingIntroductionInterceptor() {init(this);}private void init(Object delegate) {Assert.notNull(delegate, "Delegate must not be null");this.delegate = delegate;implementInterfacesOnObject(delegate);// We don't want to expose the control interfacesuppressInterface(IntroductionInterceptor.class);suppressInterface(DynamicIntroductionAdvice.class);}@Override@Nullablepublic Object invoke(MethodInvocation mi) throws Throwable {if (isMethodOnIntroducedInterface(mi)) {Object retVal = AopUtils.invokeJoinpointUsingReflection(this.delegate, mi.getMethod(), mi.getArguments());if (retVal == this.delegate && mi instanceof ProxyMethodInvocation pmi) {Object proxy = pmi.getProxy();if (mi.getMethod().getReturnType().isInstance(proxy)) {retVal = proxy;}}return retVal;}return doProceed(mi);}@Nullableprotected Object doProceed(MethodInvocation mi) throws Throwable {// If we get here, just pass the invocation on.return mi.proceed();}}

DelegatePerTargetObjectIntroductionInterceptor

DelegatePerTargetObjectIntroductionInterceptor 是一个引介拦截器,它为每个被代理的目标对象维护一个独立的委托实例(即拥有独立状态),从而确保引介的接口行为是针对每个目标对象特有的,而不是共享状态

@SuppressWarnings("serial")
public class DelegatePerTargetObjectIntroductionInterceptor extends IntroductionInfoSupportimplements IntroductionInterceptor {private final Map<Object, Object> delegateMap = new WeakHashMap<>();private final Class<?> defaultImplType;private final Class<?> interfaceType;public DelegatePerTargetObjectIntroductionInterceptor(Class<?> defaultImplType, Class<?> interfaceType) {this.defaultImplType = defaultImplType;this.interfaceType = interfaceType;Object delegate = createNewDelegate();implementInterfacesOnObject(delegate);suppressInterface(IntroductionInterceptor.class);suppressInterface(DynamicIntroductionAdvice.class);}@Override@Nullablepublic Object invoke(MethodInvocation mi) throws Throwable {if (isMethodOnIntroducedInterface(mi)) {Object delegate = getIntroductionDelegateFor(mi.getThis());Object retVal = AopUtils.invokeJoinpointUsingReflection(delegate, mi.getMethod(), mi.getArguments());if (retVal == delegate && mi instanceof ProxyMethodInvocation pmi) {retVal = pmi.getProxy();}return retVal;}return doProceed(mi);}@Nullableprotected Object doProceed(MethodInvocation mi) throws Throwable {// If we get here, just pass the invocation on.return mi.proceed();}private Object getIntroductionDelegateFor(@Nullable Object targetObject) {synchronized (this.delegateMap) {if (this.delegateMap.containsKey(targetObject)) {return this.delegateMap.get(targetObject);}else {Object delegate = createNewDelegate();this.delegateMap.put(targetObject, delegate);return delegate;}}}private Object createNewDelegate() {try {return ReflectionUtils.accessibleConstructor(this.defaultImplType).newInstance();}catch (Throwable ex) {throw new IllegalArgumentException("Cannot create default implementation for '" +this.interfaceType.getName() + "' mixin (" + this.defaultImplType.getName() + "): " + ex);}}}

实战

public interface Versioned {String getVersion();void setVersion(String version);}
public class ProductService {public void getProduct(String productId) {System.out.println("获取产品信息: " + productId);}public void updateProduct(String productId, int quantity) {System.out.println("更新产品信息: " + productId + ", 数量: " + quantity);}
}
public class VersionIntroductionInterceptor implements IntroductionInterceptor {private String serviceVersion = "1.0.0"; // 默认版本号@Overridepublic boolean implementsInterface(Class<?> intf) {return intf.isAssignableFrom(Versioned.class);}@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {if (implementsInterface(invocation.getMethod().getDeclaringClass())) {if (invocation.getMethod().getName().equals("getVersion")) {return serviceVersion;} else if (invocation.getMethod().getName().equals("setVersion")) {this.serviceVersion = (String) invocation.getArguments()[0];return null;}}return invocation.proceed();}public String getVersion() {throw new UnsupportedOperationException("This method is handled by the interceptor.");}public void setVersion(String version) {throw new UnsupportedOperationException("This method is handled by the interceptor.");}
}
public class Application {public static void main(String[] args) {ProductService targetService = new ProductService();DefaultIntroductionAdvisor introductionAdvisor = new DefaultIntroductionAdvisor(new VersionIntroductionInterceptor());ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(targetService);proxyFactory.addInterface(Versioned.class); proxyFactory.setProxyTargetClass(true); //CGLIBproxyFactory.addAdvisor(introductionAdvisor); // 介入增强ProductService productServiceProxy = (ProductService) proxyFactory.getProxy();Versioned versionedProxy = (Versioned) proxyFactory.getProxy();// 获取产品信息: BOOK001// 当前产品版本: 1.0.0productServiceProxy.getProduct("BOOK001");System.out.println("当前产品版本: " + versionedProxy.getVersion());// 更新产品信息: BOOK001, 数量: 10// 当前产品版本: 2.0.0productServiceProxy.updateProduct("BOOK001", 10);versionedProxy.setVersion("2.0.0");System.out.println("当前产品版本: " + versionedProxy.getVersion());}
}
http://www.dtcms.com/a/288180.html

相关文章:

  • C++编程学习(第11天)
  • Patch-wise Structural:一种引入局部统计特性的时序预测损失函数
  • eNSP综合实验(DNCP、NAT、TELET、HTTP、DNS)
  • 定时器中BDTR死区时间和刹车功能配置
  • debian的pulseaudio删掉也没事
  • Go语言pprof性能分析指南
  • SIMATIC WinCC Unified 使用 KPI 优化流程
  • 永磁同步电机无速度算法--脉振正弦注入法
  • Kakfa集群部署及主题创建
  • haproxy七层代理
  • day7--绑定媒资、课程发布
  • kafka--基础知识点--6--AR、ISR、OSR
  • Mysql系列--3、数据类型
  • RTDETR融合DECS-Net中的FFM模块
  • Verilog *2* SPI-立创逻辑派G1测试-1
  • 多表查询-8-练习总结
  • 【LeetCode 热题 100】437. 路径总和 III——(解法一)递归递归!
  • 【Linux】mmap的介绍和使用
  • [硬件电路-36]:模拟电路的基本组成要素以及模拟信号处理
  • Python条件控制艺术:侦探破解犯罪谜题逻辑
  • 浏览器渲染原理——计算属性和布局过程常考内容
  • 如何实现一个定时任务
  • LibreTv在线观影项目部署开箱即用
  • 如何解决Flink CDC同步时间类型字段8小时时间差的问题,以MySQL为例
  • 相似度度量方法
  • 车载刷写框架 --- 关于私有节点刷写失败未报引起的反思
  • 暑期算法训练.4
  • 用虚拟机体验纯血鸿蒙所有机型!
  • 【成品设计】基于STM32的水资源监控系列项目
  • 几个好用的MCP分享