在第一章中,我们分析了服务的发布与注册,本章中将简单的分析一下客户端调用服务的代码及流程,本文将以spring加载的方式进行分析。
1.在DemoRpcClient类的main()方法中加载类:
ApplicationContext ctx = new ClassPathXmlApplicationContext( new String[]{ "classpath:motan_demo_client.xml" });
MotanDemoService service = (MotanDemoService) ctx.getBean( "motanDemoReferer" );
2.上面加载了spring的配置文件motan_demo_client.xml
<motan:registry regProtocol="zookeeper" name="registry" address="127.0.0.1:2181" connectTimeout="2000"/>
<!-- motan协议配置 -->
<motan:protocol default="true" name="motan" haStrategy="failover"loadbalance="roundrobin" maxClientConnection="10" minClientConnection="2"/>
<!-- 通用referer基础配置 -->
<motan:basicReferer requestTimeout="200" accessLog="false"retries="2" group="motan-demo-rpc" module="motan-demo-rpc"application="myMotanDemo" protocol="motan" registry="registry"id="motantestClientBasicConfig" throwException="false" check="true"/>
<!-- 具体referer配置。使用方通过beanid使用服务接口类 -->
<motan:referer id="motanDemoReferer"
interface="com.weibo.motan.demo.service.MotanDemoService"connectTimeout="300" requestTimeout="300" basicReferer="motantestClientBasicConfig"/>
经过spring装载RefererConfig后,每次向spring框架getBean时会调用RefererConfig的getRef()方法
3.获取接口MotanDemoService的实现类代码如下:
publicObject getRef()
{
if(ref == null)
initRef();//初始化
returnref;
}
public synchronized voidinitRef()
{
if(initialized.get())
return;
try{
interfaceClass = Class.forName(interfaceClass.getName(), true, Thread.currentThread().getContextClassLoader());
}
catch(ClassNotFoundException e)
{
throw new MotanFrameworkException((new StringBuilder("ReferereConfig initRef Error: Class not found ")).append(interfaceClass.getName()).toString(), e, MotanErrorMsgConstant.FRAMEWORK_INIT_ERROR);
}
if(CollectionUtil.isEmpty(protocols))//protocol配置是否为空
throw new MotanFrameworkException(String.format("%s RefererConfig is malformed, for protocol not set correctly!", newObject[] {
interfaceClass.getName()
}));
checkInterfaceAndMethods(interfaceClass, methods);
clusterSupports = newArrayList(protocols.size());//初始化集群支持类列表,可以支持多个
List clusters = newArrayList(protocols.size());//初始化集群类列表,可以支持多个
String proxy = null;
ConfigHandler configHandler = (ConfigHandler)ExtensionLoader.getExtensionLoader(com/weibo/api/motan/config/handler/ConfigHandler).getExtension("default");//加载SimpleConfigHandler
List registryUrls =loadRegistryUrls();//加载注册中心url列表,可以支持多个注册中心
String localIp =getLocalHostAddress(registryUrls);
for(Iterator iterator =protocols.iterator(); iterator.hasNext();)
{
ProtocolConfig protocol =(ProtocolConfig)iterator.next();
LoggerUtil.info((new StringBuilder("ProtocolConfig's")).append(protocol.getName()).toString());
Map params = newHashMap();
params.put(URLParamType.nodeType.getName(), "referer");
params.put(URLParamType.version.getName(), URLParamType.version.getValue());
params.put(URLParamType.refreshTimestamp.getName(), String.valueOf(System.currentTimeMillis()));
collectConfigParams(params, newAbstractConfig[] {
protocol, basicReferer, extConfig, this});
collectMethodConfigParams(params, getMethods());
URL refUrl = new URL(protocol.getName(), localIp, 0, interfaceClass.getName(), params);
ClusterSupport clusterSupport =createClusterSupport(refUrl, configHandler, registryUrls);
clusterSupports.add(clusterSupport);
clusters.add(clusterSupport.getCluster());
proxy = proxy != null ?proxy : refUrl.getParameter(URLParamType.proxy.getName(), URLParamType.proxy.getValue());
}
ref =configHandler.refer(interfaceClass, clusters, proxy);//调用SimpleConfigHandler的refer方法获取接口实现类
initialized.set(true);
}
4.下面我们来看一下SimpleConfigHandler的refer方法的代理实现,使用了jdk的动态代理技术
public <T> T refer(Class<T> interfaceClass, List<Cluster<T>> clusters, String proxyType) {
ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory. class ).getExtension(proxyType); //创建代理工厂
return proxyFactory.getProxy(interfaceClass, new RefererInvocationHandler<T>(interfaceClass, clusters)); //获取代理类
}
public class JdkProxyFactory implements ProxyFactory {
@SuppressWarnings ( "unchecked" )
public <T> T getProxy(Class<T> clz, InvocationHandler invocationHandler) {
return (T) Proxy.newProxyInstance( this .getClass().getClassLoader(), new Class[] {clz}, invocationHandler); //使用jdk的动态代理,实际调用的代码是下面的的invoke方法
}
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
DefaultRequest request = new DefaultRequest(); //封装通信用的request,request和response是在客户端和服务端通信的两个对象
request.setRequestId(RequestIdGenerator.getRequestId());
request.setArguments(args);
request.setMethodName(method.getName());
request.setParamtersDesc(ReflectUtil.getMethodParamDesc(method));
request.setInterfaceName(clz.getName());
request.setAttachment(URLParamType.requestIdFromClient.getName(), String.valueOf(RequestIdGenerator.getRequestIdFromClient()));
// 当 referer配置多个protocol的时候,比如A,B,C,
// 那么正常情况下只会使用A,如果A被开关降级,那么就会使用B,B也被降级,那么会使用C
for (Cluster<T> cluster : clusters) { //motan支持多个protocol的配置,也就是支持多个cluster,但是默认情况下只取第一个,如果前面的被降级,则取下一个
String protocolSwitcher = MotanConstants.PROTOCOL_SWITCHER_PREFIX + cluster.getUrl().getProtocol();
Switcher switcher = switcherService.getSwitcher(protocolSwitcher);
if (switcher != null && !switcher.isOn()) {
continue ;
}
List<Referer<T>> referL = cluster.getReferers(); //此段代码为我单独添加的,目的是证明客户端在配置多个注册中心的情况下,cluster可以支持跨注册中心的调用
for (Referer<T> refer : referL){
LoggerUtil.info(refer.getServiceUrl().getUri()+refer.getServiceUrl().getPath());
}
request.setAttachment(URLParamType.version.getName(), cluster.getUrl().getVersion());
request.setAttachment(URLParamType.clientGroup.getName(), cluster.getUrl().getGroup());
// 带上client的application和module
request.setAttachment(URLParamType.application.getName(), ApplicationInfo.getApplication(cluster.getUrl()).getApplication());
request.setAttachment(URLParamType.module.getName(), ApplicationInfo.getApplication(cluster.getUrl()).getModule());
Response response = null ;
boolean throwException =
Boolean.parseBoolean(cluster.getUrl().getParameter(URLParamType.throwException.getName(),
URLParamType.throwException.getValue()));
try {
response = cluster.call(request); //调用cluster的call方法
return response.getValue(); //获取返回信息
} catch (RuntimeException e) {
if (ExceptionUtil.isBizException(e)) {
Throwable t = e.getCause();
// 只抛出Exception,防止抛出远程的Error
if (t != null && t instanceof Exception) {
throw t;
} else {
String msg =
t == null ? "biz exception cause is null" : ( "biz exception cause is throwable error:" + t.getClass()
+ ", errmsg:" + t.getMessage());
throw new MotanServiceException(msg, MotanErrorMsgConstant.SERVICE_DEFAULT_ERROR);
}
} else if (!throwException) {
LoggerUtil.warn( "RefererInvocationHandler invoke false, so return default value: uri=" + cluster.getUrl().getUri()
+ " " + MotanFrameworkUtil.toString(request), e);
return getDefaultReturnValue(method.getReturnType());
} else {
LoggerUtil.error(
"RefererInvocationHandler invoke Error: uri=" + cluster.getUrl().getUri() + " "
+ MotanFrameworkUtil.toString(request), e);
throw e;
}
}
}
throw new MotanServiceException( "Referer call Error: cluster not exist, interface=" + clz.getName() + " "
+ MotanFrameworkUtil.toString(request), MotanErrorMsgConstant.SERVICE_UNFOUND);
}
本章知识点总结:
1.客户端在获取业务接口的实现类时,使用了jdk的动态代理技术;
2.客户端可以支持多个注册中心;
3.客户端可以支持多个cluster,但是只取最前面有效那个;
4.使用request和response对象进行信息的传递。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/a1439226817/article/details/68483444
内容来源于网络,如有侵权,请联系作者删除!