From zero RPC (5) Use zookeeper as the registration center, and complete functions such as service discovery

Executive summary:

1. Zookeeper registry dependency

2. Zookeeper realizes the principle of registration center. Node, temporary node, watch mechanism.

3. Use watch to realize the registration center. The client and server use different capabilities of the registry.

 

 

One, first add dependencies

<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 simple application display

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. Encapsulation of Registration Center Code

1. Server-side registry interface capabilities

/**
 * 服务端注册中心
 * <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. Client registry interface capabilities

/**
 * 代表客户端注册中心能力接口
 * <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. Realization of the registration center

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);
			}
			
		}
	}
	
	
}

 

Guess you like

Origin blog.csdn.net/MrBack/article/details/99688401