問(wèn)題:Spring+Hibernate的應(yīng)用中,定義了兩個(gè)業(yè)務(wù)Service,這里分別稱它們?yōu)閟erivceA,ServiceB。
它們的關(guān)系簡(jiǎn)單點(diǎn)來(lái)說(shuō)是這樣的:
serviceA需要引用serviceB,在serviceB中定義了一個(gè)接口列表,serverA必須在serviceB初始化時(shí)設(shè)置進(jìn)列表。
在純bean的情況下,也就是這兩個(gè)類不需要設(shè)置其他bean的情況下,循環(huán)引用是正常的,可以通過(guò)的。例如下面配置所表示:
<bean id="serviceA" class="A" autowire="byName" lazy-init="true">
<property name="serviceB"><ref local="serviceB"/></property>
</bean>
<bean id="serviceB" class="B" autowire="byName" lazy-init="true">
<property name="serviceA"><ref bean="serviceA"/></property>
</bean>
但是作為一個(gè)業(yè)務(wù)接口,它應(yīng)該是不需要關(guān)心事務(wù),回滾這些無(wú)關(guān)的東西,
但現(xiàn)實(shí)又有這樣的需求,所以我們必須保證透明的實(shí)現(xiàn)這個(gè)功能,于是引
入了AOP方式解決該問(wèn)題,利用的是Spring自帶的org.springframework.t
ransaction.interceptor.TransactionProxyFactoryBean.
重新聲明文件如下:
<bean id="baseTxProxy" lazy-init="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="proxyTargetClass"><value>true</value></property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="serviceA" parent="baseTxProxy">
<property name="target"><ref local="serviceAImpl"/></property>
</bean>
<bean id="serviceAImpl" class="serviceA" autowire="byName" lazy-init="true">
<property name="serviceB">
<ref bean="serviceB"/>
</property>
</bean>
<bean id="serviceB" parent="baseTxProxy" lazy-init="true">
<property name="target"><ref local="serviceBImpl"/></property>
</bean>
<bean id="serviceBImpl" class="D" lazy-init="true">
<property name="serviceA">
<ref bean="serviceA"/>
</property>
</bean>
于是問(wèn)題就出現(xiàn)了,Spring報(bào)了FactoryBeanCircularReferenceException,無(wú)法繼續(xù)完成設(shè)置工作。
查看TransactionProxyFactoryBean源碼,其實(shí)現(xiàn)了FactoryBean和InitializingBean接口,應(yīng)該是
做了代理之后,兩個(gè)代理Bean需要等待所有Bean設(shè)置完成后才會(huì)標(biāo)識(shí)狀態(tài)為初始化完畢,于是造成了
沖突。
由于兩個(gè)業(yè)務(wù)服務(wù)互相調(diào)用的路徑是不相交的,所以采用了一種變通的方法,在聲明serviceA時(shí),
直接定義serviceB:
<bean id="serviceAImpl" class="serviceA" autowire="byName" lazy-init="true">
<property name="serviceB">
<bean class="B" autowire="byName"/>
</property>
</bean>
相當(dāng)于serviceB和serviceA中使用的serviceB不是同一個(gè)實(shí)例。
但是如果確實(shí)調(diào)用重合時(shí)怎么辦?
解決方法是這樣的:
<bean id="serviceAImpl" class="serviceA" autowire="byName" lazy-init="true">
<property name="serviceB">
<ref bean="serviceBImpl"/>
</property>
</bean>
非常簡(jiǎn)單,serviceAImpl調(diào)用時(shí),可能已經(jīng)在事務(wù)環(huán)境中了,不需再使用serviceB代理的事務(wù)支持,
于是直接引用serviceB實(shí)例。這個(gè)方法是我寫(xiě)這篇文章時(shí)想到的,-_-!!!,看來(lái)知識(shí)果真還是好好
整理呀。