您的位置:首页 > 其它

dubbo学习七--参数回调,本地存根,延迟暴露,并发控制

2017-01-03 13:43 260 查看
参数回调

参数回调方式与调用本地callback或Listener相同,只需要在Spring的配置文件中声明哪个参数是callback类型即可,dubbo将基于长连接生成反向代理,这样就可以从服务器端调用客户端逻辑。

(1)共享服务接口

服务接口示例:
CallbackService.java
package com.callback;
 
public interface CallbackService {
    void addListener(String key, CallbackListener listener);
}
CallbackListener.java
package com.callback;
 
public interface CallbackListener {
    void changed(String msg);
}
(2)服务提供者

CallbackServiceImpl.java
package com.callback.impl;
 
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
import com.callback.CallbackListener;
import com.callback.CallbackService;
 
public class CallbackServiceImpl implements CallbackService {
     
    private final Map<String, CallbackListener> listeners = new ConcurrentHashMap<String, CallbackListener>();
  
    public CallbackServiceImpl() {
        Thread t = new Thread(new Runnable() {
            public void run() {
                while(true) {
                    try {
                        for(Map.Entry<String, CallbackListener> entry : listeners.entrySet()){
                           try {
                               entry.getValue().changed(getChanged(entry.getKey()));
                           } catch (Throwable t) {
                               listeners.remove(entry.getKey());
                           }
                        }
                        Thread.sleep(5000); // 定时触发变更通知
                    } catch (Throwable t) { // 防御容错
                        t.printStackTrace();
                    }
                }
            }
        });
        t.setDaemon(true);
        t.start();
    }
  
    public void addListener(String key, CallbackListener listener) {
        listeners.put(key, listener);
        listener.changed(getChanged(key)); // 发送变更通知
    }
     
    private String getChanged(String key) {
        return "Changed: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    }
 
}
本地存根

远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有时候想在客户端也执行部分逻辑,此进需要在API中带上Stub,客户端生成Proxy,把Proxy通过构造函数传递给Stub,然后把Stub暴露给用户,Stub可以决定要不要去调用 Proxy。



<dubbo:service interface="com.foo.BarService" stub="true" />
Or:
<dubbo:service interface="com.foo.BarService" stub="com.foo.BarServiceStub" />
api.jar:
com.foo.BarService
com.foo.BarServiceStub // 在API旁边放一个Stub实现,它实现BarService接口,并有一个传入远程BarService实例的构造函数
package com.foo
public class BarServiceStub implements BarService {
 
    private final BarService barService;
 
    // 构造函数传入真正的远程代理对象
    public (BarService barService) {
        this.barService = barService;
    }
 
    public String sayHello(String name) {
        // 此代码在客户端执行
        // 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等
        try {
            return barService.sayHello(name);
        } catch (Exception e) {
            // 你可以容错,可以做任何AOP拦截事项
            return "容错数据";
        }
    }
}
本地伪装

Mock通常用于服务降级,比如某难权服务,当服务提供方全部挂掉后,客户端不抛出异常,而是通过Mock数据返回授权失败。

Mock是Stub的一个子集,便于服务提供方在客户端执行容错逻辑,因经常需要出现RpcException时进行容错,而在出现业务异常时不需要容错,如果用Stub,可能就需要捕获并依赖RpcException类。而用Mock就可以不依赖RpcException,因为它的约定就是只有出现RpcException时才执行。

<dubbo:service interface="com.foo.BarService" mock="true" />
Or:
<dubbo:service interface="com.foo.BarService" mock="com.foo.BarServiceMock" />
api.jar:
com.foo.BarService
com.foo.BarServiceMock // 在API旁边放一个Mock实现,它实现BarService接口,并有一个无参构造函数
package com.foo
public class BarServiceMock implements BarService {
 
    public String sayHello(String name) {
        // 你可以伪造容错数据,此方法只在出现RpcException时被执行
        return "容错数据";
    }
}
如果服务的消费方经常需要try-catch捕获异常,如:
Offer offer = null;
try {
    offer = offerService.findOffer(offerId);
} catch (RpcException e) {
   logger.error(e);
}
请考虑改为Mock实现,并在Mock中return null。
如果只是想简单的忽略异常,在2.0.11以上版本可用:
<dubbo:service interface="com.foo.BarService" mock="return null" />
延迟暴露

如果你的服务warmup时间,比如初始化缓存,等待相关资源就位等,可以使用delay进行延迟暴露。

<dubbo:servicedelay="5000"/>

并发控制

限制com.foo.BarService的每个方法,服务器端并发执行(或占用线程池线程数)不能超过10个:
<dubbo:service interface="com.foo.BarService" executes="10" />
限制com.foo.BarService的sayHello方法,服务器端并发执行(或占用线程池线程数)不能超过10个:
<dubbo:service interface="com.foo.BarService">
    <dubbo:method name="sayHello" executes="10" />
</dubbo:service>
限制com.foo.BarService的每个方法,每客户端并发执行(或占用连接的请求数)不能超过10个:
<dubbo:service interface="com.foo.BarService" actives="10" />
Or:
<dubbo:reference interface="com.foo.BarService" actives="10" />
限制com.foo.BarService的sayHello方法,每客户端并发执行(或占用连接的请求数)不能超过10个:
<dubbo:service interface="com.foo.BarService">
    <dubbo:method name="sayHello" actives="10" />
</dubbo:service>
Or:
<dubbo:reference interface="com.foo.BarService">
    <dubbo:method name="sayHello" actives="10" />
</dubbo:service>
如果<dubbo:service>和<dubbo:reference>都配了actives,<dubbo:reference>优先
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: