Skip to content

Commit

Permalink
Merge pull request #56 from insaneXs/master
Browse files Browse the repository at this point in the history
翻译完11章剩余部分
  • Loading branch information
waylau committed Feb 3, 2018
2 parents b81c411 + c3293f1 commit 59d1197
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 0 deletions.
92 changes: 92 additions & 0 deletions III. Core Technologies/11.10. Using TargetSources.md
@@ -0,0 +1,92 @@
Spring通过`org.springframework.aop.TargetSource`接口提供了TargetSource的概念。这个接口负责返回实现了Joint point的目标对象。`TargetSource`在每次AOP代理处理方法调用时,都会被要求产生一个目标对象。
使用Spring AOP的开发者通常不需要直接使用TargetSources,但这为池,热交换和其他复杂的目标提供了强大的支持。比如,一个池化的TargetSource可以为每个调用返回不同的目标对象,并用池管理这些实例。
如果你没有特指TargetSource,会使用包装本地对象的默认实现。(正如你所期望的)每次调用返回的都是相同的目标。让我们看一下Spring提供的标准的target Source和你该如何使用它们。
>当使用自定义的target source时,你的目标通常要是原型的,而非单例的。这允许Spring在需要时创建新的实例。
### 12.10.1 Hot swappable target sources
`org.springframework.aop.target.HotSwappleTargetSource`的存在允许AOP 代理的目标在调用者仍持有它们引用的情况下替换掉它们。
改变target source的目标会被立刻生效。`HotswappableTargetSource`是线程安全的。
你可以通过HotSwappableTargetSource的`swap()方法`来改变目标:

```
HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
Object 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()`会改变swappable bean的目标。持有这个引用的客户端并不会知道这个变化的过程,但是变化立即生效了。
尽管这个例子中没有添加任何的通知——并且在使用`TargetSource`时不需要添加通知——当然任何`TargetSource`可以和任意通知结合使用。
#### 12.10.2 Pooling target sources
池化的target source提供了和无状态会话EJB相似的编程模型,池中维护着不同的实例,当方法被调用时,可以从池中获取对象。
Spring池和SLSB池关键的区别是Spring池可以应用于任何POJO。通常对Spring而言,服务可以以非入侵的方式被应用。
Spring提供了对Commons Pool 2.2开箱即用的支持,它提供了相当有效率池化实现。如果要使用这个特性,你需要将commons-pool的Jar包添加到应用程序的类路径下。也可以继承`org.springframework.aop.target.AbstractPoolingTargetSource`来支持其他的池化API。
> Spring框架4.2起也支持Commons Pool 1.5+。
下面是配置实例:

```
<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`的实现在需要的时候让池创建一个新的实例。查看Java文档了解`AbstractPoolingTargetSource`和你所希望使用的具体子类的属性:最基础的属性时"maxSize",且必须要保证存在这个属性。
在这个例子中,"myInterceptor"是定义在同一个IoC容器中的拦截器。然而,在使用池时不需要指定拦截器。如果你只希望池化且没有其他的通知,那就不需要设置interceptorsNames的属性。
可以通过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>
```
因为我们使用了MethodInvokingFactoryBean,advisor会在`AbstractPoolingTargetSource`类调用方法时被获得。这个advisor的名字(这里时"poolingConfigAdvisor")一定要在ProxyFactoryBean的拦截器名字的列表中,以暴露被池化的对象。
可以像下面这样转型:

```
PoolingConfig conf = (PoolingConfig) beanFactory.getBean("businessObject");
System.out.println("Max pool size is " + conf.getMaxSize());
```
> 通查,池化管理无状态的服务对象是不必要的。我们不认为这要作为默认的选择,因为大多数无状态的对象时线程安全的,并且如果资源被缓存的话是有问题的。
更简单的池可以使用自动代理。可以为自动代理创造器设置TargetSources。
### 12.10.3 Prototype target sources
设置“原型”的target source和池化TargetSource很像。这种情况下,秒内次调用方法时,都会为目标创建新的实例。尽管在现代的JVM中,创建新对象的话费并不是很高,但(满足IoC依赖的)织入的代价可能会很高。因此在没有特别好的理由下,你不应该使用这个方法。
为了实现这点,你需要将上面的`poolTargetSource`定义做些修改(为了更清晰,我还改了名字。)

```
<bean id="prototypeTargetSource" class="org.springframework.aop.target.PrototypeTargetSource">
<property name="targetBeanName" ref="businessObjectTarget"/>
</bean>
```
这里只有一个属性:目标bean的名字。它继承而来,保证了在TargetSource的各实现中命名的一致性。和pooling target source一样,(prototype target source的)目标bean必须要是原型的bean定义。
### 12.10.4 ThreadLocal taget sources
`ThreadLocal` target sources在你需要为每个请求(即每个线程)创建一个对象时十分有用。`ThreadLocal`的概念是在JDK级别为每个线程透明的存储资源。设置`TheadLocalTargetSource`和其他说明过的target source类型很相似:

```
<bean id="threadlocalTargetSource" class="org.springframework.aop.target.ThreadLocalTargetSource">
<property name="targetBeanName" value="businessObjectTarget"/>
</bean>
```
>在多线程或时多个类加载器环境中,不正确的使用ThreadLocals可能会导致严重的问题(可能引起内存泄漏)。应该考虑用其他类包装threadlocal,而不是直接使用。并且应该记得中正确为线程设置和取消(可以简单的调用`ThreadLocal.set(null)`)资源。无论什么情况下都要记住取消资源,否则可能会引发问题。Spring的ThreadLocal支持为你做了这一点,但你再使用其他没有正确的处理代码的ThreadLocal时,要考虑这点。
3 changes: 3 additions & 0 deletions III. Core Technologies/11.11. Defining new Advice types.md
@@ -0,0 +1,3 @@
Spring AOP被设计成可拓展的。尽管内部使用的策略是拦截器实现的,它还可以支持任意的通知类型,除了开箱即用的拦截器外,还有around advice,before, throws advice和after returning advice。
`org.srpingframework.aop.framework.adapter`包是一个回调函数的包,用来在不改变核心框架的情况下,支持自定义的通知类型。唯一的约束是自定义的通知类型必须要是想`org.aopalliance.aop.Advice`标记接口。
请查阅`org.springframework.aop.framework.adapter`的文档来获取更多信息。
3 changes: 3 additions & 0 deletions III. Core Technologies/11.12. Further resources.md
@@ -0,0 +1,3 @@
请查看Spring实例程序来获得更多关于Spring AOP的应用:
* JPetstore的默认配置说明了如何用`TransactionProxyFactoryBean`声明事物管理。
* JPetStore的`/attributes`目录说明了如何使用属性驱动的声明性事物管理。

0 comments on commit 59d1197

Please sign in to comment.