環(huán)境
dubbo版本: 2.7.3
springCloud版本: 2.2.0
復(fù)現(xiàn)步驟
當使用@Service
注解注入dubbo provider
到Spring容器中時,在dubbo provider
的bean對象里依賴SpringCloud
的bean時硫朦,觸發(fā)報錯烈菌,應(yīng)用報錯無法啟動花履!
dubbo provider bean
@Service(registry = "dubbo-registry", interfaceClass = DubboProvideFacade.class)
public class DubboProviderServiceImpl implements DubboProvideFacade {
@Resource
private FeignClient feignClient;
······
}
SpringCloud Client
@FeignClient(name = "feignClient", url = "${feign.client.config.url}", configuration = FeignClientInterceptor.class)
public interface FeignClient {
······
}
報錯
報錯圖片
Caused by: java.lang.IllegalStateException: <dubbo:service interface="" /> interface not allow null!
at org.apache.dubbo.config.ServiceConfig.checkAndUpdateSubConfigs(ServiceConfig.java:297)
at org.apache.dubbo.config.ServiceConfig.export(ServiceConfig.java:358)
at org.apache.dubbo.config.spring.ServiceBean.export(ServiceBean.java:327)
at org.apache.dubbo.config.spring.ServiceBean.onApplicationEvent(ServiceBean.java:105)
at org.apache.dubbo.config.spring.ServiceBean.onApplicationEvent(ServiceBean.java:51)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:402)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:408)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:359)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:896)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552)
at org.springframework.cloud.context.named.NamedContextFactory.createContext(NamedContextFactory.java:136)
at org.springframework.cloud.context.named.NamedContextFactory.getContext(NamedContextFactory.java:101)
at org.springframework.cloud.context.named.NamedContextFactory.getInstance(NamedContextFactory.java:145)
at org.springframework.cloud.openfeign.FeignClientFactoryBean.get(FeignClientFactoryBean.java:224)
at org.springframework.cloud.openfeign.FeignClientFactoryBean.feign(FeignClientFactoryBean.java:85)
at org.springframework.cloud.openfeign.FeignClientFactoryBean.getTarget(FeignClientFactoryBean.java:261)
at org.springframework.cloud.openfeign.FeignClientFactoryBean.getObject(FeignClientFactoryBean.java:251)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:171)
... 142 common frames omitted
原因
這個錯誤是由 Spring Cloud Feign 設(shè)計引起的济瓢,每個@FeignClient
都會生成一個帶有新子 Spring 的 Feign 代理妹卿,該子 SpringApplicationContext
可能會在其 parent 之前刷新ApplicationContext
蔑鹦。如果有注解@Service
的 Dubbo 服務(wù) bean 被子上下文掃描到箕宙,這個 DubboServiceBean
也會被初始化,并且不能保證其依賴的 Spring bean 在那個時候已經(jīng)準備好
解決方式
方式一(已驗證)
將FeignClient
使用ApplicationContextAware
進行獲取
首先寫一個SpringBean獲取工具類
@Component
public class SpringBeanUtil implements ApplicationContextAware {
private static ApplicationContext appContext;
private static boolean hasBean(String name){
return appContext.containsBean(name);
}
public static Object getBeanByName(String name) throws BeansException {
return appContext.getBean(name);
}
public static Object getBeanByType(Class requiredType) throws BeansException {
return appContext.getBean(requiredType);
}
public static Object getBeanIfPresent(String name){
if(hasBean(name)){
return getBeanByName(name);
}
return null;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
setAppContext(applicationContext);
}
private static synchronized void setAppContext(ApplicationContext appContext) {
SpringBeanUtil.appContext = appContext;
}
}
通過Util獲取FeignClient而不是Spring注入的方式
FeignClient client = SpringContextUtils.getBean(FeignClient.class)
方式二
升級dubbo版本至2.7.9
據(jù)說在2.7.9解決了改問題
方式三
一個不完美的解決方法是,讓FeignClient以來注入的方式進行注入
@Service(registry = "dubbo-registry", interfaceClass = DubboProvideFacade.class)
public class DubboProviderServiceImpl implements DubboProvideFacade {
@Resource
@Lazy
private FeignClient feignClient;
······
}