All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hc360.rsf.rpc.protocol.RsfInvokerClientReg Maven / Gradle / Ivy

The newest version!
/**
 * RsfInvokerClientReg.java   2012-6-15
 * Copyright(c) 2000-2012 HC360.COM, All Rights Reserved.
 */
package com.hc360.rsf.rpc.protocol;

import java.text.MessageFormat;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hc360.rsf.common.Constants;
import com.hc360.rsf.common.URL;
import com.hc360.rsf.config.ClientConfig;
import com.hc360.rsf.config.GlobalManager;
import com.hc360.rsf.registry.Provider;
import com.hc360.rsf.registry.RegistryFactory;
import com.hc360.rsf.registry.ServiceProviderIdelList;
import com.hc360.rsf.registry.ServiceProviderList;
import com.hc360.rsf.remoting.Channel;
import com.hc360.rsf.remoting.Client;
import com.hc360.rsf.remoting.RemotingException;
import com.hc360.rsf.rpc.EchoService;
import com.hc360.rsf.rpc.RpcException;
import com.hc360.rsf.rpc.RpcInvocation;
import com.hc360.rsf.rpc.loadbalance.LoadBalance;

/**
 * Invoker接口的实现
 * 
 * 作用:在客户端使用,客户端“发起调用”。
 * 
 * 扩展发父类RsfInvokerClientP2p的功能,
 * 
 * 本类添加了新的能力,可从注册中心下载服务列表,创建多个连接并选中其中 一个发起调用,实现了软负载。
 * 
 * @author zhaolei 2012-6-15
 */
public class RsfInvokerClientReg extends RsfInvokerClientP2p {
	
	//@modify
	private static final Logger logger = LoggerFactory.getLogger(RsfInvokerClientReg.class);
	private volatile boolean init = false;// 是否下载过服务列表  
	private ClientConfig clientConfig;

	/**
	 * 构造方法
	 * 
	 * @param serviceType
	 * @param url
	 */
	public RsfInvokerClientReg(Class serviceType, URL url) {
		super(serviceType,url);
	}
	public RsfInvokerClientReg(Class serviceType, URL url,ClientConfig clientConfig) {
		super(serviceType,url);
		this.clientConfig=clientConfig;
	}
	
