活动介绍

SpringAOP框架高级特性的使用

立即解锁
发布时间: 2025-08-19 02:32:41 阅读量: 2 订阅数: 11
PDF

Spring框架下的Java开发实践与进阶

### Spring AOP框架高级特性的使用 #### 1. 目标源(TargetSources) 通常,拦截器链通过反射调用目标对象上的适当方法来结束。一般在创建代理时就已知目标对象,使用Spring AOP的目的通常是在目标对象周围添加声明式行为。 不过,Spring终止拦截器链的方式更为复杂。Spring在调用适当方法之前才获取目标对象引用,该目标对象从`TargetSource`接口的实现中获取,该接口定义如下: ```java public interface TargetSource { Class getTargetClass(); boolean isStatic(); Object getTarget() throws Exception; void releaseTarget(Object target) throws Exception; } ``` 在最简单、最常见的情况下,当预先知道目标对象时,Spring会创建`TargetSource`接口的实现,开发者无需关注。这个实现(`SingletonTargetSource`)在调用`getTarget()`方法时,在所有情况下都会返回相同的实例。 然而,`TargetSource`接口也支持更复杂的行为,例如从池或工厂获取目标实例。Spring自带了一些`TargetSource`实现,开发者也可以轻松实现自己的`TargetSource`。 #### 2. 可热交换目标源(HotSwappableTargetSource) 除了用于“单例”目标的默认实现外,最重要的`TargetSource`实现是`HotSwappableTargetSource`。它使我们能够以线程安全的方式在代理下切换目标对象,这在依赖注入框架中尤为重要。 默认情况下,热交换功能未启用,Spring会使用普通的POJO来满足依赖,这样能提供最佳性能,适用于大多数情况。要启用热交换,需要进行显式配置。 `HotSwappableTargetSource`类提供了一个新方法: ```java Object swap(Object o); ``` 该方法返回旧的目标对象。 以下是`HotSwappableTargetSource`的典型使用示例: ```xml <bean id="target1" class="com.mycompany.MyInterfaceImpl"> </bean> <bean id="target2" class="com.mycompany.MyInterfaceImpl"> </bean> <bean id="swapper" class="org.springframework.aop.target.HotSwappableTargetSource"> <constructor-arg><ref local="target1"/></constructor-arg> </bean> <bean id="swappable" class="org.springframework.aop.framework.ProxyFactoryBean" > <property name="targetSource"><ref local="swapper"/></property> </bean> ``` 编程式交换的代码如下: ```java MyInterface target1 = (MyInterface) beanFactory.getBean("target1"); MyInterface target2 = (MyInterface) beanFactory.getBean("target2"); MyInterface proxied = (MyInterface) beanFactory.getBean("swappable"); // 现在对proxied的调用会命中target1 HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper"); Object old = swapper.swap(target2); // old将是target1 // 现在对proxied的调用会命中target2 ``` 在这个例子中,两个目标都来自bean定义。很可能初始目标来自bean定义,而新目标可能来自其他源。 `HotSwappableTargetSource`非常适合构建基础设施,例如支持某些频繁更改的应用程序对象的动态重新配置。 #### 3. 池化目标源(Pooling Target Source) `TargetSource`接口的另一个重要用途是支持池化。在这种情况下,需要的不是单个目标,而是目标池,拦截器链末尾的实际调用将指向空闲的目标。 拦截器实例通常是共享的,因为拦截器通常是线程安全的,如事务拦截器。代理本身是单例实例,位于目标对象池的前面。 ##### 3.1 开箱即用的使用 Spring开箱即用地支持Apache Commons Pool(http://jakarta.apache.org/commons/pool/),这是一个开源的池实现,性能可接受,在负载下很健壮。 可以按以下方式为任何POJO配置池: ```xml <bean id="prototypeTest" class="org.springframework.aop.interceptor.SideEffectBean" singleton="false"> <property name="count"><value>10</value></property> </bean> <bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource"> <property name="targetBeanName"><value>prototypeTest</value></property> <property name="maxSize"><value>25</value></property> </bean> <bean id="pooled" class="org.springframework.aop.framework.ProxyFactoryBean" > <property name="targetSource"><ref local="poolTargetSource"/></property> <property name="interceptorNames"><value>whatever...</value></property> </bean> ``` 需要注意的是,虽然`pooled`是单例bean定义,但目标`prototypeTest`必须是非单例定义,以便Spring配置的池可以根据需要实例化独立的实例。 可以池化的实际类没有限制,虽然池化模型与无状态会话EJB的模型类似,但它适用于任何POJO。 ##### 3.2 使用自定义池化实现 和Spring的其他功能一样,池化`TargetSource`支持自定义。可以扩展`org.springframework.aop.target.AbstractPoolingTargetSource`来使用除Commons Pool之外的池提供程序,需要实现以下方法: ```java protected final void createPool(BeanFactory beanFactory); public Object getTarget() throws Exception; public void releaseTarget(Object target) throws Exception; public void destroy(); ``` 任何池API通常都需要一个回调来为池构造新对象,可以使用继承的`newPrototypeInstance()`方法来实现,如Commons Pool实现中的以下示例: ```java public Object makeObject() { return newPrototypeInstance(); } ``` 基本的池配置参数(如`maxSize`)继承自`org.springframework.aop.target.AbstractPoolingTargetSource`,应该为任何特定于池的配置添加属性。 ##### 3.3 何时使用池化 Spring基于AOP的池化功能通常用作本地无状态会话EJB的替代方案,它提供了相同的基本模型:一个无状态服务对象池,任何对象都可以由给定的方法调用调用。 然而,无状态服务对象通常很容易实现线程安全,通常不需要读写实例变量,或者至少在配置完成后不需要读写实例变量。而且通常拥有对象的单个实例比池更方便,例如在需要维护对象缓存的情况下。 不要过于急切地使用池化,它通常是不必要的。考虑到现代JVM的高效垃圾回收,在J2EE架构中,池化是一个被高估的概念。 ##### 3.4 暴露池统计信息 如果想暴露池化对象的池统计信息,可以按以下方式操作: ```xml <bean id="poolConfigAdvisor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="targetObject"><ref local="poolTargetSource" /></property> <property name="targetMethod"><value>getPoolingConfigMixin</value></property> </bean> <bean id="pooled" class="org.springframework.aop.framework.ProxyFactoryBean" > <property name="targetSource"><ref local="poolTargetSource"/></property> <property name="interceptorNames"><value>poolConfigAdvisor</value></property> <!-- 由于有一个混合器,并且想避免丢失类,因为没有目标 --> <property name="proxyTargetClass"><value>true</value></property> </bean> ``` 这使用了引入(在后面讨论)来使池前面的AOP代理实现`PoolingConfig`接口。 现在可以将从池中获取的任何对象强制转换为`PoolingConfig`并查询其统计信息,假设池化对象是池前面的AOP代理的引用: ```java PoolingConfig conf = (PoolingConfig) pooled; assertEquals(1, conf.getInvocations()); assertEquals("Correct target source", 25, conf.getMaxSize()); ``` 这是引入潜力的一个有趣示例。 #### 4. 自定义目标源(Custom TargetSources) 开发者也可以自由实现自己的`TargetSource`。例如,有用户需要使用多个数据源,并根据上下文在运行时选择一个。 传统的面向对象方法是实现一个`DataSource`装饰器,根据状态委托给一个或另一个`DataSource`。由于`DataSource`接口上的方法数量不多,这不会太麻烦,但代码会很冗长,并且是一个很好的横切关注点示例。 可以通过实现一个`TargetSource`来满足这个需求,该`TargetSource`根据上下文(其他应用程序对象的状态、当前用户或任何其他上下文信息)选择正确的`DataSource`。无论`TargetSource`在运行时选择哪个目标,任何拦截器链都将被共享。 也可以使用核心Spring IoC容器的方法注入功能来解决这个问题,这种方法的优点是对象本身可以调用`getDataSource()`方法,在这种情况下需要实现一个自定义的`MethodReplacer`。 #### 5. 以编程方式访问目标源(Programmatic Access to the TargetSource) 可以通过将任何AOP代理强制转换为`Advised`并使用`TargetSource`属性来获取甚至修改`TargetSource`。这对于允许以编程方式进行配置更改的`TargetSource`实现(如`HotSwappableTargetSource`)最为有用。 在大多数情况下,不会显式设置`TargetSource`,`TargetSource`将是`SingletonTargetSource`类型。需要注意的是,即使在没有目标对象的特殊情况下,`TargetSource`也永远不会为`null`。 #### 6. 无目标对象的情况(Doing Without a Target Object) 偶尔会没有目标对象,在这种情况下,拦截器将负责返回结果。`TargetSource`将是`org.springframework.aop.target.EmptyTargetSource`的规范实例,其`getTarget()`方法始终返回`null`。 当所有行为都由拦截器提供时(可能包括通常自身持有目标的引入拦截器),可以不使用目标对象。最常见的情况是,终端拦截器使用除反射调用目标对象之外的策略来跳出拦截器栈。 例如,Spring EJB代理(如`org.springframework.ejb.access.LocalSlsbInvokerInterceptor`)就采用了这种方法:它们不调用`proceed()`(这会导致AOP基础设施反射调用从`TargetSource`获取的目标),而是在本地或远程EJB上调用`MethodInvocation`中指定的方法,远程技术也使用相同的技术。 需要记住,设计用于跳出拦截器链而不是调用`proceed`的拦截器通常应该是拦截器链中的最后一个。 也有可能(但更不常见)让拦截器本身实现方法,链中的任何拦截器都可以选择返回一个值(或抛出异常)而不是调用`proceed()`方法。需要注意的是,使用CGLIB代理时不能没有目标对象。 #### 7. 提前终止拦截器链(Terminating the Interceptor Chain Early) 当没有目标对象或出于其他原因时,可能希望链中的通知提前终止。这可以通过两种方式发生:抛出异常或返回一个值而不是调用`proceed`。 任何通知都可以抛出异常,该异常将报告给客户端。只有方法拦截器可以返回而不是调用`proceed()`,其他通知类型(如`MethodBeforeAdvice`)没有能力改变返回值。 如果`MethodInterceptor`或其他通知抛出异常,情况如下: - 如果不是受检异常,客户端将看到该异常。 - 如果是方法签名上的受检异常,客户端将看到该异常。 - 如果是方法签名上没有的受检异常,它将被包装在`java.lang.reflect.UndeclaredThrowableException`中并报告给客户端。 #### 8. 使用引入(Using Introduction) 引入意味着使被通知的对象(在这种情况下是Spring AOP代理)实现目标对象未实现的额外接口,甚至可以创建一个仅由引入组成、没有目标对象的代理。 引入有很多用途: - 创建混合器,添加对象中保存的状态,这可能是最重要的用途。 - 暴露与特殊`TargetSource`关联的额外状态,例如在Spring的脚本支持中使用。 - 以不同的方式暴露对象或对象图,例如使对象图实现XML DOM接口。 在AspectJ术语中,引入被称为“类型内声明”。 Spring提供了两种进行引入的方式: - `IntroductionInfo`接口:任何通知都可以实现该接口,以表明它引入了一个或多个接口。这样的通知可以与任何切入点一起使用,甚至可以没有切入点。 - `IntroductionAdvisor`接口:一种特殊的引入顾问类型,不包括`MethodMatcher`,因为它与引入无关,实际上它扩展了`IntroductionInfo`接口。 第一种方法更简单,自Spring 1.1.1引入以来就被推荐使用(在早期版本的Spring中,进行引入总是需要一个`IntroductionAdvisor`)。 以下是一个实际示例,假设要使任何对象“可锁定”,使其实现`Lockable`接口以暴露和控制锁定状态,并在其状态被锁定时禁用所有设置器方法。 `Lockable`接口可能如下所示: ```java public interface Lockable { void lock(); void unlock(); boolean locked(); } ``` 现在需要一个进行引入的通知,它必须实现`IntroductionInfo`接口,该接口包含以下方法: ```java Class[] getInterfaces() ``` 该方法用于返回顾问或通知引入的接口。 通常,在实现引入通知时会扩展Spring方便的`DelegatingIntroductionInterceptor`类,该类会自动检测子类实现的任何接口,并在`IntroductionInfo.getInterfaces()`方法中返回该接口。 因此,简单的引入可以如下所示: ```java public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable { private boolean locked ```
corwn 最低0.47元/天 解锁专栏
赠100次下载
继续阅读 点击查看下一篇
profit 400次 会员资源下载次数
profit 300万+ 优质博客文章
profit 1000万+ 优质下载资源
profit 1000万+ 优质文库回答
复制全文

