Dubbo 2.7.3支持配置中心外部化配置, 所以只須要定義一個ConfigCenterConfig的Bean。html
@EnableDubbo(scanBasePackages = {"com.slankka.cloud.dubbo"}) @Configuration public class DubboConfig { @Bean public ConfigCenterConfig configCenterConfig() { ConfigCenterConfig configCenterConfig = new ConfigCenterConfig(); configCenterConfig.setAddress("apollo.xxxxx.com:8080"); configCenterConfig.setProtocol("apollo"); configCenterConfig.setNamespace("dubbo"); configCenterConfig.setGroup(null); return configCenterConfig; } }
問題:java
Apollo的jar 的apollo-core的配置文件明明聲明瞭PRO.meta="apollo.xxxxx.com:8080"。
這個問題出如今git
apollo.bootstrap.enabled = false
若是要堅持這樣配置,須要增長github
apollo.meta=apollo.xxxxx.com:8080
更新:此問題還有更深刻的分析: Apollo報錯找不到apollo.meta的問題解決方案spring
仔細看日誌 Interface: com.xxx.xxx.service,若是後面沒有跟着版本號例如: 1.2.0,則說明版本沒有定義。
問題是由於定義了佔位符,而Dubbo啓動的時候,建立ReferenceBean的類是個BeanPostProcessor,啓動比較早,而apollo.bootstrap.enabled=false。
則Dubbo建立這個IRExecutionService對應的Bean類的時候,找不到version,可是他catch吃掉異常了。等於沒有配置version。apache
apollo.bootstrap.enabled = false @Reference(version = "${job.service.version}", retries = 0, lazy = true) private IRExecutionService executionService;
則緣由是Dubbo不能從ConfigCenterConfig讀取版本配置,或者太遲了,若是要解決很簡單 ,可是太依賴Apollo提早初始化開關。bootstrap
package io.github.slankka.dubbo-apollo.server.config; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.Configuration; import org.apache.dubbo.common.config.Environment; import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ConfigCenterConfig; import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor; import org.apache.dubbo.configcenter.DynamicConfiguration; import org.apache.dubbo.configcenter.DynamicConfigurationFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.InjectionMetadata; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.bind.PropertySourcesPlaceholdersResolver; import org.springframework.context.ApplicationContext; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.env.PropertySource; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.ArrayList; import java.util.List; import static org.apache.dubbo.common.config.ConfigurationUtils.parseProperties; /** * Project: dubbo-apollo * * @author slankka on 2019/8/29. */ @ConditionalOnProperty(name = "apollo.bootstrap.enabled", havingValue = "false", matchIfMissing = true) @Component(value = ReferenceAnnotationBeanPostProcessor.BEAN_NAME) public class ReferencedAnnotationPatch extends ReferenceAnnotationBeanPostProcessor { private ApplicationContext myContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { myContext = applicationContext; super.setApplicationContext(applicationContext); } @Override protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType, InjectionMetadata.InjectedElement injectedElement) throws Exception { eagerInitConfigCenter(); Configuration configuration = Environment.getInstance().getConfiguration(); List<PropertySource<?>> propertySources = new ArrayList<>(); propertySources.add(new PropertySource<Configuration>("dubboConfigCenter", configuration) { @Override public Object getProperty(String name) { return configuration.getProperty(name); } }); PropertySourcesPlaceholdersResolver propertySourcesPlaceholdersResolver = new PropertySourcesPlaceholdersResolver(propertySources); for (String attribute : attributes.keySet()) { Object stringAttr = attributes.get(attribute); if (stringAttr instanceof String) { Object value = propertySourcesPlaceholdersResolver.resolvePlaceholders(attributes.getString(attribute)); attributes.put(attribute, value); } } return super.doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement); } private void eagerInitConfigCenter() { ConfigCenterConfig configCenter = myContext.getBean(ConfigCenterConfig.class); if (configCenter.isValid()) { if (configCenter.checkOrUpdateInited()) { configCenter.refresh(); URL url = configCenter.toUrl(); DynamicConfigurationFactory factories = ExtensionLoader .getExtensionLoader(DynamicConfigurationFactory.class) .getExtension(url.getProtocol()); DynamicConfiguration dynamicConfiguration = factories.getDynamicConfiguration(url); String configContent = dynamicConfiguration.getProperties(configCenter.getConfigFile(), configCenter.getGroup()); ApplicationConfig application = myContext.getBean(ApplicationConfig.class); String appGroup = application.getName(); String appConfigContent = null; if (StringUtils.isNotEmpty(appGroup)) { appConfigContent = dynamicConfiguration.getProperties (StringUtils.isNotEmpty(configCenter.getAppConfigFile()) ? configCenter.getAppConfigFile() : configCenter.getConfigFile(), appGroup ); } try { Environment.getInstance().setConfigCenterFirst(configCenter.isHighestPriority()); Environment.getInstance().updateExternalConfigurationMap(parseProperties(configContent)); Environment.getInstance().updateAppExternalConfigurationMap(parseProperties(appConfigContent)); } catch (IOException e) { throw new IllegalStateException("Failed to parse configurations from Config Center.", e); } } } } }
則能糾正Dubbo 的ReferenceAnnotationBeanPostProcessor 行爲,由於這個時候,已經有ConfigCenterConfig這個Bean了,因此讓ConfigCenter提早啓動,從而使得@Reference註解的佔位符可以被解析。
注意,這個佔位符是配置在Namespace("dubbo");內的。app
Dubbo 會默認讀取 dubbo這個 Apollo的namespace,若是用自定義的namespace,他也會讀取,由於不存在而啓動減慢,因此爲了加快啓動速度,建議建立Apollo的 一個空dubbo的namespace。ide