TOP

dubbo中Listener的实现(一)
2017-10-13 09:55:07 】 浏览:10060
Tags:dubbo Listener 实现

这里继续dubbo的源码旅程,在过程中学习它的设计和技巧,看优秀的代码,我想对我们日程编码必然有帮助的。而那些开源的代码正是千锤百炼的东西,希望和各位共勉。

拿ProtocolListenerWrapper为例子,看源码的时候发现它是一个装饰类的标准实现有一个自身的复制构造函数,把被包装者复制进来,然后结合装饰部分的操作。看下ProtocolListenerWrapper类有这样的代码:

public class ProtocolListenerWrapper implements Protocol {

    private final Protocol protocol;

    public ProtocolListenerWrapper(Protocol protocol){
        if (protocol == null) {
            throw new IllegalArgumentException("protocol == null");
        }
        this.protocol = protocol;
    }

    public int getDefaultPort() {
        return protocol.getDefaultPort();
    }

    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
            return protocol.export(invoker);
        }
        return new ListenerExporterWrapper<T>(protocol.export(invoker),
                Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
                        .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
    }

    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
            return protocol.refer(type, url);
        }
        return new ListenerInvokerWrapper<T>(protocol.refer(type, url),
                Collections.unmodifiableList(
                        ExtensionLoader.getExtensionLoader(InvokerListener.class)
                        .getActivateExtension(url, Constants.INVOKER_LISTENER_KEY)));
    }

    public void destroy() {
        protocol.destroy();
    }

}
而我们在ExtensionLoader里找到了这份代码片段clazz.getConstructor()方法就是去匹配前面提到的装饰模式用到的方式。
而这些类作为插件会被放入cachedWrapperClasses进行缓存。而对这个缓存的使用就是解开listenter调用实现的钥匙。
try {
    clazz.getConstructor(type);
    Set<Class<?>> wrappers = cachedWrapperClasses;
    if (wrappers == null) {
        cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
        wrappers = cachedWrapperClasses;
    }
    wrappers.add(clazz);
} catch (NoSuchMethodException e) {

上面也可以看到用异常作为一个判断逻辑。

ExtensionLoader中getExtension(String name)方法中会调用createExtension(String name)这个方法中将cachedWrapperClasses利用了起来,具体实现就是将被装饰类实例作为参数调用warpper类的自身复制构造函数,这样就会把被装饰累包装起来,从而达到,当有调用被装饰类的方法是就可以执行到warpper中的逻辑代码了,实现都是调用了clazz.getConstructor方法,代码片段:

Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && wrapperClasses.size() > 0) {
    for (Class<?> wrapperClass : wrapperClasses) {
        instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
    }
}
再回去看一下ProtocolListenerWrapper,我们可以发现继承Protocol中的export方法是对外开放service的入口方法,它返回exporter,代码中实际是返回了ListenerExporterWrapper,这也是个装饰类,不过没有使用上面提到的机制,只是把exporter和listener进行类包装,在构造函数里将listener执行。至此我们终于找到了执行listener的代码。
在dubbo的开发中listener是及其重要的一个扩展口子,在服务对外时执行一些自己想做的事情就些各类继承ExporterListener
在引用服务的时候想做些自己的事就写个类继承InvokerListener。
 
另外,ExporterListener为例,发现他的子类中有一个ExporterListenerAdapter,两个空方法,代码:
public abstract class ExporterListenerAdapter implements ExporterListener {

    public void exported(Exporter<?> exporter) throws RpcException {
    }

    public void unexported(Exporter<?> exporter) throws RpcException {
    }

}

这是个技巧吧,刚刚上面提到自己要写扩展类的时候就不直接继承
dubbo中Listener的实现(一) https://www.cppentry.com/bencandy.php?fid=76&id=156144

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇dubbo中Listener的实现 下一篇java冒泡排序的思想及代码实现