Apollo client获取服务器的三种方式
1.启动的时候http从服务器获取
2.定时任务定时从服务器获取
3.服务器主动推送到客户端
若不能连接到服务器,则从本地文件获取。
LocalFileConfigRepository 继承 AbstractConfigRepository
RemoteConfigRepository 继承 AbstractConfigRepository
PropertySourcesProcessor继承 BeanFactoryPostProcessor 加载的入口
- NamespaceHandler.doParse()方法解析Apollo的XMl配置
- 解析调用PropertySourcesProcessor.addNamespaces()方法新增到NAMESPACE_NAMES
- PropertySourcesProcessor.postProcessBeanFactory()
- PropertySourcesProcessor.initializePropertySources()
- 循环ConfigService.getConfig(namespace);
- LocalFileConfigRepository createLocalConfigRepository 里面先调用远程的 LocalFileConfigRepository(namespace, createRemoteConfigRepository(namespace));
- 远程则loadApolloConfig() 通过http请求去服务器请求配置信息。
RemoteConfigRepository
trySync()
sync()
ApolloConfig loadApolloConfig() 获取apollo上的配置信息
http://apolloserver:8080/configs/项目目/集群名/namespace?ip=apollo客户端ip
- 调用本地LocalFileConfigRepository 文件写入本地文件。
Apollo长连接
前面提到了Apollo客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。
长连接实际上我们是通过Http Long Polling实现的,具体而言:
客户端发起一个Http请求到服务端 服务端会保持住这个连接30秒 如果在30秒内有客户端关心的配置变化,被保持住的客户端请求会立即返回,并告知客户端有配置变化的namespace信息,客户端会据此拉取对应namespace的最新配置 如果在30秒内没有客户端关心的配置变化,那么会返回Http状态码304给客户端 客户端在服务端请求返回后会自动重连 考虑到会有数万客户端向服务端发起长连,在服务端我们使用了async servlet(Spring DeferredResult)来服务Http Long Polling请求。
一,轮询,长轮询
轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接。 优点:后端程序编写比较容易。 缺点:请求中有大半是无用,浪费带宽和服务器资源。 实例:适于小型应用。
长轮询:客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。 优点:在无消息的情况下不会频繁的请求,耗费资源小。 缺点:服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。 实例:WebQQ、Hi网页版、Facebook IM。
在源码的config package下有一个java类
PropertySourcesProcessor实现的接口有 BeanFactoryPostProcessor, EnvironmentAware, PriorityOrdered。
EnvironmentAware 通过实现EnvironmentAware接口,获取环境变量。
BeanFactoryPostProcessor的使用
BeanFactoryPostProcessor的主要作用是让你能接触到bean definitions,对bean definitions进行一定hack,不允许在BeanFactoryPostProcessor中触发到bean的实例化。
but never bean instances. Doing so may cause premature bean instantiation, violating the container and causing unintended side-effects
可以修改bean的属性值
Apollo配置
通过页面配置
客户端依赖的maven文件
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.1.0</version>
</dependency>
spring配置文件中新增配置
<apollo:config/>
<apollo:config namespaces="apolloDealer"/>
调用测试
@SpringBootApplication
public class ApolloTest {
public static void main(String args[]) {
SpringApplication.run(ApolloTest.class, args);
String[] fn = new String[] {"apollo.xml"};
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(fn);
User user = ctx.getBean("user", User.class);
while (true){
System.out.println("name = " + user.getName());
}
}
}
测试类
@Service
public class User {
@Value("${name:1222}")
private String name;
public String getName(){
return name;
}
public void setName(String name) {
this.name = name;
}
}
Disconf是百度的一个分布式配置中心,目前已经开源。而且它是基于java实现的,有简单的配置页面。
一 配置文件的方式
1.新增app
2.选择新建配置文件
java应用系统调用,resources下新增disconf.properties文件
# 是否使用远程配置文件,true(默认)会从远程获取配置,false则直接从本地获取配置
disconf.enable.remote.conf=true
# 配置服务器的HOST,用逗号分隔
disconf.conf_server_host=disconf链接地址
# 版本号
disconf.version=1.0.0
# APP的名称
disconf.app=p-dealer
# 添加的配置文件所在的环境
disconf.env=local
# 忽略分布式配置
disconf.ignore=
# 获取远程配置重试次数
disconf.conf_server_url_retry_times=1
# 获取远程配置重试时休眠时间
disconf.conf_server_url_retry_sleep_seconds=1
# 用户自定义的下载路径
#disconf.user_define_download_dir=./disconf
applicationContext.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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.jeff" />
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 使用disconf必须添加以下配置 -->
<bean id="disconfMgrBean" class="com.baidu.disconf.client.DisconfMgrBean"
destroy-method="destroy">
<property name="scanPackage" value="com.jeff"/>
</bean>
<bean id="disconfMgrBean2" class="com.baidu.disconf.client.DisconfMgrBeanSecond"
init-method="init" destroy-method="destroy">
</bean>
<bean id="configproperties_disconf"
class="com.baidu.disconf.client.addons.properties.ReloadablePropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:/redis.properties</value>
<value>classpath:/system.properties</value>
</list>
</property>
</bean>
<bean id="propertyConfigurer"
class="com.baidu.disconf.client.addons.properties.ReloadingPropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="propertiesArray">
<list>
<ref bean="configproperties_disconf" />
</list>
</property>
</bean>
</beans>
java测试文件
package com.jeff;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@SpringBootApplication
// 引入disconf
public class DisconfRunMain{
public static void main(String args[]) {
SpringApplication.run(DisconfRunMain.class, args);
String[] fn = new String[] {"applicationContext.xml"};
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(fn);
JedisConfig jedisConfig = ctx.getBean("jedisConfig", JedisConfig.class);
while(true) {
System.out.println("host=" + jedisConfig.getHost());
System.out.println("port=" + jedisConfig.getPort());
}
}
}
运行起来后从页面更新disconf配置文件,系统立马可以读取。
host=192.168.111.199
port=6389
二 配置项
配置项的新增与修改与配置文件略有不同。
package com.jeff;
import com.baidu.disconf.client.common.annotations.DisconfItem;
import org.springframework.stereotype.Service;
@Service
public class User {
private String name;
@DisconfItem(key="name")
public String getName(){
return name;
}
}
使用的时候直接DisconfItem加上配置的key值,就可以直接读取。
原理
Disconf怎么做到实时修改?
Disconf主要是依靠zookeeper的Watch机制来做配置实时修改的,我们都知道ZK是通过目录挂载的方式来做服务的自动注册与发布。客户端启动时注册了一个回调接口,当zk目录发生变化时会回调所有客户端节点,从而做到"实时"更新配置的目的。