Open xinrong2019 opened 5 years ago
我首先新建了一个模块(工程),采用Sping Cloud方式使用Nacos。
这是我遇到的第一个问题。具体可以参考版本说明
解决方法:
maven中只允许有一个parent依赖,将spring boot parent依赖,加入dependencyManagement中
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
遇到了一个版本兼容问题,参考了 spring boot不用parent引入,采用dependencyManagement引入后的坑
在原有项目启动时,这个import
存在问题,找不到CronTriggerBean这个类。
import org.springframework.scheduling.quartz.CronTriggerBean;
在官方文档中,找不到兼容的信息,只能去github上搜issue,一大堆,没有看的欲望。
去StackOverflow上搜索了“Where is CronTriggerBean in Spring 5”,原来CronTriggerBean替换成了CronTriggerFactoryBean,Spring4的时候改变的。然后就百度搜了搜spring4整合quartz。
搜到了这个答案,
然后改了一些API。调整API适配也是麻烦事。。
上面一种方式放弃,因为项目还是Spring开发,所以试试直接以Spring方式集成
还是报一堆错误
12:04:10.993 [RMI TCP Connection(2)-127.0.0.1] INFO com.alibaba.nacos.client.identify.CredentialWatcher - [] [] [] No credential found
12:04:11.190 [RMI TCP Connection(2)-127.0.0.1] WARN com.alibaba.nacos.spring.core.env.AnnotationNacosPropertySourceBuilder - There is no content for NacosPropertySource from dataId[alibaba-nacos-config-client] , groupId[DEFAULT_GROUP] , properties[{encode=${nacos.encode:UTF-8}, namespace=${nacos.namespace:}, endpoint=${nacos.endpoint:}, contextPath=${nacos.context-path:}, accessKey=${nacos.access-key:}, secretKey=${nacos.secret-key:}, serverAddr=${nacos.server-addr:}, clusterName=${nacos.cluster-name:}}].
12:04:11.196 [RMI TCP Connection(2)-127.0.0.1] ERROR org.springframework.web.context.ContextLoader - Context initialization failed
刚才想到是不是又是版本问题,于是将nacos-spring-context换成了0.3.0版本,结果启动成功了。。。好坑啊。。
14:26 目前启动了,但是设置的值没有获取到
@NacosValue(value = "${ftp.host.url}", autoRefreshed = true)
private String ftpHost;
@RequestMapping(value = "/test", method = GET)
@ResponseBody
public String test() {
return ftpHost;
}
在baidu和stackoverflow搜索spring nacos config结果都不好,都是和spring cloud集成,但是我们的项目是Spring的,如果改成Spring Cloud的,需要做很多兼容性的工作,就偏离了我想引入配置中心的初衷,转而去搞各种版本兼容?
宁愿去开发一套新的,也不想搞这个兼容,除非是去了新公司接手老项目。但是就算是接手老项目,也不想在其上做兼容升级版本,最好是能新开发的新开发,不动已有的。。。
既然上面遇到了一系列问题,最终还是没有解决,我将尝试看网上最多的Spring Cloud版本,看看其原理,然后从内部改造适配。(官方的Spring nacos config example我一直没有跑成功,没有报错,连映射都映射不到)
需要搞清楚的问题:
[ ] 1、nacos配置属性注入的逻辑
[ ] 2、nacos自动刷新配置的逻辑
示例代码以内置的HTTP Server端口作为Nacos Server端口,直接改成默认nacos端口,方便测试
一开始引用的nacos-spring-context是0.2.3-RC1版本,总是启动不了,现有系统使用的是Spring4,在官方issues找到了,是不兼容的bug,换成0.3.0后,项目可以启动了,但是nacos配置没有生效。
再回到0.2.3-RC1版本启动,很多nacos的配置没有找到,比如nacos.cluster-name:
,所以设想应该0.3.0没有解决这个问题,只是让项目启动起来。
引入0.2.3-RC1版本启动时,有如下错误:
LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context:
在DeferredApplicationEventPublisher
类中的publishEvent
方法,需要用try-catch
将方法内容捕获,0.3.0就是这么干的。
debug了源码后发现,我在nacos控制台发布的配置已经获取到了。
Bean实例化了,属性也成功注入了。
我跟踪到AbstractAutowireCapableBeanFactory的createBean方法,打了一个条件断点,
发现断点进来两次,第二次通过nacos拉取的配置是null
项目中Spring Context初始化的流程如下:
1、contextloader初始化spring容器,初始化了configXController
2、rpc-servlet初始化spring容器,没有做任何改变,通过wac.setParent(parent);
将上面的context传递下去
3、spring-mvc初始化spring容器,configXController此时被置空了。
使用spring-mvc.xml
初始化spring容器,虽然也会通过wac.setParent(parent);
将上面的context传递下去,但是在AbstractRefreshableApplicationContext
类中的refreshBeanFactory
方法中,执行loadBeanDefinitions(beanFactory);
后,beanfactory中的configXController
的两个属性被置空了。
逐一排查spring-mvc.xml
配置,看到这一行
<!-- 自动扫描且只扫描@Controller -->
<context:component-scan base-package="cn.evun.ime.**.controller,cn.evun.qns.**.controller" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
我的整合用例是在controller中直接写的,spring-mvc.xml
文件中又对controller进行一次扫描,会不会是这里扫描的时候将前面的属性设置冲掉。带着这个猜想,我把controller中的属性注入移到另外一个专门的配置类中,然后注入配置类,调用配置的中属性的get方法,居然成功了。
总结:
总结一下,版本是spring4,nacos1.0.0,nacos-spring-context0.3.0。
目前,SpringMVC项目的Controller中不能直接注入属性,因为扫了两次包,应该还是项目配置的问题,明天再看。
最近计划在项目中引入分布式配置中心,解决开发中改配置重启麻烦的痛点,大概列了下面三个,都是国内的:
Apollo
disconf
Nacos