1、引入 jar 包
<dependencies>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
</dependencies>
2、新建工具类 ZookeeperClients
public class ZookeeperClients {
private final CuratorFramework client;
private static ZookeeperClients INSTANCE;
static {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory.newClient("101.132.167.18:2181",retryPolicy);
INSTANCE = new ZookeeperClients(client);
}
private ZookeeperClients(CuratorFramework client){
this.client = client;
}
public static CuratorFramework client(){
return INSTANCE.client;
}
}
3、新建 ReadyRestartInstances
public class ReadyRestartInstances implements PathChildrenCacheListener {
private static final Logger LOGGER = LoggerFactory.getLogger(ReadyRestartInstances.class);
private static final String LISTEN_PATHS = "/lagou/dubbo/restart/instances";
private final CuratorFramework zkClient;
// 当节点变化时,给这个集合赋值,重启机器的信息列表
private volatile Set<String> restartInstance = new HashSet<>();
private ReadyRestartInstances(CuratorFramework zkClient){
this.zkClient = zkClient;
}
public static ReadyRestartInstances create(){
final CuratorFramework zookeeperClient = ZookeeperClients.client();
try{
// 检查监听路径是否存在
final Stat stat = zookeeperClient.checkExists().forPath(LISTEN_PATHS);
// 如果监听路径不存在,则创建
if(stat == null){
zookeeperClient.create().creatingParentsIfNeeded().forPath(LISTEN_PATHS);
}
}catch (Exception e){
e.printStackTrace();
LOGGER.error("确保基础路径存在");
}
final ReadyRestartInstances instances = new ReadyRestartInstances(zookeeperClient);
// 创建一个 NodeCache
PathChildrenCache nodeCache = new PathChildrenCache(zookeeperClient,LISTEN_PATHS,false);
// 给节点缓存对象加入监听
nodeCache.getListenable().addListener(instances);
try{
nodeCache.start();
}catch (Exception e){
e.printStackTrace();
LOGGER.error("启动监听失败");
}
return instances;
}
/** 返回应用名 和 主机拼接后的字符串 **/
private String buildApplicationAndInstanceString(String applicationName,String host){
return applicationName + "_" + host;
}
/** 增加重启实例的配置信息方法 **/
public void addRestartingInstance(String applicationName,String host) throws Exception{
zkClient.create().creatingParentsIfNeeded().forPath(LISTEN_PATHS + "/" + buildApplicationAndInstanceString(applicationName,host));
}
/** 删除重启实例的配置信息方法 **/
public void deleteRestartingInstance(String applicationName,String host) throws Exception{
zkClient.delete().forPath(LISTEN_PATHS + "/" + buildApplicationAndInstanceString(applicationName,host));
}
/** 判断节点信息是否存在于 restartInstances **/
public boolean hasRestartingInstance(String applicationName,String host){
return restartInstance.contains(buildApplicationAndInstanceString(applicationName,host));
}
@Override
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
// 查询出监听路径下所有的目录配置信息
final List<String> restartingInstances = zkClient.getChildren().forPath(LISTEN_PATHS);
// 给 restartInstances;
if(CollectionUtils.isEmpty(restartingInstances)){
this.restartInstance = Collections.emptySet();
}else{
this.restartInstance = new HashSet<>(restartingInstances);
}
}
}
4、新建 RestartingInstanceRouter
public class RestartingInstanceRouter implements Router {
private final ReadyRestartInstances instances;
private final URL url;
public RestartingInstanceRouter(URL url){
this.url = url;
this.instances = ReadyRestartInstances.create();
}
@Override
public URL getUrl() {
return url;
}
@Override
public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
// 如果没有在重启列表中,才会加入到后续调用列表
return invokers.stream().filter(i->!instances.hasRestartingInstance(
i.getUrl().getParameter("remote.application"),
i.getUrl().getIp())).collect(Collectors.toList());
}
@Override
public boolean isRuntime() {
return false;
}
@Override
public boolean isForce() {
return false;
}
@Override
public int getPriority() {
return 0;
}
}
5、新建 RestartingInstanecRouterFactory
@Activate
public class RestartingInstanecRouterFactory implements RouterFactory {
@Override
public Router getRouter(URL url) {
return new RestartingInstanceRouter(url);
}
}
6、配置文件:
包名:META-INF/dubbo
文件名:org.apache.dubbo.rpc.cluster.RouterFactory
restartInstances=com.deppon.util.RestartingInstanecRouterFactory
7、启动类:ServerRestartMain
public class ServerRestartMain {
public static void main(String[] args) throws Exception {
// ReadyRestartInstances.create().addRestartingInstance("server-provider","xxx.xx.xx.xx");
ReadyRestartInstances.create().removeRestartingInstance("server-provider","xxx.xx.xx.xx");
}
}