十、 服务延迟发布
如果你的服务需要预热时间,比如初始化缓存,等待相关资源就位等,可以使用delay进行延迟暴露。我们在Dubbo 2.6.5版本中对服务延迟暴露逻辑进行了细微的调整,将需要延迟暴露(delay>0)服务的倒计时动作推迟到了Spring初始化完成后进行。你在使用Dubbo的过程中,并不会感知到此变化,因此请放心使用。
1. Dubbo 2.6.5之前版本
延迟到Spring初始化完成后,再暴露服务。
延迟5秒暴露服务
2. Dubbo 2.6.5及以后版本
所有服务都将在Spring初始化完成后进行暴露,如果你不需要延迟暴露服务,无需配置delay。
延迟5秒暴露服务
3. Spring 2.x初始化死锁问题
1) 触发条件
在Spring解析到时,就已经向外暴露了服务,而Spring还在接着初始化其它Bean。如果这时有请求进来,并且服务的实现类里有调用applicationContext.getBean()的用法。
• 请求线程的applicationContext.getBean()调用,先同步singletonObjects判断Bean是否存在,不存在就同步beanDefinitionMap进行初始化,并再次同步singletonObjects写入Bean实例缓存。
• 而Spring初始化线程,因不需要判断Bean的存在,直接同步beanDefinitionMap进行初始化,并同步singletonObjects写入Bean实例缓存。
这样就导致getBean线程,先锁singletonObjects,再锁beanDefinitionMap,再次锁singletonObjects。
而Spring初始化线程,先锁beanDefinitionMap,再锁singletonObjects。反向锁导致线程死锁,不能提供服务,启动不了。
2) 规避办法
• 强烈建议不要在服务的实现类中有applicationContext.getBean()的调用,全部采用IoC注入的方式使用Spring的Bean。
• 如果实在要调getBean(),可以将Dubbo的配置放在Spring的最后加载。
• 如果不想依赖配置顺序,可以使用,使Dubbo在Spring容器初始化完后,再暴露服务。
• 如果大量使用getBean(),相当于已经把Spring退化为工厂模式在用,可以将Dubbo的服务隔离单独的Spring容器。