服务提供者启动成功后,启动消费者时报错:
com.alibaba.dubbo.registry.integration.RegistryDirectory - [DUBBO] Failed to refer invoker for interface
You must use at least one, but no more than one http method annotation on:
at org.jboss.resteasy.client.jaxrs.ProxyBuilder.createClientInvoker(ProxyBuilder.java:76) ~[resteasy-client-3.0.7.Final.jar:?]
at org.jboss.resteasy.client.jaxrs.ProxyBuilder.proxy(ProxyBuilder.java:52) ~[resteasy-client-3.0.7.Final.jar:?]
at org.jboss.resteasy.client.jaxrs.ProxyBuilder.build(ProxyBuilder.java:120) ~[resteasy-client-3.0.7.Final.jar:?]
at org.jboss.resteasy.client.jaxrs.internal.ClientWebTarget.proxy(ClientWebTarget.java:72) ~[resteasy-client-3.0.7.Final.jar:?]
at com.alibaba.dubbo.rpc.protocol.rest.RestProtocol.doRefer(RestProtocol.java:161) ~[dubbo-2.8.3.jar:2.8.3]
at com.alibaba.dubbo.rpc.protocol.AbstractProxyProtocol.refer(AbstractProxyProtocol.java:88) ~[dubbo-2.8.3.jar:2.8.3]
at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper.refer(ProtocolFilterWrapper.java:62) ~[dubbo-2.8.3.jar:2.8.3]
at com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper.refer(ProtocolListenerWrapper.java:65) ~[dubbo-2.8.3.jar:2.8.3]
at com.alibaba.dubbo.rpc.Protocol$Adpative.refer(Protocol$Adpative.java) ~[dubbo-2.8.3.jar:2.8.3]
at com.alibaba.dubbo.registry.integration.RegistryDirectory.toInvokers(RegistryDirectory.java:395) [dubbo-2.8.3.jar:2.8.3]
at com.alibaba.dubbo.registry.integration.RegistryDirectory.refreshInvoker(RegistryDirectory.java:224) [dubbo-2.8.3.jar:2.8.3]
at com.alibaba.dubbo.registry.integration.RegistryDirectory.notify(RegistryDirectory.java:195) [dubbo-2.8.3.jar:2.8.3]
at com.alibaba.dubbo.registry.support.AbstractRegistry.notify(AbstractRegistry.java:449) [dubbo-2.8.3.jar:2.8.3]
进入源码中查看ProxyBuilder.createClientInvoker的前后执行代码,调用这个方法是ProxyBuilder.proxy(final Class<T> iface, WebTarget base, final ProxyConfig config),iface是被代理的接口
public static <T> T proxy(final Class<T> iface, WebTarget base, final ProxyConfig config)
{
if (iface.isAnnotationPresent(Path.class))
{
Path path = iface.getAnnotation(Path.class);
if (!path.value().equals("") && !path.value().equals("/"))
{
base = base.path(path.value());
}
}
HashMap<Method, MethodInvoker> methodMap = new HashMap<Method, MethodInvoker>();
for (Method method : iface.getMethods())
{
MethodInvoker invoker;
Set<String> httpMethods = IsHttpMethod.getHttpMethods(method);
if ((httpMethods == null || httpMethods.size() == 0) && method.isAnnotationPresent(Path.class) && method.getReturnType().isInterface())
{
invoker = new SubResourceInvoker((ResteasyWebTarget)base, method, config);
}
else
{
invoker = createClientInvoker(iface, method, (ResteasyWebTarget)base, config);
}
methodMap.put(method, invoker);
}
Class<?>[] intfs =
{
iface
};
ClientProxy clientProxy = new ClientProxy(methodMap);
// this is done so that equals and hashCode work ok. Adding the proxy to a
// Collection will cause equals and hashCode to be invoked. The Spring
// infrastructure had some problems without this.
clientProxy.setClazz(iface);
return (T) Proxy.newProxyInstance(config.getLoader(), intfs, clientProxy);
}
该方法中的条件method.isAnnotationPresent(Path.class)判断方法上是否有@Path注解,由于代码中@Path及相关注解都是在实现类和实现类的方法中,获取不到返回false进入createClientInvoker方法:
private static <T> ClientInvoker createClientInvoker(Class<T> clazz, Method method, ResteasyWebTarget base, ProxyConfig config)
{
Set<String> httpMethods = IsHttpMethod.getHttpMethods(method);
if (httpMethods == null || httpMethods.size() != 1)
{
throw new RuntimeException("You must use at least one, but no more than one http method annotation on: " + method.toString());
}
ClientInvoker invoker = new ClientInvoker(base, clazz, method, config);
invoker.setHttpMethod(httpMethods.iterator().next());
return invoker;
}
而IsHttpMethod.getHttpMethods(method)首先要从方法上获取注解,getHttpMethods方法代码如下:
public static Set<String> getHttpMethods(Method method)
{
HashSet<String> methods = new HashSet<String>();
for (Annotation annotation : method.getAnnotations())
{
HttpMethod http = annotation.annotationType().getAnnotation(HttpMethod.class);
if (http != null) methods.add(http.value());
}
if (methods.size() == 0) return null;
return methods;
}
但是手上的项目中,该类上仅有两个方法上添加了@Path、@Post、@Produces等注解,且该类为实现类,编译打包后proxy接口时找不到注解,问题找到了。
问题解决:将该类上的@Path、@Post、@Produces等注解转移到接口上,并给该接口其他没有注解的方法上也全部加上@Path和@Post、@Get等注解后问题解决