dubbo分析-export一个服务

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/taotoxht/article/details/79879874

export一个service

我们先看下export 一个service 的具体代码:

// 服务实现
HellowService hellowService = new HellowServiceImpl();

// 应用配置
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("test");

// 连接注册中心配置
RegistryConfig registry = new RegistryConfig();
registry.setAddress("zookeeper://192.168.41.77:2181");

// 服务提供者协议配置
ProtocolConfig protocol = new ProtocolConfig();
protocol.setName("dubbo");
protocol.setPort(12345);
protocol.setThreads(200);

// 服务提供者暴露服务配置
ServiceConfig<HellowService> service = new ServiceConfig<HellowService>(); // 此实例很重,封装了与注册中心的连接,请自行缓存,否则可能造成内存和连接泄漏
service.setApplication(applicationConfig);
service.setRegistry(registry); // 多个注册中心可以用setRegistries()
service.setProtocol(protocol); // 多个协议可以用setProtocols()
service.setInterface(HellowService.class);
service.setRef(hellowService);
service.setVersion("1.0.0");

// 暴露及注册服务
service.export();

System.in.read()// press any key to exit

一个服务 的export 主要包括以下三点:
1.如何构造一个invoker
2. 根据protocol配置监听一个端口可以接受远程请求。
3. 以及将服务注册到 注册中心,这里我们用的zookeeper。

本篇重点分析下 service.export(); 看下 2 3 两点是如何实现的,invoker的我们后面分析调用过程时候单独再看。

export 方法最终的调用转到了doExportUrlsFor1Protocol,下面是具体代码

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
    String name = protocolConfig.getName();
    if (name == null || name.length() == 0) {
        name = "dubbo";
    }

    Map<String, String> map = new HashMap<String, String>();
    map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE);
    map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion());
    map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
    if (ConfigUtils.getPid() > 0) {
        map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
    }
    appendParameters(map, application);
    appendParameters(map, module);
    appendParameters(map, provider, Constants.DEFAULT_KEY);
    appendParameters(map, protocolConfig);
    appendParameters(map, this);
    // 省略了提取方法配置 参数到 map 的逻辑
    // ...
    }

    if (ProtocolUtils.isGeneric(generic)) {
        map.put("generic", generic);
        map.put("methods", Constants.ANY_VALUE);
    } else {
        String revision = Version.getVersion(interfaceClass, version);
        if (revision != null && revision.length() > 0) {
            map.put("revision", revision);
        }

        String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
        if (methods.length == 0) {
            logger.warn("NO method found in service interface " + interfaceClass.getName());
            map.put("methods", Constants.ANY_VALUE);
        } else {
            map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
        }
    }
    if (!ConfigUtils.isEmpty(token)) {
        if (ConfigUtils.isDefault(token)) {
            map.put("token", UUID.randomUUID().toString());
        } else {
            map.put("token", token);
        }
    }
    if ("injvm".equals(protocolConfig.getName())) {
        protocolConfig.setRegister(false);
        map.put("notify", "false");
    }
    // export service
    String contextPath = protocolConfig.getContextpath();
    if ((contextPath == null || contextPath.length() == 0) && provider != null) {
        contextPath = provider.getContextpath();
    }

    String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
    Integer port = this.findConfigedPorts(protocolConfig, name, map);
    URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map);

    if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
            .hasExtension(url.getProtocol())) {
        url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
    }

    String scope = url.getParameter(Constants.SCOPE_KEY);
    // don't export when none is configured
    if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {

        // export to local if the config is not remote (export to remote only when config is remote)
        if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
            //发布到本地
            exportLocal(url);
        }
        // export to remote if the config is not local (export to local only when config is local)
        if (!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)) {
            if (logger.isInfoEnabled()) {
                logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
            }
            if (registryURLs != null && !registryURLs.isEmpty()) {
                for (URL registryURL : registryURLs) {
                    url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY));
                    URL monitorUrl = loadMonitor(registryURL);
                    if (monitorUrl != null) {
                        url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
                    }
                    if (logger.isInfoEnabled()) {
                        logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
                    }
                    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

                    Exporter<?> exporter = protocol.export(wrapperInvoker);
                    exporters.add(exporter);
                }
            } else {
                Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
                DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

                Exporter<?> exporter = protocol.export(wrapperInvoker);
                exporters.add(exporter);
            }
        }
    }
    this.urls.add(url);
}

