随笔 - 11, 文章 - 1, 评论 - 20, 引用 - 0
数据加载中……

spring配置中bean的循环引用问题及解决方法

问题:Spring+Hibernate的应用中,定义了两个业务Service,这里分别称它们为serivceA,ServiceB。
它们的关系简单点来说是这样的:
serviceA需要引用serviceB,在serviceB中定义了一个接口列表,serverA必须在serviceB初始化时设置进列表。
在纯bean的情况下,也就是这两个类不需要设置其他bean的情况下,循环引用是正常的,可以通过的。例如下面配置所表示:

    <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>
但是作为一个业务接口,它应该是不需要关心事务,回滚这些无关的东西,
但现实又有这样的需求,所以我们必须保证透明的实现这个功能,于是引
入了AOP方式解决该问题,利用的是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>
于是问题就出现了,Spring报了FactoryBeanCircularReferenceException,无法继续完成设置工作。
查看TransactionProxyFactoryBean源码,其实现了FactoryBean和InitializingBean接口,应该是
做了代理之后,两个代理Bean需要等待所有Bean设置完成后才会标识状态为初始化完毕,于是造成了
冲突。

    由于两个业务服务互相调用的路径是不相交的,所以采用了一种变通的方法,在声明serviceA时,
直接定义serviceB:
  <bean id="serviceAImpl" class="serviceA"  autowire="byName"  lazy-init="true">
     <property name="serviceB">
         <bean class="B"  autowire="byName"/>
     </property>
 </bean>
相当于serviceB和serviceA中使用的serviceB不是同一个实例。
 
 但是如果确实调用重合时怎么办?
 
 解决方法是这样的:
 
 <bean id="serviceAImpl" class="serviceA"  autowire="byName"  lazy-init="true">
     <property name="serviceB">
         <ref bean="serviceBImpl"/>
     </property>
 </bean>
 
  非常简单,serviceAImpl调用时,可能已经在事务环境中了,不需再使用serviceB代理的事务支持,
  于是直接引用serviceB实例。这个方法是我写这篇文章时想到的,-_-!!!,看来知识果真还是好好
  整理呀。

 

posted on 2006-02-07 08:53 wolfsquare 阅读(2550) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航: