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实例。这个方法是我写这篇文章时想到的,-_-!!!,看来知识果真还是好好
  整理呀。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值