从零RPC(五) 使用zookeeper做注册中心,并完成服务发现等功能

内容提要:

1、zookeeper注册中心依赖

2、zookeeper实现注册中心原理。节点、临时节点、watch机制。

3、利用watch实现注册中心。客户端、服务端使用注册中心不同的能力。

一、首先添加依赖

<dependency>
		    <groupId>org.apache.zookeeper</groupId>
		    <artifactId>zookeeper</artifactId>
		    <version>3.4.5</version>
		    <exclusions> 
             <exclusion>               
                <groupId>javax.jms</groupId> 
                <artifactId>jms</artifactId> 
             </exclusion> 
             <exclusion>                
                 <groupId>com.sun.jdmk</groupId>           
                  <artifactId>jmxtools</artifactId> 
             </exclusion> 
             <exclusion>             
                  <groupId>com.sun.jmx</groupId> 
                  <artifactId>jmxri</artifactId> 
             </exclusion>
          </exclusions>
		</dependency>
		<dependency>
		    <groupId>com.github.sgroschupf</groupId>
		    <artifactId>zkclient</artifactId>
		    <version>0.1</version>
		</dependency>

2、zk API简单应用展示

package com.cloudwise.registy.zk;

import javax.swing.plaf.synth.SynthSpinnerUI;

import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;

/**
  *
  * <p>Title: TestZookeeper 测试zkclient功能代码</p>  
  * <p>Description: </p>  
  * @author back  
  * @date 2019年8月17日
 */
public class TestZookeeper {

	
	public static void main(String[] args) throws InterruptedException {
		
		String addr = "192.168.231.135:2181";
		
		int connectionTimeout = 3000;
		
		ZkClient zkClient = new ZkClient(addr, connectionTimeout);
		
		String path = "/zk-data";
		boolean flag = zkClient.exists(path);
		if(flag)
			zkClient.delete(path);
		//创建永久节点
		zkClient.createPersistent(path);
		//节点下写入数据
		zkClient.writeData(path, "zk store data");
		//读取节点下数据
		String data = zkClient.<String>readData(path, true);
		
		System.out.println("读取数据 :  "+data);
		
		zkClient.subscribeDataChanges(path, new IZkDataListener() {
			
			@Override
			public void handleDataDeleted(String dataPath) throws Exception {
					System.out.println("节点数据删除 !");
			}
			
			@Override
			public void handleDataChange(String dataPath, Object data) throws Exception {
					System.out.println("节点数据更改");
			}
		});
		
		zkClient.writeData(path, "zk store data new");
		
		zkClient.delete(path);
		
		Thread.sleep(Integer.MAX_VALUE);
	}
}

3、注册中心代码封装

1、服务端注册中心接口能力

/**
 * 服务端注册中心
 * <p>Title: IRegisterCenter4Provider.java</p>  
* <p>Description: </p>  
* @author zhaojunjie  
* @date 2020年3月28日  
* @version 1.0
 */
public interface IRegisterCenter4Provider {

	/**
	 * 提供者信息注册到zk节点下
	 * @param serviceMetaData
	 */
	public void registerProvider(final List<ProviderService> serviceMetaData);
	/**
	 * 服务端获取提供者信息
	 * @return
	 */
	public Map<String, List<ProviderService>> getProviderServiceMap();
}

2、客户端注册中心接口能力

/**
 * 代表客户端注册中心能力接口
 * <p>Title: IRegisterCenter4Invoker.java</p>  
* <p>Description: </p>  
* @author zhaojunjie  
* @date 2020年3月28日  
* @version 1.0
 */
public interface IRegisterCenter4Invoker {

	/**
	 * 客户端初始化服务提供者基本信息
	 */
	public void initProviderMap();
	/**
	 * 客户端获取服务端提供者信息
	 * @return
	 */
	public Map<String, List<ProviderService>> getServiceMetaDataMap4Consume();
	/**
	 * 消费端将缴费者信息注册到zk节点下
	 * @param invok
	 */
	public void registerInvoker(final InvokerService invokerService);
}

3、注册中心实现

public class RegisterCenter implements IRegisterCenter4Invoker, IRegisterCenter4Provider{

	private static RegisterCenter registerCenter = new RegisterCenter();
	//key:接口 value:方法
	private static final Map<String, List<ProviderService>> providerServiceMap = new ConcurrentHashMap<>();
	//zk同步的信息
	private static final Map<String, List<ProviderService>> serviceMetaDataMap4Consume = new ConcurrentHashMap<String, List<ProviderService>>();
	