上面的代码有两个方法是发布服务 一个是 exportLocal(url); 发布到本地 一个是 Exporter

分析两个 Protocol wrapper

dubbo 里 默认将 扩展类构造函数,如果包含一个参数 是拓展类接口,则当作是 wrapper。

默认的Protocol 如DUbboProtocol 和RegistryProtocol 都会被下面的 两个 包裹。

filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper

ProtocolFilterWrapper 作用主要export 或refer 时候调用 buildInvokerChain 创建 一个invoker 调用链(原始的invoker 和list<Filter>合并为一个 invokerChain)。

ProtocolListenerWrapper 作用主要是  export 和 refer 之后调用 暴漏或者 refer 的监听器列表。


# dubbo 的 过滤器链 实现分析

这里模拟它的实现 给出关键的demo 代码:

// invoker 接口
package com.exampl_1;
public interface Invoker {

    Object invoke(Invocation invocation);
}

//invoker的参数
package com.exampl_1;
import java.lang.reflect.Method;
public interface Invocation {
    Method getMethod();

    Object[] getArgs();

    Object getTarget();
}

// filter 拦截
package com.exampl_1;
public interface Filter {

    Object filter(Invocation invocation, Invoker invoker);
}

// list<Filter> 和invoker 的合并为一个invokerChain
package com.exampl_1;
import java.util.ArrayList;
import java.util.List;
public class InvokerUtil {

    //合并  list<Filter> 和invoker 的合并为一个invokerChain 
    public static Invoker buildInvokerChain(Invoker invoker, List<Filter> filters) {
        Invoker temp = invoker;
        for (int i = filters.size() - 1; i >= 0; i--) {
            Filter filter = filters.get(i);
            temp = new FilterInvoker(filter, temp);
        }
        return temp;
    }

    //测试方法入口
    public static void main(String[] args) {
        Invoker trueInvoker = new DemoInvoker();
        List<Filter> filters = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            filters.add(new DemoFiter("filter-" + i));
        }
        Invoker invokerChain = buildInvokerChain(trueInvoker, filters);
        Object ret = invokerChain.invoke(null);
        System.out.println("invoker return :" + ret);
    }
}

//补充需要的Filter 转化成一个invoker
package com.exampl_1;

public class FilterInvoker implements Invoker {

    private Filter filter;

    private Invoker invoker;

    public FilterInvoker(Filter filter, Invoker invoker) {
        this.filter = filter;
        this.invoker = invoker;
    }

    @Override
    public Object invoke(Invocation invocation) {
        return filter.filter(invocation, invoker);
    }
}

//一个 invoker 样例
package com.exampl_1;
public class DemoInvoker implements Invoker {
    @Override
    public Object invoke(Invocation invocation) {
        System.out.println("----true invoker invoked----");
        return "DemoInvoker";
    }
}

// 一个filter 样例
package com.exampl_1;
public class DemoFiter implements Filter {

    private String name;

    public DemoFiter(String name) {
        this.name = name;
    }

    @Override
    public Object filter(Invocation invocation, Invoker invoker) {
        System.out.println(String.format("filter: %s before", name));
        Object ret = invoker.invoke(invocation);
        System.out.println(String.format("filter: %s after", name));
        return ret;
    }
}

执行输出如下:

filter: filter-0 before
filter: filter-1 before
filter: filter-2 before
----true invoker invoked----
filter: filter-2 after
filter: filter-1 after
filter: filter-0 after
invoker return :DemoInvoker

说明

关键逻辑是 将 一个filter 转化为 FilterInvoker (filter 包裹类)。

猜你喜欢

转载自blog.csdn.net/taotoxht/article/details/79879874