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