相关推荐

李_涛

知名公司架构师
拥有多年在大型科技公司的工作经验,曾在多个大厂担任技术主管和架构师一职。擅长设计和开发高效稳定的后端系统,熟练掌握多种后端开发语言和框架,包括Java、Python、Spring、Django等。精通关系型数据库和NoSQL数据库的设计和优化,能够有效地处理海量数据和复杂查询。
最低0.47元/天 解锁专栏
赠100次下载
百万级 高质量VIP文章无限畅学
千万级 优质资源任意下载
千万级 优质文库回答免费看
立即解锁

专栏目录

最新推荐

零信任架构的IoT应用:端到端安全认证技术详解

![零信任架构的IoT应用:端到端安全认证技术详解](https://img-blog.csdnimg.cn/20210321210025683.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyMzI4MjI4,size_16,color_FFFFFF,t_70) # 摘要 随着物联网(IoT)设备的广泛应用,其安全问题逐渐成为研究的焦点。本文旨在探讨零信任架构下的IoT安全认证问题,首先概述零信任架构的基本概念及其对Io

虚拟助理引领智能服务:酒店行业的未来篇章

![虚拟助理引领智能服务:酒店行业的未来篇章](https://images.squarespace-cdn.com/content/v1/5936700d59cc68f898564990/1497444125228-M6OT9CELKKA9TKV7SU1H/image-asset.png) # 摘要 随着人工智能技术的发展,智能服务在酒店行业迅速崛起,其中虚拟助理技术在改善客户体验、优化运营效率等方面起到了关键作用。本文系统地阐述了虚拟助理的定义、功能、工作原理及其对酒店行业的影响。通过分析实践案例,探讨了虚拟助理在酒店行业的应用,包括智能客服、客房服务智能化和后勤管理自动化等方面。同时,

【仿真模型数字化转换】:从模拟到数字的精准与效率提升

![【仿真模型数字化转换】:从模拟到数字的精准与效率提升](https://img-blog.csdnimg.cn/42826d38e43b44bc906b69e92fa19d1b.png) # 摘要 本文全面介绍了仿真模型数字化转换的关键概念、理论基础、技术框架及其在实践中的应用流程。通过对数字化转换过程中的基本理论、关键技术、工具和平台的深入探讨,文章进一步阐述了在工程和科学研究领域中仿真模型的应用案例。此外,文中还提出了数字化转换过程中的性能优化策略,包括性能评估方法和优化策略与方法,并讨论了数字化转换面临的挑战、未来发展趋势和对行业的长远意义。本文旨在为专业人士提供一份关于仿真模型数

地震波正演的逆问题:从正演到反演的深入研究与应用

![地震波正演的逆问题:从正演到反演的深入研究与应用](https://img-blog.csdnimg.cn/baf501c9d2d14136a29534d2648d6553.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Zyo6Lev5LiK77yM5q2j5Ye65Y-R,size_20,color_FFFFFF,t_70,g_se,x_16) # 摘要 本文系统地论述了地震波正演与反演技术的理论基础、实现方法以及实际应用。首先概述了地震波正演的逆问题,然后详细介绍了地震波传播

【心电信号情绪识别在虚拟现实中的应用研究】:探索虚拟世界中的情绪分析

![【心电信号情绪识别在虚拟现实中的应用研究】:探索虚拟世界中的情绪分析](https://www.radsport-rennrad.de/wp-content/uploads/2018/10/leistungstest-radsport.jpg) # 摘要 情绪识别技术与虚拟现实的结合为沉浸式体验带来了新的可能性。本文首先概述了情绪识别与虚拟现实的基本概念,接着深入探讨了心电信号(ECG)的理论基础,包括其产生原理、采集方法和数据处理技术。文中详细分析了心电信号情绪识别算法,并研究了机器学习和深度学习在情绪识别中的应用。此外,本文还探讨了心电信号情绪识别技术在虚拟现实中的实际应用,并通过具

手机Modem协议在网络环境下的表现:分析与优化之道

![手机Modem协议开发快速上手.docx](https://img-blog.csdnimg.cn/0b64ecd8ef6b4f50a190aadb6e17f838.JPG?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBATlVBQeiInOWTpQ==,size_20,color_FFFFFF,t_70,g_se,x_16) # 摘要 Modem协议在网络通信中扮演着至关重要的角色,它不仅定义了数据传输的基础结构,还涉及到信号调制、通信流程及错误检测与纠正机制。本文首先介

【飞机缺陷检测模型压缩加速】:减小模型尺寸,加速推理过程

![【飞机缺陷检测模型压缩加速】:减小模型尺寸,加速推理过程](https://static.mianbaoban-assets.eet-china.com/xinyu-images/MBXY-CR-c3b4ad4ba4139993bf9baedd09c1c762.png) # 摘要 随着深度学习在飞机缺陷检测领域应用的增多,模型压缩和加速技术成为提升检测效率的关键。本文首先介绍了深度学习模型压缩的理论基础,包括其重要性和技术分类,随后探讨了模型加速技术实践,如深度学习框架的选择和模型剪枝、量化实践。通过应用案例分析,展示了模型压缩加速技术在实际飞机缺陷检测中的应用及其带来的性能改善。最后,

【多源数据整合王】:DayDreamInGIS_Geometry在不同GIS格式中的转换技巧,轻松转换

![【多源数据整合王】:DayDreamInGIS_Geometry在不同GIS格式中的转换技巧,轻松转换](https://community.esri.com/t5/image/serverpage/image-id/26124i748BE03C6A81111E?v=v2) # 摘要 本论文详细介绍了DayDreamInGIS_Geometry这一GIS数据处理工具,阐述了其核心功能以及与GIS数据格式转换相关的理论基础。通过分析不同的GIS数据格式,并提供详尽的转换技巧和实践应用案例,本文旨在指导用户高效地进行数据格式转换,并解决转换过程中遇到的问题。文中还探讨了转换过程中的高级技巧、

物联网技术:共享电动车连接与控制的未来趋势

![物联网技术:共享电动车连接与控制的未来趋势](https://read.nxtbook.com/ieee/potentials/january_february_2020/assets/4cf66356268e356a72e7e1d0d1ae0d88.jpg) # 摘要 本文综述了物联网技术在共享电动车领域的应用,探讨了核心的物联网连接技术、控制技术、安全机制、网络架构设计以及实践案例。文章首先介绍了物联网技术及其在共享电动车中的应用概况,接着深入分析了物联网通信协议的选择、安全机制、网络架构设计。第三章围绕共享电动车的控制技术,讨论了智能控制系统原理、远程控制技术以及自动调度与充电管理

【C#数据绑定高级教程】:深入ListView数据源绑定,解锁数据处理新技能

![技术专有名词:ListView](https://androidknowledge.com/wp-content/uploads/2023/01/customlistthumb-1024x576.png) # 摘要 随着应用程序开发的复杂性增加,数据绑定技术在C#开发中扮演了关键角色,尤其在UI组件如ListView控件中。本文从基础到高级技巧,全面介绍了C#数据绑定的概念、原理及应用。首先概述了C#中数据绑定的基本概念和ListView控件的基础结构,然后深入探讨了数据源绑定的实战技巧,包括绑定简单和复杂数据源、数据源更新同步等。此外,文章还涉及了高级技巧,如数据模板自定义渲染、选中项