如何在默认lazy-init为true的Spring项目中启用可用的RmiServiceExporter?
我来帮你梳理下这个场景下的解决方案,结合你提到的遗留项目多上下文、循环依赖导致全局default-lazy-init=true的背景,咱们一步步来处理:
核心矛盾点分析
你现在的问题在于:为了规避循环依赖,多数上下文开了default-lazy-init=true,但RMI导出的Bean必须提前实例化(毕竟要注册到RMI注册中心,总不能等第一次调用才初始化)。你已经给partnershipPluginService设了lazy-init=false,但要注意它依赖的selectionService、editObjectService等Bean可能还处于懒加载状态,这时候容易出现初始化失败或者服务不可用的问题。
具体解决方案步骤
1. 确保导出Bean的依赖能被正确初始化
当你给partnershipPluginService设为非懒加载后,Spring在启动时会递归初始化它的所有直接/间接依赖——哪怕这些依赖所在的上下文是default-lazy-init=true,Spring也会打破懒加载规则提前初始化它们。不过保险起见,你可以做以下操作:
- 显式给依赖的Bean也加上
lazy-init=false,避免因上下文隔离或自定义配置导致的异常; - 或者在导出Bean的配置里用
depends-on强制指定初始化顺序,确保依赖先于目标Bean初始化:
<bean id="partnershipPluginService" class="com.otr.sufd.services.security.PartnershipPluginServiceImpl" lazy-init="false" depends-on="selectionService,editObjectService"> <property name="selectionService" ref="selectionService"/> <property name="editObjectService" ref="editObjectService"/> <!-- 其他属性配置 --> </bean>
2. 正确配置RMI导出器
要完成RMI导出,你需要在Spring上下文里配置RmiServiceExporter,这个导出器本身必须是非懒加载的(要在启动时注册服务),同时要引用你的目标Bean:
<bean class="org.springframework.remoting.rmi.RmiServiceExporter" lazy-init="false"> <!-- 绑定要导出的服务Bean --> <property name="service" ref="partnershipPluginService"/> <!-- 必须指定服务的接口(接口需可序列化,RMI要求) --> <property name="serviceInterface" value="com.otr.sufd.services.security.PartnershipPluginService"/> <!-- RMI注册中心里的服务名称 --> <property name="serviceName" value="PartnershipPluginService"/> <!-- RMI注册中心端口,默认是1099 --> <property name="registryPort" value="1099"/> </bean>
⚠️ 注意:接口里的所有方法参数和返回值都必须实现Serializable接口,否则RMI调用时会抛出序列化异常。
3. 规避循环依赖的额外注意事项
虽然全局lazy-init=true解决了大部分循环依赖,但强制初始化某些Bean时可能触发隐藏的循环问题。如果遇到循环依赖报错,可以尝试:
- 优先考虑重构代码打破循环(比如引入中间层、把双向依赖改成单向);
- 在循环依赖的其中一端使用
lazy-init="true"(或注解版@Lazy),让Spring延迟初始化该Bean,避免启动时的循环; - 把构造器注入改成setter注入——Spring的循环依赖解决机制主要针对setter注入,构造器注入的循环很难通过懒加载规避。
4. 验证与调试
启动服务后,你可以通过以下方式确认是否正常:
- 查看日志,确认
partnershipPluginService及其依赖的Bean都有类似Creating instance of bean 'xxx'的初始化记录; - 用RMI客户端尝试调用服务,验证功能是否正常;
- 如果初始化失败,重点看日志里的循环依赖报错,定位具体的循环链后针对性调整。
内容的提问来源于stack exchange,提问作者gooamoko

