Dubbo 2.7.3 Integrated Apollo
Problem Description
Dubbo 2.7.3 supports the configuration of the central external configuration, and therefore only need to define a ConfigCenterConfig of Bean.
@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;
}
}
problem:
- Apollo can not find the meta.
- Dubbo provider can not be found
solution
- Apollo can not find the meta, jar of Apollo, apollo-core configuration file clearly declares PRO.meta = "apollo.xxxxx.com:8080". This problem occurs in
apollo.bootstrap.enabled = false
If you want to adhere to this configuration, the need to increase
apollo.meta=apollo.xxxxx.com:8080
- Dubbo can not find the Provider, a closer look at the log Interface: com.xxx.xxx.service, if the latter did not follow the version number, for example: 1.2.0, then the version is not defined.
The problem is that because the definition of a placeholder, while Dubbo start when the class is created ReferenceBean BeanPostProcessor, start early, and apollo.bootstrap.enabled = false.
Dubbo create this IRExecutionService the corresponding Bean class, you can not find the version, but he ate abnormal catch up. Is equal to is not configured version.
apollo.bootstrap.enabled = false
@Reference(version = "${job.service.version}", retries = 0, lazy = true)
private IRExecutionService executionService;
The reason is not available from Dubbo ConfigCenterConfig read version, or too late, if you want to solve very simple, but too dependent on Apollo ahead of the initialization switch.
If you insist on apollo.bootstrap.enabled = false, correct behavior Dubbo how to do?
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);
}
}
}
}
}
ReferenceAnnotationBeanPostProcessor is able to correct the behavior of Dubbo, because this time, there have been ConfigCenterConfig the Bean, so let ConfigCenter early start, so that @Reference comment placeholder can be resolved.
Note that this placeholder is disposed Namespace ( "dubbo"); inside.
Finally, a small problem
Dubbo will default read dubbo this Apollo's namespace, if a custom namespace, he would read, because they do not exist and start to slow down, so in order to speed up the startup speed, suggests an empty dubbo the namespace creation of Apollo.