来源:http://www.softstudio.com.cn/leadbbs/Announce/announce2.asp?BoardID=200&ID=183&TopicSortID=183
5.10. 使用TargetSources
Spring提供了TargetSource的概念,由 org.springframework.aop.TargetSource接口定义。这个接口负责返回实现切入点的 “目标对象”。每次AOP代理处理方法调用时,目标实例都会用到TargetSource实现。
使用Spring AOP的开发者一般不需要直接使用TargetSources,但是这提供了一种强大的方法来支持池,热交换, 和其它复杂目标。例如,一个支持池的TargetSource可以在每次调用时返回不同的目标对象实例,使用池来管理实例。
如果你没有指定TargetSource,就使用缺省的实现,它封装了一个本地对象。每次调用会返回相同的目标对象 (和你期望的一样)。
让我们来看一下Spring提供的标准目标源,以及如何使用它们。
当使用定制目标源时,你的目标通常需要定义为prototype bean,而不是singleton bean。这使得 Spring在需要的时候创建一个新的目标实例。
5.10.1. 可热交换的目标源
org.springframework.aop.target.HotSwappableTargetSource 允许切换一个AOP代理的目标,而调用者维持对它的引用。
修改目标源的目标会立即起作用。并且HotSwappableTargetSource是线程安全的。
你可以通过HotSwappableTargetSource的swap()方法 来改变目标,就象下面一样:
HotSwappableTargetSource swapper =
(HotSwappableTargetSource) beanFactory.getBean("swapper");
Object oldTarget = swapper.swap(newTarget);
所需的XML定义如下:
上面的swap()调用会修改swappable这个bean的目标。持有对这个bean应用的客户端 将不会知道这个变化,但会立刻转为使用新的目标对象。
虽然这个例子没有添加任何通知--使用TargetSource也没必要添加通知-- 当然任何TargetSource都可以和任何一种通知一起使用。
5.10.2. 支持池的目标源
使用支持池的目标源提供了一种和无状态的session EJB类似的编程模式,在无状态的session EJB中,维护了 一个相同实例的池,提供从池中获取可用对象的方法。
Spring的池和SLSB的池之间的重要区别在于Spring的池可以被应用到任何普通Java对象。就象Spring的通用 的做法,这个业务也可以以非侵入的方式被应用。
Spring直接支持Jakarta Commons Pool 1.1,它是一种非常高效的池实现。使用这个功能,你需要在你的应用的 classpath中添加commons-pool的Jar文件。也可以直接继承 org.springframework.aop.target.AbstractPoolingTargetSource来支持其它池API。
下面是一个配置的例子:
<bean class="com.mycompany.MyBusinessObject" id="businessObjectTarget"></bean>
注意例子中的目标对象“businessObjectTarget”必须是prototype。这样在 PoolingTargetSource的实现在扩大池容量的时候可以创建目标的新实例。关于这些属性的 信息可以参考AbstractPoolingTargetSource和子类的Javadoc。maxSize是最基本的属性, 被保证总是存在。
在这种情况下,名字为“myInterceptor”的拦截器需要定义在同一个IoC上下文中。但是,并不一定需要 指定拦截器也用池。如果你仅需要池,并且没有其它通知,可以根本不设置属性interceptorNames。
也可以配置Spring以便可以将任何池化的对象转换类型为 org.springframework.aop.target.PoolingConfig接口。通过这个接口的一个引入,可以得到 配置信息和池的当前大小。你需要这样定义一个advisor:
<bean id="poolConfigAdvisor"></bean>
<bean id="poolConfigAdvisor"></bean>
通过调用AbstractPoolingTargetSource类上的方法,可以得到这个advisor, 因此使用MethodInvokingFactoryBean。这个advisor的名字(“poolConfigAdvisor”)必须在暴露池化对象的 This advisor is obtained by calling a convenience method on the ProxyFactoryBean中的拦截器名字列表中。
这个类型转换就象下面:
池化无状态业务对象并不是总是必要的。我们不认为这是缺省选择,因为大多数无状态对象自然就是线程 安全的,如果资源被缓存,实例池化会有问题。
简单的池也可以使用自动代理。任何自动代理生成器都可以设置TargetSources。
5.10.3. Prototype目标源
设置“prototype”目标源和支持池的目标源类似。在每次方法调用的时候都会创建一个新的目标实例。 虽然在现代JVM中创建对象的代价不是很高,但是装配新对象的代价可能更高(为了maz满足它的IoC依赖关系)。 因此没有好的理由不应该使用这个方法。
为了这么做,你可以修改上面的的poolTargetSource定义,就向下面一样。 (为了清晰起见,我修改了名字。)
只有一个属性:目标bean的名字。在TargetSource实现中使用继承是为了保证命名的一致性。就象支持池的 目标源一样,目标bean必须是一个prototype的bean定义。
5.11. 定义新的通知类型
Spring AOP设计能够很容易地扩展。虽然拦截实现的策略目前只在内部使用,但还是有可能支持拦截around通知, before通知,throws通知和after returning通知以外的任何通知类型。
org.springframework.aop.framework.adapter 包是一个支持添加新的定制通知类型而不修改核心框架的SPI(译:可能是API)包。定制通知类型的唯一限制是它必须实现 org.aopalliance.aop.Advice标记接口。
更多信息请参考org.springframework.aop.framework.adapter包的Javadoc。
5.12. 进一步的资料和资源
对于AOP的介绍,我推荐Ramnivas Laddad (Manning, 2003)写的AspectJ in Action。
进一步的Spring AOP的例子请参考Spring的示例应用:
JPetStore的缺省配置演示了使用TransactionProxyFactoryBean来定义声明式事务管理。
JPetStore的/attributes目录演示了属性驱动的声明式事务管理。
如果你对Spring AOP更多高级功能感兴趣,可以看一下测试套件。测试覆盖率超过90%,并且演示了本文档没有提到 的许多高级功能。
5.13. 路标
Spring AOP,就象Spring的其它部分,是开发非常活跃的部分。核心API已经稳定了。象Spring的其它部分一样, AOP框架是非常模块化的,在保留基础设计的同时提供扩展。在Spring 1.1到1.2阶段有很多地方可能会有所提高,但是这 些地方也保留了向后兼容性。它们是:
性能的提高:AOP代理的创建由工厂通过策略接口处理。因此我们能够支持额外的AOP 代理类型而不影响用户代码或核心实现。对于Spring 1.1,我们正在检查AOP代理实现的所有字节码,万一不需要 运行时通知改变。这应该大大减少AOP框架的额外操作。但是注意,AOP框架的额外操作不是在普通使用中需要考虑 的内容。
更具表达力的切入点:Spring目前提供了一个具有表达力的切入点接口,但是我们 添加更多的切入点实现。我们正在考虑提供一个简单但具有强大表达式语言的实现。如果你希望贡献一个有用的 切入点实现,我们将非常欢迎。
引入方面这个高层概念,它包含多个advisor。