此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10spring-doc.cadn.net.cn

TargetSource实现

Spring 提供了TargetSource,以org.springframework.aop.TargetSource接口。该接口负责 返回实现连接点的“目标对象”。这TargetSource每次 AOP 代理处理方法时都会要求实现目标实例 调用。spring-doc.cadn.net.cn

使用 Spring AOP 的开发人员通常不需要直接使用TargetSource实现,但 这提供了一种支持池化、热插拔和其他 复杂的目标。例如,池化TargetSource可以返回不同的目标 实例,通过使用池来管理实例。spring-doc.cadn.net.cn

如果未指定TargetSource,则默认实现用于包装 local 对象。每次调用都会返回相同的目标(正如您所期望的那样)。spring-doc.cadn.net.cn

本节的其余部分介绍了 Spring 提供的标准目标源以及如何使用它们。spring-doc.cadn.net.cn

使用自定义目标源时,您的目标通常需要是原型 而不是单例 bean 定义。这允许 Spring 创建一个新的目标 实例。

热插拔目标源

org.springframework.aop.target.HotSwappableTargetSource存在是为了让目标 的 AOP 代理进行切换,同时让调用方保留对它的引用。spring-doc.cadn.net.cn

更改目标源的目标立即生效。这HotSwappableTargetSource是线程安全的。spring-doc.cadn.net.cn

您可以使用swap()方法,如以下示例所示:spring-doc.cadn.net.cn

HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
Object oldTarget = swapper.swap(newTarget);
val swapper = beanFactory.getBean("swapper") as HotSwappableTargetSource
val oldTarget = swapper.swap(newTarget)

以下示例显示了所需的 XML 定义:spring-doc.cadn.net.cn

<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()调用更改可交换 bean 的目标。持有 引用该 bean 时不知道更改,但立即开始点击 新目标。spring-doc.cadn.net.cn

虽然这个例子没有添加任何建议(没有必要向 使用TargetSource)、任何TargetSource可与 任意建议。spring-doc.cadn.net.cn

池化目标源

使用池化目标源提供与无状态会话类似的编程模型 EJB,其中维护相同实例的池,并调用方法。 去释放池中的对象。spring-doc.cadn.net.cn

Spring 池化和 SLSB 池化之间的一个关键区别在于,Spring 池化可以 应用于任何 POJO。与一般的 Spring 一样,此服务可以应用于 非侵入性方式。spring-doc.cadn.net.cn

Spring 为 Commons Pool 2.2 提供支持,它提供了一个 相当有效的池化实现。您需要commons-poolJar 在您的 应用程序的类路径以使用此功能。您还可以将子类化org.springframework.aop.target.AbstractPoolingTargetSource支持任何其他 池化 API。spring-doc.cadn.net.cn

Commons Pool 1.5+ 也受支持,但从 Spring Framework 4.2 开始被弃用。

以下列表显示了示例配置:spring-doc.cadn.net.cn

<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实现创建新实例 目标的,以根据需要扩大池。请参阅javadoc 的AbstractPoolingTargetSource以及您希望用于信息的具体子类 关于它的属性。maxSize是最基本的,总是保证在场。spring-doc.cadn.net.cn

在这种情况下,myInterceptor是需要 在同一 IoC 上下文中定义。但是,您无需指定拦截器 使用池化。如果您只想要池化而不需要其他建议,请不要将interceptorNames财产。spring-doc.cadn.net.cn

您可以将 Spring 配置为能够将任何池化对象转换为org.springframework.aop.target.PoolingConfig接口,用于公开信息 通过介绍池的配置和当前规模。你 需要定义类似于以下内容的顾问:spring-doc.cadn.net.cn

<bean id="poolConfigAdvisor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
	<property name="targetObject" ref="poolTargetSource"/>
	<property name="targetMethod" value="getPoolingConfigMixin"/>
</bean>

此顾问是通过调用AbstractPoolingTargetSource类,因此使用MethodInvokingFactoryBean.这 顾问姓名 (poolConfigAdvisor,此处)必须位于 这ProxyFactoryBean,这将公开池化对象。spring-doc.cadn.net.cn

演员阵容定义如下:spring-doc.cadn.net.cn

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实现 由任何自动代理创建者使用。spring-doc.cadn.net.cn

原型目标源

设置“原型”目标源类似于设置池TargetSource.在这个 情况下,每次方法调用时都会创建一个目标的新实例。虽然 在现代 JVM 中创建新对象的成本并不高,连接 new 对象(满足其 IoC 依赖项)可能更昂贵。因此,您不应该 没有充分理由使用这种方法。spring-doc.cadn.net.cn

为此,您可以修改poolTargetSource定义如下 (为了清楚起见,我们还更改了名称):spring-doc.cadn.net.cn

<bean id="prototypeTargetSource" class="org.springframework.aop.target.PrototypeTargetSource">
	<property name="targetBeanName" ref="businessObjectTarget"/>
</bean>

唯一的属性是目标 Bean 的名称。继承用于TargetSource实现以确保命名的一致性。与池化目标一样 source,目标 Bean 必须是原型 Bean 定义。spring-doc.cadn.net.cn

ThreadLocal目标来源

ThreadLocal如果需要为每个对象创建对象,则目标源非常有用 传入请求(即每个线程)。的概念ThreadLocal提供 JDK 范围的 将资源透明地存储在线程旁边。设置ThreadLocalTargetSource与其他类型的解释几乎相同 目标源,如以下示例所示:spring-doc.cadn.net.cn

<bean id="threadlocalTargetSource" class="org.springframework.aop.target.ThreadLocalTargetSource">
	<property name="targetBeanName" value="businessObjectTarget"/>
</bean>
ThreadLocal实例会出现严重问题(可能导致内存泄漏) 在多线程和多类加载器环境中错误地使用它们。你 应始终考虑将ThreadLocal在其他类中,并且从不直接使用 这ThreadLocal本身(包装器类除外)。此外,你应该 始终记住正确设置和取消设置(其中后者涉及对ThreadLocal.remove()) 线程本地资源。取消设置应在 无论如何,因为不取消设置可能会导致有问题的行为。Spring的ThreadLocal支持会为您执行此作,并且应始终考虑使用ThreadLocal没有其他正确处理代码的实例。