最近搞了2个老项目,想把他们融合到一起。这俩项目情况简介如下:
项目一:基于SpringMVC + dubbo,配置读取本地properties文件,少量配置读取apollo
项目二:基于Springboot + dubbo,配置读取apollo
本着就高不就低的原则,顺带就把他们拉平到基于springboot的了,没想到这一番操作引入了一个折腾我2天的坑。
2、现象项目合到一起后,处理掉各种报错后,启动,控制台迅速打印出错误日志:
Caused by: java.net.UnknownHostException: ${zk.address} at java.net.InetAddress.getAllByName0(InetAddress.java:1280) at java.net.InetAddress.getAllByName(InetAddress.java:1192) at java.net.InetAddress.getAllByName(InetAddress.java:1126) at java.net.InetAddress.getByName(InetAddress.java:1076) at io.netty.util.internal.SocketUtils$8.run(SocketUtils.java:156)zk.address是写在项目的spring-dubbo-common.xml中,配置内容如下:
<!--?xml version="1.0" encoding="UTF-8"?--> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemalocation="http://www.springframework.org/schema/beans "> <dubbo:application> <dubbo:registry address="${zk.address}"> <dubbo:protocol port="21660" threadpool="fixed" threads="300"> </dubbo:protocol></dubbo:registry></dubbo:application></beans>具体的值是配置在apollo上的。
3、问题排查 3.1、apollo配置问题?首先想到的是,可能是apollo配置问题。就依次做了如下检查:
检查【src/main/resources/META-INF/app.properties】里面的appId是否和apollo配置中心的一致
检查apollo上的配置,是不是真的有zk.address
检查下【C:\opt\data\ {appId}】目录下的apollo配置缓存,找一下是不是有zk.address的配置
这三点都检查下来,发现配置读取都正常。
3.2、 配置解析问题?配置都正常,但是占位符却没解析,那么想到解析“模块”出了问题。
解析占位符一般通过Spring的PropertySourcesPlaceholderConfigurer来处理。
在Apollo的源码中,已经注册过PropertySourcesPlaceholderConfigurer这个类了,源码com.ctrip.framework.apollo.spring.spi.DefaultApolloConfigRegistrarHelper摘录如下:
public class DefaultApolloConfigRegistrarHelper implements ApolloConfigRegistrarHelper { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AnnotationAttributes attributes = AnnotationAttributes .fromMap(importingClassMetadata.getAnnotationAttributes(EnableApolloConfig.class.getName())); String[] namespaces = attributes.getStringArray("value"); int order = attributes.getNumber("order"); PropertySourcesProcessor.addNamespaces(Lists.newArrayList(namespaces), order); Map<string, object=""> propertySourcesPlaceholderPropertyValues = new HashMap<>(); propertySourcesPlaceholderPropertyValues.put("order", 0); // !! 这里注册了PropertySourcesPlaceholderConfigurer类 !! BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class.getName(), PropertySourcesPlaceholderConfigurer.class, propertySourcesPlaceholderPropertyValues); BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesProcessor.class.getName(), PropertySourcesProcessor.class); BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloAnnotationProcessor.class.getName(), ApolloAnnotationProcessor.class); BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueProcessor.class.getName(), SpringValueProcessor.class); BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueDefinitionProcessor.class.getName(), SpringValueDefinitionProcessor.class); BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloJsonValueProcessor.class.getName(), ApolloJsonValueProcessor.class); } @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } }然后我尝试在PropertySourcesPlaceholderConfigurer里面加断点,看下是不是有进入解析替换配置。
从debug来看,配置解析也正常,能正确解析apollo上的配置。
到这里,我有点纳闷了,已经解析到了,咋还提示报错了呢?难道是dubbo的问题?
3.3、dubbo自身的问题?dubbo的配置,最终会封装成对象。上面配置的zk.address是dubbo:registry的配置,最终会封装成RegistryConfig对象。
类似的还有很多,比如:
ApplicationConfig:对应dubbo:application应用配置
ProtocolConfig:对应协议配置
于是,我在RegistryConfig#setAddress方法加了个断点。看看对象构造时,传入的address参数是多少。