使用实现TargetSource
Spring 提供了在接口中表示的 , 的概念。此接口负责
返回实现连接点的 “target object”。每次 AOP 代理处理方法时,都会请求目标实例的实现
调用。TargetSource
org.springframework.aop.TargetSource
TargetSource
使用 Spring AOP 的开发人员通常不需要直接使用实现,但是
这提供了一种强大的方法来支持池化、热插拔和其他
复杂的目标。例如,池化可以返回不同的目标
instance 的实例,方法是使用池来管理实例。TargetSource
TargetSource
如果未指定 a ,则默认实现用于包装
local 对象。每次调用都会返回相同的目标(如您所料)。TargetSource
本节的其余部分介绍了 Spring 提供的标准目标源以及如何使用它们。
使用自定义目标源时,您的目标通常需要是原型 而不是单例 bean 定义。这允许 Spring 创建一个新目标 实例。 |
热插拔目标源
存在让目标
的 AOP 代理,同时让调用者保留对它的引用。org.springframework.aop.target.HotSwappableTargetSource
更改目标源的目标将立即生效。这是线程安全的。HotSwappableTargetSource
您可以使用 HotSwappableTargetSource 上的方法来更改目标,如下例所示:swap()
-
Java
-
Kotlin
HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
Object oldTarget = swapper.swap(newTarget);
val swapper = beanFactory.getBean("swapper") as HotSwappableTargetSource
val oldTarget = swapper.swap(newTarget)
以下示例显示了所需的 XML 定义:
<bean id="initialTarget" class="mycompany.OldTarget"/>
<bean id="swapper" class="org.springframework.aop.target.HotSwappableTargetSource">
<constructor-arg ref="initialTarget"/>
</bean>
<bean id="swappable" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource" ref="swapper"/>
</bean>
前面的调用更改了可交换 bean 的目标。持有
引用时,该 bean 不知道更改,但立即开始点击
新目标。swap()
虽然这个例子没有添加任何 advice(没有必要在
使用 a ),any 可以与
武断的建议。TargetSource
TargetSource
池化目标源
使用池化目标源提供与无状态会话类似的编程模型 EJB,其中维护了一个相同实例的池,具有方法调用 正在释放池中的对象。
Spring 池和 SLSB 池之间的一个关键区别是 Spring 池可以 应用于任何 POJO。与一般的 Spring 一样,此服务可以应用于 非侵入性方式。
Spring 提供了对 Commons Pool 2.2 的支持,它提供了一个
相当有效的池实现。您需要 Jar
application 的 Classpath 来使用此功能。你也可以子类来支持任何其他
pooling API 的 API 中。commons-pool
org.springframework.aop.target.AbstractPoolingTargetSource
Commons Pool 1.5+ 也受支持,但从 Spring Framework 4.2 开始已弃用。 |
下面的清单显示了一个示例配置:
<bean id="businessObjectTarget" class="com.mycompany.MyBusinessObject"
scope="prototype">
... properties omitted
</bean>
<bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPool2TargetSource">
<property name="targetBeanName" value="businessObjectTarget"/>
<property name="maxSize" value="25"/>
</bean>
<bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource" ref="poolTargetSource"/>
<property name="interceptorNames" value="myInterceptor"/>
</bean>
请注意,目标对象(在前面的示例中为 )必须是
原型。这允许 implementation 创建新实例
的目标以根据需要增加池。请参阅 AbstractPoolingTargetSource
的 javadoc 和您希望使用的具体子类以获取信息
关于其属性。 是最基本的,并且始终保证存在。businessObjectTarget
PoolingTargetSource
maxSize
在本例中, 是需要
在相同的 IoC 上下文中定义。但是,您无需指定拦截器来
使用池化。如果只需要 pooling 而不想要其他建议,则根本不要设置该属性。myInterceptor
interceptorNames
你可以配置 Spring 以便能够将任何池化对象强制转换为接口,从而公开信息
通过简介介绍池的配置和当前大小。你
需要定义一个类似于以下内容的 advisor:org.springframework.aop.target.PoolingConfig
<bean id="poolConfigAdvisor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="poolTargetSource"/>
<property name="targetMethod" value="getPoolingConfigMixin"/>
</bean>
此顾问是通过对类调用便捷方法获得的,因此使用 .这
advisor 的名称 (, here) 必须在
公开 pooled 对象的 API。AbstractPoolingTargetSource
MethodInvokingFactoryBean
poolConfigAdvisor
ProxyFactoryBean
演员定义如下:
-
Java
-
Kotlin
PoolingConfig conf = (PoolingConfig) beanFactory.getBean("businessObject");
System.out.println("Max pool size is " + conf.getMaxSize());
val conf = beanFactory.getBean("businessObject") as PoolingConfig
println("Max pool size is " + conf.maxSize)
通常不需要池化无状态服务对象。我们认为不应该 是默认选项,因为大多数无状态对象本质上是线程安全的,而实例 如果缓存了资源,则池化是有问题的。 |
使用自动代理可以实现更简单的池化。您可以设置实现
由任何 Auto-Proxy Creator 使用。TargetSource
原型目标源
设置“原型”目标源与设置池类似 。在这个
case,则在每次方法调用时都会创建一个 Target 的新实例。虽然
在现代 JVM 中,创建新对象的成本并不高,将
新对象(满足其 IoC 依赖项)可能更昂贵。因此,您不应该
使用这种方法没有很好的理由。TargetSource
为此,您可以修改前面显示的定义,如下所示
(为清楚起见,我们还更改了名称):poolTargetSource
<bean id="prototypeTargetSource" class="org.springframework.aop.target.PrototypeTargetSource">
<property name="targetBeanName" ref="businessObjectTarget"/>
</bean>
唯一的属性是目标 Bean 的名称。在实现中使用继承来确保命名一致。与池化目标一样
source,则目标 Bean 必须是原型 Bean 定义。TargetSource
ThreadLocal
目标源
ThreadLocal
如果需要为每个源创建一个对象,则 target 源非常有用
传入请求(即每个线程)。a 的概念提供了 JDK 范围的
工具以透明方式将资源与线程一起存储。设置 a 与为其他类型的解释几乎相同
的目标源,如下例所示:ThreadLocal
ThreadLocalTargetSource
<bean id="threadlocalTargetSource" class="org.springframework.aop.target.ThreadLocalTargetSource">
<property name="targetBeanName" value="businessObjectTarget"/>
</bean>
ThreadLocal 实例存在严重问题(可能导致内存泄漏),当
在多线程和多类加载器环境中错误地使用它们。你
应该始终考虑将 a 包装在其他类中,并且永远不要直接使用
本身(包装器类除外)。此外,您应该
请始终记住正确设置和取消设置(如果后者涉及对 )线程本地资源的调用。取消设置应在
无论如何,因为不取消设置它可能会导致有问题的行为。Spring 的支持为您完成了此操作,并且应始终考虑使用实例,而无需其他适当的处理代码。ThreadLocal ThreadLocal ThreadLocal.remove() ThreadLocal ThreadLocal |