导言
SpringCloud大家初次使用的时候,都有一个疑惑,官网推崇的是restful,但RPC该如何支持?本文旨在为大家提供一个思路,至于如何集成到大家自己的框架中还需要各自针对自己的情况好好思考。
思路
我们拿基于spring包装的hessian框架举例。构造HessianProxyFactoryBean对象时,原生是需要传入url,这里我们改成传入调用的服务名称和服务暴露的路径。扩展HessianClientInterceptor的invoke代码,原先获取hessianProxy的代码改为根据ribbon拿到的url缓存的hessianProxy,如果不存在则创建并加入缓存中。其他功能不变,即可实现hessian对eureka的支持。
关键代码
- 继承HessianClientInterceptor,覆盖invoke方法
HessianClientInterceptor中invoke的代码为:
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
if (this.hessianProxy == null) {
throw new IllegalStateException("HessianClientInterceptor is not properly initialized - " +
"invoke 'prepare' before attempting any operations");
}
ClassLoader originalClassLoader = overrideThreadContextClassLoader();
try {
return invocation.getMethod().invoke(this.hessianProxy, invocation.getArguments());
}
catch (InvocationTargetException ex) {
...
}
扩展代码为:
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object hessianProxy = null;
String url = null;
try {
url = this.getServiceUrl();
hessianProxy = hessianProxyMap.get(url);
if (hessianProxy == null) {
hessianProxy = proxyFactory.create(getServiceInterface(), url, getBeanClassLoader());
hessianProxyMap.put(url, hessianProxy);
}
} catch (MalformedURLException ex) {
throw new RemoteLookupFailureException("Service URL [" + url + "] is invalid", ex);
}
if (hessianProxy == null) {
throw new IllegalStateException("HessianProxy init fail, service url : " + url);
}
ClassLoader originalClassLoader = overrideThreadContextClassLoader();
try {
return invocation.getMethod().invoke(hessianProxy, invocation.getArguments());
} catch (InvocationTargetException ex) {
...
}
- 调用Ribbon API获取服务url, 注意如果应用有contextpath,可以利用eureka的metaData进行保存,即app配置euraka的配置中增加metadata的配置。
@Autowired
private LoadBalancerClient loadBalancer;
@Override
public String selectUrl(String serviceName) throws NoServiceUrlFoundException {
ServiceInstance serviceInstance = loadBalancer.choose(serviceName);
if (serviceInstance == null) {
throw new NoServiceUrlFoundException("No valid serviceUrl find from RegServer by serviceName: " + serviceName);
}
StringBuffer sb = new StringBuffer(serviceInstance.getUri().toString());
if (serviceInstance.getMetadata() != null && serviceInstance.getMetadata().containsKey(KEY_CONTEXT_PATH) &&
StringUtils.isNotEmpty(serviceInstance.getMetadata().get(KEY_CONTEXT_PATH))) {
String contextPath = serviceInstance.getMetadata().get(KEY_CONTEXT_PATH);
if (!contextPath.startsWith("/")) {
sb.append("/");
}
sb.append(contextPath);
}
return sb.toString();
}