撸了一个简易的配置中心,顺带整合到了SpringCloud( 四 )


RefreshEventListener
  • 从配置中心再次拉取属性值,而这个拉取的代码逻辑跟项目启动时拉取的属性值核心逻辑几乎是一样的,也是创建一个新的spring容器,加载配置文件和配置类,最后通过PropertySourceLocator获取属性,这一部分核心的代码逻辑是复用的 。
  • 有了最新的属性之后,就开始刷新对象的属性 。
刷新的逻辑实现的非常的巧妙,可不是你以为的简单地将新的属性重新注入对象中,而是通过动态代理的方式来实现的 。
对于在类上加了@RefreshScope注解的Bean,Spring在生成这个Bean的时候,会进行动态代理 。
这里我们就上面举个UserService例子来分析,在生成UserService有两步操作
  • 生成一个UserService对象,将从配置中心拉到的配置sanyou.username注入给UserService对象
  • 由于加了@RefreshScope,会给上一步骤生成的UserService对象进行代理,生成一个代理对象
最后真正暴露出去供我们使用的其实是就是这个代理对象,如图所示

撸了一个简易的配置中心,顺带整合到了SpringCloud

文章插图
由于暴露出去的是一个代理对象,所以当调用getUsername方法的时候,其实是调用UserService的代理对象的getUsername方法,从而就会找到UserService,调用UserService的getUsername获取到username的属性值 。
当配置中心的配置有变动刷新属性的时候,Spring会把UserService这个对象(非代理对象)给销毁,重新创建一个UserService对象,注入最新的属性值 。
当再次通过UserService代理对象获取username属性的时候,就会找最新创建的那个UserService对象,此时就能获取到最新的属性值 。

撸了一个简易的配置中心,顺带整合到了SpringCloud

文章插图
配置每刷新一次,UserService对象就会先销毁再重新创建,但是暴露出去的UserService代理对象一直不会变 。
这样,对于使用者来说,好像是UserService对象的属性自动刷新了,其实本质上是UserService代理对象最终找的UserService对象发生了变化 。
到这应该就知道为什么加了@RefreshScope的对象能够实现配置的自动刷新了,其实依靠的是动态代理完成的 。
3、源码执行流程图由于上面并没有涉及整体执行流程的源码分析,所以我特地结合源码画了两张源码的执行流程图,有兴趣的小伙伴可以对照着图翻一翻具体的源码 。
3.1启动时加载配置流程
撸了一个简易的配置中心,顺带整合到了SpringCloud

文章插图
最终从配置中心获取到的属性会放在项目启动时创建的 Environment 对象里面 。
3.2配置刷新源码流程
撸了一个简易的配置中心,顺带整合到了SpringCloud

文章插图
这个图新增了对于加了@ConfigurationProperties数据绑定的对象原理的分析 。
整合SpringCloud和测试一、整合SpringCloud1、ConfigCenterProperties
撸了一个简易的配置中心,顺带整合到了SpringCloud

文章插图
配置中心的配置信息,这里需要配置配置中心服务端的地址和使用的配置文件的id 。当然这部分信息需要写在bootstrap配置文件中,前面也说过具体的原因 。
2、ConfigCenterPropertySourceLocator上面分析知道,项目启动和刷新的时候,SpringCloud是通过PropertySourceLocator的实现从配置中心加载配置信息,所以这里就得实现一下

撸了一个简易的配置中心,顺带整合到了SpringCloud

文章插图
核心的逻辑就是根据所配置的文件的id,从配置中心拉取配置信息,然后解析配置 。
3、ConfigContextRefresher这个是用来注册文件变动的监听器,来刷新文件的信息的 。

经验总结扩展阅读