	private static String ZK_SERVICE = PropertyHelper.getProperty("zookeeper", String.class);
	
	private static int ZK_SESSION_TIMEOUT = 3000;
	
	private static int ZK_CONNECT_TIMEOUT = 3000;
	
	private static String ROOT_PATH = "/back_register";

	private static String PROVIDER_TYPE = "/provider";
	
	private static String INVOKER_TYPE = "/consumer";
	
	private static volatile ZkClient zkClient = null;
	
	private RegisterCenter(){}
	
	public static RegisterCenter singleton(){
		return registerCenter;
	}
	@Override
	public void registerProvider(List<ProviderService> serviceMetaData) {
		if(serviceMetaData == null){
			return;
		}
		//连接zk 注册服务
		synchronized (RegisterCenter.class) {
			for (ProviderService providerService : serviceMetaData) {
				String serviceKey = providerService.getServiceInterface().getName();
				List<ProviderService> list = providerServiceMap.get(serviceKey);
				if(list == null){
					list = new ArrayList<ProviderService>();
				}
				list.add(providerService);
				providerServiceMap.put(serviceKey, list);
			}
			if(zkClient == null){
				zkClient = new ZkClient(ZK_SERVICE, ZK_SESSION_TIMEOUT, 
						ZK_CONNECT_TIMEOUT, new SerializableSerializer());
			}
			boolean exists = zkClient.exists(ROOT_PATH);
			
			if(!exists){
				zkClient.createPersistent(ROOT_PATH, true);
			}
			
			for (Entry<String, List<ProviderService>> entry : providerServiceMap.entrySet()) {
				
				String serviceNode = entry.getKey();
				String basePath = ROOT_PATH + "/" + serviceNode;
				String servicePath = ROOT_PATH + "/" + serviceNode + PROVIDER_TYPE;
				exists = zkClient.exists(basePath);
				if(!exists){
					zkClient.createPersistent(basePath);
				}
				exists = zkClient.exists(servicePath);
				if(!exists){
					zkClient.createPersistent(servicePath);
				}
				int servicePort = entry.getValue().get(0).getServicePort();
				String ip = IPHelper.getCurrentIp();
				String currentServiceIpNode = servicePath + "/" + ip + "|" + servicePort;
				exists = zkClient.exists(currentServiceIpNode);
				if(!exists){
					zkClient.createEphemeral(currentServiceIpNode);
				}
				zkClient.subscribeChildChanges(servicePath, new IZkChildListener() {
					
					@Override
					public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
						if(currentChilds == null){
							currentChilds = new ArrayList<>();
						}
						List<String> transform = Lists.transform(currentChilds, new Function<String, String>() {
							@Override
							public String apply(String input) {
								
								return org.apache.commons.lang3.StringUtils.split(input, "|")[0];
							}
						});
						refreshActivityService(transform);
					}

				});
			}
			
		}
	}

	/**
	 * 服务端刷新服务列表
	 */
	private void refreshActivityService(List<String> serviceIpList) {
		
		if(serviceIpList == null){
			serviceIpList = Lists.newArrayList();
		}
		Map<String,List<ProviderService>> currentServiceMetaDataMap = Maps.newHashMap();
		
		for (Entry<String, List<ProviderService>> entry : providerServiceMap.entrySet()) {
			String key = entry.getKey();
			List<ProviderService> providerServices = entry.getValue();
			List<ProviderService> serviceMetaDataModelList = currentServiceMetaDataMap.get(key);
			if(serviceMetaDataModelList == null){
				serviceMetaDataModelList = Lists.newArrayList();
			}
			for (ProviderService providerService : providerServices) {
				if(serviceIpList.contains(providerService.getServerIp())){
					serviceMetaDataModelList.add(providerService);
				}
			}
			currentServiceMetaDataMap.put(key, serviceMetaDataModelList);
		}
		providerServiceMap.putAll(currentServiceMetaDataMap);
	}
	
	/**
	 * 客户端刷新列表
	 * @param transform
	 */
	private void refreshServiceMetaDataMap(List<String> serviceIpList) {
		if(serviceIpList == null){
			serviceIpList = Lists.newArrayList();
		}
		Map<String,List<ProviderService>> currentServiceMetaDataMap = Maps.newHashMap();
		for (Entry<String, List<ProviderService>> entry : serviceMetaDataMap4Consume.entrySet()) {
			String key = entry.getKey();
			List<ProviderService> serviceList = entry.getValue();
			List<ProviderService> providerServiceList = currentServiceMetaDataMap.get(key);
			if(providerServiceList == null){
				providerServiceList = Lists.newArrayList();
			}
			for (ProviderService providerService : serviceList) {
				if(serviceIpList.contains(providerService.getServerIp())){
					providerServiceList.add(providerService);
				}
			}
			currentServiceMetaDataMap.put(key, providerServiceList);
		}
		serviceMetaDataMap4Consume.putAll(currentServiceMetaDataMap);
		System.out.println("serviceMetaDataMap4Consume : " + JsonUtils.writeToString(serviceMetaDataMap4Consume));
	}
	/**
	 * 获得服务信息
	 * @return
	 */
	private Map<String, List<ProviderService>> fetchorUpdateServiceMetaData() {
		Map<String, List<ProviderService>> providerServiceMap = Maps.newConcurrentMap();
		synchronized (RegisterCenter.class) {
			if(zkClient == null){
				zkClient = new ZkClient(ZK_SERVICE, ZK_SESSION_TIMEOUT, 
						ZK_CONNECT_TIMEOUT, new SerializableSerializer());
			}
			String providerPath = ROOT_PATH;
			List<String> providerServices = zkClient.getChildren(providerPath);
			for (String serviceName : providerServices) {
				String servicePath = providerPath + "/" + serviceName + PROVIDER_TYPE;
				List<String> ipList = zkClient.getChildren(servicePath);
				for (String ipPath : ipList) {
					String serverIp = org.apache.commons.lang3.StringUtils.split(ipPath, "|")[0];
					String serverPort = org.apache.commons.lang3.StringUtils.split(ipPath, "|")[1];
					List<ProviderService> providerServiceList = providerServiceMap.get(serviceName);
					if(providerServiceList == null){
						providerServiceList = Lists.newArrayList();
					}
					ProviderService providerService = new ProviderService();
					try {
						providerService.setServiceInterface(ClassUtils.getClass(serviceName));
					} catch (ClassNotFoundException e) {
						throw new RuntimeException(e);
					}
					providerService.setServerIp(serverIp);
					providerService.setServicePort(Integer.parseInt(serverPort));
					providerServiceList.add(providerService);
					providerServiceMap.put(serviceName, providerServiceList);
				}
				zkClient.subscribeChildChanges(servicePath, new IZkChildListener() {
					
					@Override
					public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
						if(currentChilds == null){
							currentChilds = Lists.newArrayList();
						}
						List<String> transform = Lists.transform(currentChilds, new Function<String, String>() {
							@Override
							public String apply(String input) {
								
								return org.apache.commons.lang3.StringUtils.split(input, "|")[0];
							}
						});
						refreshServiceMetaDataMap(transform);
					}

				});
			}
		}
		return providerServiceMap;
	}
	
	@Override
	public Map<String, List<ProviderService>> getProviderServiceMap() {
		return providerServiceMap;
	}

	@Override
	public void initProviderMap() {
		if(MapUtils.isEmpty(serviceMetaDataMap4Consume)){
			serviceMetaDataMap4Consume.putAll(fetchorUpdateServiceMetaData());
		}
	}

	

	@Override
	public Map<String, List<ProviderService>> getServiceMetaDataMap4Consume() {
		return serviceMetaDataMap4Consume;
	}

	@Override
	public void registerInvoker(InvokerService invokerService) {
		if(invokerService == null){
			return;
		}
		
		synchronized (RegisterCenter.class) {
			if(zkClient == null){
				zkClient = new ZkClient(ZK_SERVICE, ZK_SESSION_TIMEOUT, 
						ZK_CONNECT_TIMEOUT, new SerializableSerializer());
			}
			boolean exists = zkClient.exists(ROOT_PATH);
			
			if(!exists){
				zkClient.createPersistent(ROOT_PATH, true);
			}
			
			String serviceNode = invokerService.getTargetInterface().getName();
			String servicePath = ROOT_PATH + "/" + serviceNode + INVOKER_TYPE;
			exists = zkClient.exists(servicePath);
			if(!exists){
				zkClient.createPersistent(servicePath);
			}
			
			String ip = IPHelper.getCurrentIp();
			String currentServiceIpNode = servicePath + "/" + ip;
			exists = zkClient.exists(currentServiceIpNode);
			if(!exists){
				zkClient.createEphemeral(currentServiceIpNode);
			}
			
		}
	}
	
	
}

猜你喜欢

转载自blog.csdn.net/MrBack/article/details/99688401