dubbo系列--本地服务发布源码分析

先来看我们的provider.xml的配置文件


这个文件的重要性肯定重要,那么这些标签是怎么来的呢?

其实就是spring自定义标签来的,在源码中我们可以看到,


继续看spring.handlers文件中内容


可以看得出这个DubboNamespaceHandler应该很重要,最后可以找出他的所在位置,同时还发现同目录下还有DubboBeanDefinitionParser类似于spring中BeanDefinitionParser。DubboNamespaceHandler类似于spring中NamespaceHandler:


再进去看看里面到底做了些什么东东



可以看到

DubboBeanDefinitionParser继承spring的BeanDefinitionParser,DubboNamespaceHandlerSupport继承spring的NamespaceHandlerSupport,NamespaceHandlerSupport继承NamespaceHandler。由此可以知道这个provider.xml配置文件的解析其实就是和spring一样解析。


 在这个spring目录下我们看到这两个类


这两个类非常重要:

ServiceBean服务端发布入口

ReferenceBean客户端发布入口

先看看服务端的服务是怎么发布的


他是实现spring的这几类来做的。所以还是基于spring来做的

这个类中afterPropertiesSet()方法中。是否延迟加载


export()方法就是做了一些参数校验


不管是否延迟加载都会走doExport()方法,doExport()方法也是做一些参数校验
和配置项的校验


然后调用doExportUrls()



就是在provider.xml中配置多个protocol


doExportUrlsFor1Protocol中
1:使用各种方法获取本地ip
2:如果没有配置端口则
final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();

 获取默认端口dubbo默认20880


3:拼凑url

dubbo://192.168.11.1:20880/com.tian.dubbo.IGpHello?anyhost=true&application=hello-world-app&default.delay=10&delay=10&dubbo=2.5.6&generic=false&interface=com.tian.dubbo.IGpHello&methods=sayHello&pid=121964&side=provider×tamp=1529758790987

然后


debug到此


这里有个Invoker对象为




所以我们可以把Invoker对象理解为服务的代理对象。

如果没有配置注册中心,

protocol

----->Protocol$Adaptive

---->ProtocolFilterWrapper(ProtocolListenerWrapper(DubboProtocol))。底层是基于netty协议去启动一个nettyserver

} else {//如果没有配置注册中心
    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
    Exporter<?> exporter = protocol.export(invoker);//dubbo
    exporters.add(exporter);
}

Protocol extension = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(“registry”);


registry=com.alibaba.dubbo.registry.integration.RegistryProtocol

protocol=RegistryProtocol

RegistryProtocol的export方法源码


 doLocalExport()本地发布


对缓存进行双重检查锁,如果有就直接返回,否则new一个

debug到此,相关属性对应的值:


exporter相关属性


此时相关值


上面


同样根据

Protocol extension =ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(“dubbo”);

protocol=DubboProtocol.这里并不是获得一个单纯的DubboProtocol扩展点,而是会通过Wrapper对Protocol进行装饰,装饰器分别为: ProtocolFilterWrapper/ ProtocolListenerWrapper;两个装饰类的源码为以下:


ProtocolFilterWrapper

这个类非常重要,dubbo机制里面日志记录、超时等等功能都是在这一部分实现的

这个类有3个特点,

第一它有一个参数为Protocol protocol的构造函数;

第二,它实现了Protocol接口;

第三,它使用责任链模式,对export和refer函数进行了封装;部分代码如下,上面的源码中ProtocolFilterWrapper有个buildInvokderChain()方法

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
        return protocol.export(invoker);
    }
    return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}
public void destroy() {
    protocol.destroy();
}

//buildInvokerChain函数:它读取所有的filter类,利用这些类封装invoker
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
    Invoker<T> last = invoker;
    List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);//自动激活扩展点,根据条件获取当前扩展可自动激活的实现
    if (filters.size() > 0) {
        for (int i = filters.size() - 1; i >= 0; i --) {
            final Filter filter = filters.get(i);
            final Invoker<T> next = last;
            last = new Invoker<T>() {
                public Class<T> getInterface() {
                    return invoker.getInterface();
                }
                public URL getUrl() {
                    return invoker.getUrl();
                }
                public boolean isAvailable() {
                    return invoker.isAvailable();
                }
                public Result invoke(Invocation invocation) throws RpcException {
                    return filter.invoke(next, invocation);
                }
                public void destroy() {
                    invoker.destroy();
                }
                @Override
                public String toString() {
                    return invoker.toString();
                }
            };
        }
    }
    return last;
}

 

我们看如下文件:

 /dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Filter

其实就是对Invoker,通过如下的Filter组装成一个责任链

echo=com.alibaba.dubbo.rpc.filter.EchoFilter
generic=com.alibaba.dubbo.rpc.filter.GenericFilter
genericimpl=com.alibaba.dubbo.rpc.filter.GenericImplFilter
token=com.alibaba.dubbo.rpc.filter.TokenFilter
accesslog=com.alibaba.dubbo.rpc.filter.AccessLogFilter
activelimit=com.alibaba.dubbo.rpc.filter.ActiveLimitFilter
classloader=com.alibaba.dubbo.rpc.filter.ClassLoaderFilter
context=com.alibaba.dubbo.rpc.filter.ContextFilter
consumercontext=com.alibaba.dubbo.rpc.filter.ConsumerContextFilter
exception=com.alibaba.dubbo.rpc.filter.ExceptionFilter
executelimit=com.alibaba.dubbo.rpc.filter.ExecuteLimitFilter
deprecated=com.alibaba.dubbo.rpc.filter.DeprecatedFilter
compatible=com.alibaba.dubbo.rpc.filter.CompatibleFilter
timeout=com.alibaba.dubbo.rpc.filter.TimeoutFilter

这其中涉及到很多功能,包括权限验证、异常、超时等等,当然可以预计计算调用时间等等应该也是在这其中的某个类实现的;这里其实就是dubbo中AOP

这里我们可以看到export和refer过程都会被filter过滤


ProtocolListenerWrapper

在这里我们可以看到export和refer分别对应了不同的Wrapper;export是对应的ListenerExporterWrapper。这块暂时先不去分析,因为这个地方并没有提供实现类。

debug到此


exporterMap




createServer方法()


Exchangers.bind()方法


这里使用的是getExchange(url)=默认自适应扩展类HeaderExchanger


这里先去Transporters.bind()方法,


getTransporter().bind(url, handler);


这里的自适应扩展类就是默认的netty的


构造一个NettyServer


继续调用父类的方法


这个open()方法在这个父类里并没有实现,而是采用模板方法模式,由各自实现类自己去实现


到此本地发布已经结束。


上一篇:Java设计模式——命令模式


下一篇:java命令模式的缺点