dubbo广播模式的坑

dubbo集群广播模式的坑

场景:消费者需要依次调用某个服务的所有实例,当某个实例报错则消费者能得到异常信息。
dubbo官网的介绍如下:
https://dubbo.gitbooks.io/dubbo-user-book/content/demos/fault-tolerent-strategy.html

Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。
于是乎,看代码:
消费者端:

@RestController
public class UserController {
    @Reference(cluster="broadcast")
    private UserService us;
    @RequestMapping("/")
    public String index() {
        String s = null;
        try {
            s = us.getName();
        } catch (Exception e) {
            System.out.println("客户端开始报错了");
            e.printStackTrace();
        }
        return s;
    }
}

服务1:

@Service(cluster="broadcast")
public class UserServerImpl implements UserService{
    public String getName() throws Exception {
        System.out.println("UserService.getName1...");
        int i = 1/0;
        return "UserService.getName1...";
    }
}

服务2:

@Service(cluster="broadcast")
public class UserServerImpl implements UserService{
    public String getName() {
        System.out.println("UserService.getName2...");
        return "UserService.getName2...";
    }
}

启动2个服务,接着启动消费者,调用UserController接口,效果为依次调用了2个服务的getName()方法。
但是,调用了n遍,服务1报错,服务2正常,消费端却没有得到异常信息,这并不是我们想要的结果,因为,某个服务异常,我们需要消费端得到通知并做相应的处理。
于是乎,在消费端debug,进入dubbo源码分析,层层进入,最终到达
com.alibaba.dubbo.rpc.protocol.AbstractProxyProtocol这个类的refer()方法:

public  Invoker refer(final Class type, final URL url) throws RpcException {
        final Invoker tagert = proxyFactory.getInvoker(doRefer(type, url), type, url);
        Invoker invoker = new AbstractInvoker(type, url) {
            @Override
            protected Result doInvoke(Invocation invocation) throws Throwable {
                try {
                    Result result = tagert.invoke(invocation);
                    Throwable e = result.getException();
                    if (e != null) {
                        for (Class rpcException : rpcExceptions) {
                            if (rpcException.isAssignableFrom(e.getClass())) {
                                throw getRpcException(type, url, invocation, e);
                            }
                        }
                    }
                    return result;
                } catch (RpcException e) {
                    if (e.getCode() == RpcException.UNKNOWN_EXCEPTION) {
                        e.setCode(getErrorCode(e.getCause()));
                    }
                    throw e;
                } catch (Throwable e) {
                    throw getRpcException(type, url, invocation, e);
                }
            }
        };
        invokers.add(invoker);
        return invoker;

请看第9行,debug的结果表明,e就是服务1抛出的异常。
但是,程序并没有走到throw getRpcException(type, url, invocation, e);这一步。
再看rpcExceptions的值:
这里写图片描述
org.springframework.remoting.RemoteAccessException
java.rmi.RemoteException
而e.getClass()为:java.lang.ArithmeticException,所以该异常并不会抛给消费者。
解决方法:
服务1抛出的异常封装为RemoteAccessException或者RemoteException。

@Service(cluster="broadcast")
public class UserServerImpl implements UserService{
    public String getName() throws RemoteException {
        try {
            System.out.println("UserService.getName1...");
            int i = 1/0;
        }catch (Exception e) {
            throw new RemoteException(e.getMessage(),e);
        }
        return "UserService.getName1...";
    }
}

此时,服务1抛异常,消费者能接收到了。
over

你可能感兴趣的:(dubbo,java,分布式,dubbo,java,分布式)