	/**
	 * 重写了父类的方法,提供增加功能
	 * 从注册中心下载服务列表,连接多选 一,做软负载
	 * 
	 * @param invocation
	 * @return
	 * @see com.hc360.rsf.rpc.Invoker#invoke(com.hc360.rsf.rpc.RpcInvocation)
	 */
	protected Channel doInvoker(RpcInvocation invocation){
		String serviceName = getInterface().getName();//服务名
		if (!init) {
			synchronized (this) {
				if (!init) {
					//准备定时下载
					//不多余,Java编码方式(非XML方法)配置,需要以下这一行。
					GlobalManager.TIMER.appendClientConfig(clientConfig);
					
					List url_list=ServiceProviderList.findServiceList(serviceName);
					if(url_list==null || url_list.size()==0){
						url_list=RegistryFactory.download(clientConfig);//下载服务列表 ,并保存服务列表到ServiceProviderList
					}
					
					// 创建当前服务的所有连接
					// 这里也可以不创建,在发起调用时(下面),再创建,也可以
					Client client = GlobalManager.getClient();
					for(Provider url:url_list){
						try{
							client.getOrCreateChannel(url.getIp(),url.getPort());
						}catch(Exception e){
							//创建失败--忽略,以后由定时任务负责创建连接
						}
					}
					init = true;
				}
			}
		}
		//服务提供者列表,复制一个新的List,防修改
		List providerList = new CopyOnWriteArrayList(ServiceProviderList.findServiceList(serviceName));
		Channel channel =null;
		String path = invocation.getAttachments().get(Constants.PATH_KEY);// 接口名
		boolean bl=EchoService.class.getName().equals(path);
		
		if(!bl){
			//这是防御性代码(第一防线)
			if (providerList == null || providerList.size() == 0){
				//99.99%不会走入这里
				//无服务提供者列表,说明注册中心也没有。
				//从 “不可用--服务列表”中查找,做为一种补救措施
				//不可用服务 提供者列表,复制一个新的List,防修改
				providerList = new CopyOnWriteArrayList(ServiceProviderIdelList.findServiceList(serviceName));
				if(providerList!=null && providerList.size()>0){
					String message = "serviceName="+serviceName+",无法找到服务提供者,无法发出请求,可能是服务端没有启动或网络故障。";
					logger.error(message);
					String message2 = "但是从不可用服务提供者列表中找到"+providerList.size()+"个过时的服务提供者,将尝试性建立连接并发起调用:\r\n";
					for(int i=0;i urls,RpcInvocation invocation){
		if (urls == null || urls.size() == 0){
			return null;
		}
		
		
		URL url=getUrl();
		String loadBalance_name=url.getParameter(Constants.LOADBALANCE_KEY);
		// 取出软负载的实现方式 
		LoadBalance LoadBalance=GlobalManager.getLoadBalance(loadBalance_name);
		
		Provider url_select = LoadBalance.select(urls, invocation);
		Client client = GlobalManager.getClient();
		
		//从连接池中取连接,如果池中没有连接就新建连接
		Channel channel = null;
		try{
			channel=client.getOrCreateChannel(url_select.getIp(),url_select.getPort());		
		}catch(Exception e){
			logger.error("创建连接时异常",e);
		}
		urls.remove(url_select);
		while( (channel==null || !channel.isConnected()) &&  urls.size()>0 ){
			channel=failOver(urls,invocation);//连接不可用,转移到下一个
		}
		return channel;
	}
	
	/**
	 * 得到可能可用的channel
	 * 
	 * @param providers  服务提供者列表 (取决于isIdle的值,true 为不可用服务提供者列表   false 为可用服务提供者列表)
	 * @param invocation 调用的方法封装对象
	 * @param isIdle 决定是否是从不可用服务列表中恢复
	 * @return  channel(可能是连接的,也可能是非连接的) or null
	 */
	private Channel failOver(List providers,RpcInvocation invocation,boolean isIdle){
		//入参检验
		if (providers == null || providers.size() == 0){
			return null;
		}
		
		URL url=getUrl();
		String loadBalance_name=url.getParameter(Constants.LOADBALANCE_KEY);
		// 取出软负载的实现方式 
		LoadBalance loadBalance=GlobalManager.getLoadBalance(loadBalance_name);
		
		Channel channel = getChannel(loadBalance,providers,invocation,isIdle);
		
		logger.debug("经过failOver得到的channel:{}{}",channel,(channel==null?"":",连接状态是:"+(channel.isConnected()?true:false)));
		return channel;
	}
	
	/**
	 * 递归的去寻找可用的channel
	 * 
	 * @param loadBalance 服务节点选择器
	 * @param providers  服务节点集合
	 * @param invocation 调用的方法封装对象
	 * @param isIdle   决定是否是从不可用服务列表中恢复
	 * @return  channel(可能是连接的,也可能是非连接的) or null
	 */
	private Channel getChannel(LoadBalance loadBalance,List providers,RpcInvocation invocation,boolean isIdle){
		Channel channel = null;
		Client client = GlobalManager.getClient();
		Provider provider_select = loadBalance.select(providers, invocation);
		logger.debug("isIdle:{},provider_select:{}",isIdle,provider_select);
		//从连接池中取连接,如果池中没有连接就新建连接
		try{
			channel = client.getOrCreateChannel(provider_select.getIp(),provider_select.getPort());		
		}catch(Exception e){
			logger.error("创建连接时异常",e);
		}
		
		boolean contain = false;
		//处理完一个服务提供者节点,将它移除
		providers.remove(provider_select);
		if(channel != null && channel.isConnected()){
			//从可用服务列表取的时候,直接返回channel
			if(!isIdle){
				return channel;
			}
			
			//做回声方式是否存在的测试
			try {
				contain = channel.isContainService(provider_select.getServiceName());
				if(contain){
					//将从不可用列表中找到的可用提供者恢复到可用列表中,并从不可用列表中移除
					ServiceProviderList.addNode(provider_select);
					ServiceProviderIdelList.romveNode(provider_select);
					logger.info("{}从ServiceProviderIdelList恢复到ServiceProviderList里。",provider_select);
					return channel;
				}
			} catch (RemotingException e) {
		        logger.error(MessageFormat.format("{0}回声测试{1}出现异常",channel,provider_select.getServiceName()),e);
			}
		}
		
		//这个节点不能用,进行下个节点的尝试
		while(providers.size()>0){
			channel = getChannel(loadBalance,providers,invocation,isIdle);
		}
		
		//防止得到与其他系统的连接 
		if(isIdle&&channel!=null&&channel.isConnected()&&!contain){
			logger.debug("可用列表没有提供者,从不可用列表中寻找,但一样没有找到,将channel设置为空");
			channel = null; 
		}
		return channel;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy