Dubbo/Dubbox的服务暴露(一)

dubboX提供rest服务 上一章,我们详细介绍了如何搭建dubbo服务,本章节我们将在dubbo服务的基础上,利用dubbox,对外提供rest服务。 1. 修改maven 依赖 目前的最新版是 dubbox-2.8.4 ,其实groupId和artifactId还是原来的不变,我们升级一下dubbo版本,并且新增dubbox依赖,修改后的pom文件如下 阅读详情

前言

源码入手

平时我要了解一个框架,基本会去从他的Listener入手,如果web.xml中没有配置listener可能还会有 filter,这是spring给我们的启示,可是当要去了解dubbo的时候,发现dubbo并没有自己的listener监听器。已知dubbo是一款和spring结合较好的rpc框架,那么其不使用web容器相关的方式,必然遵循spring的方式。依据平时开发经验,我们知道要想在Spring初始化之后,做一些自己的逻辑,有一种方法即实现org.springframework.beans.factory.InitializingBean接口,那么我们搜一下,dubbo有没有这么干。
这里写图片描述

前文 Dubbo 对配置文件的解析我们知道,服务(beans->dubbo:service)相关的节点配置会在com.alibaba.dubbo.config.spring.ServiceBean的实例中保存,这里正好巧了public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware
出去一些初始化参数的工作,这里我们主要关注这里

public void onApplicationEvent(ApplicationEvent event) {
        if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {
            if (isDelay() && ! isExported() && ! isUnexported()) {
                if (logger.isInfoEnabled()) {
                    logger.info("The service ready on spring started. service: " + getInterface());
                }
                //暴露服务
                export();
            }
        }
    }

public synchronized void export() 方法里会做一些判断,我们这里只关注自己最关注的部分

public synchronized void export() {
        //.......如果当前服务被暴露过就不再暴露,等一些判断
        if (delay != null && delay > 0) {//delay 延迟暴露参数,如果配置延迟暴露。
            Thread thread = new Thread(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(delay);
                    } catch (Throwable e) {
                    }
                    doExport();
                }
            });
            thread.setDaemon(true);
            thread.setName("DelayExportServiceThread");
            thread.start();
        } else {
            doExport();
        }
    }

很尴尬,好多源码都没有相关的文档注释,如果没参考相关资料,第一次阅读会很难受
protected synchronized void doExport() 这个方法的作用大概是执行具体的服务暴露

 protected synchronized void doExport() {
        //......异常处理省略.......//
        //检查provider是否有配置,如果该属性为null,则new一个ProviderConfig对象,方法内部调用appendProperties(provider)方法,该方法内部会拼装一个 dubbo.tagName.属性名的key,在配置文件中查找值,如果有值则调用属性的setter方法,设置属性值。
        checkDefault();
        //如果ProviderConfig实例不为null的情况下,初始化一些配置,通常情况下很少会配置<dubbo:provider/>标签
        //提供方的缺省值,当ProtocolConfig和ServiceConfig某属性没有配置时,采用此缺省值,可选。
        if (provider != null) {
            //application 对应 <dubbo:application/> 应用配置,用于配置当前应用信息,不管该应用是提供者还是消费者。
            if (application == null) {
                application = provider.getApplication();
            }
            // module 对应<dubbo:module/>模块配置,用于配置当前模块信息,可选。
            if (module == null) {
                module = provider.getModule();
            }
            //registries 对应 <dubbo:registry/> 注册中心配置,用于配置连接注册中心相关信息。
            if (registries == null) {
                registries = provider.getRegistries();
            }
            // monitor 对应 <dubbo:monitor/> 监控中心配置,用于配置连接监控中心相关信息,可选。
            if (monitor == null) {
                monitor = provider.getMonitor();
            }
            //protocols 对应 <dubbo:protocol/> 协议配置,用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受。
            if (protocols == null) {
                protocols = provider.getProtocols();
            }
        }
        //........省略进一步初始化相关配置的代码行 .......//
        if (ref instanceof GenericService) { //判断是否是泛化调用接口,这里不重要。
            interfaceClass = GenericService.class;
            if (StringUtils.isEmpty(generic)) {
                generic = Boolean.TRUE.toString();
            }
        } else {
            try {

                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
                        .getContextClassLoader());
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            //检查接口类中是否存在指定的方法,如果dubbo:service->dubbo:method 没有配置的情况下,methods为null,该方法不会执行方法校验。如果有相关的配置,该方法会检查name属性对应的方法是否存在,不存在会抛IllegalStateException异常。
            checkInterfaceAndMethods(interfaceClass, methods);
            // 检查服务实现,如果ref不是服务的接口实现,则会抛出IllegalStateException异常。
            checkRef();
            // 声明该接口非泛化调用
            generic = Boolean.FALSE.toString();
        }
        if(local !=null){ //如果是本地服务,常用配置方案下,local 值为null
            if(local=="true"){
                local=interfaceName+"Local";
            }
            Class<?> localClass;
            try {
                localClass = ClassHelper.forNameWithThreadContextClassLoader(local);
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            if(!interfaceClass.isAssignableFrom(localClass)){
                throw new IllegalStateException("The local implemention class " + localClass.getName() + " not implement interface " + interfaceName);
            }
        }
        if(stub !=null){//如果是远程服务,常用配置方案下,stub值为null
            if(stub=="true"){
                stub=interfaceName+"Stub";
            }
            Class<?> stubClass;
            try {
                stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub);
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            if(!interfaceClass.isAssignableFrom(stubClass)){
                throw new IllegalStateException("The stub implemention class " + stubClass.getName() + " not implement interface " + interfaceName);
            }
        }
        //检查应用配置,如果没有配置会创建默认对象。其内部会调用appendProperties(AbstractConfig config) 填充属性。检查失败会抛出IllegalStateException异常
        checkApplication();
        //检查注册中心配置,如果没有配置,则会检查配置文件中的dubbo.registry.address 设置,并创建默认对象。其内部会调用appendProperties(AbstractConfig config) 填充属性。检查失败会抛出IllegalStateException异常
        checkRegistry();
        //检查协议配置,该方法不会抛出异常,如果没配置dubbo:protocol,会取dubbo:provider相关配置填充,如果依旧protocols依旧为null,则创建默认对象。其内部会调用appendProperties(AbstractConfig config) 填充属性。
        checkProtocol();
        //填充属性 不多说
        appendProperties(this);
        //
        checkStubAndMock(interfaceClass);
        // 初始化path属性
        if (path == null || path.length() == 0) {
            path = interfaceName;
        }
        // 暴露服务的URL
        doExportUrls();
    }

doExportUrls(); 实现如下(吐槽,怀疑下到假的源码了,到处都没有文档注释):

 @SuppressWarnings({ "unchecked", "rawtypes" })
    private void doExportUrls() {
        //获得注册中心列表
        List<URL> registryURLs = loadRegistries(true);
        for (ProtocolConfig protocolConfig : protocols) {
            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
        }
    }

protected List loadRegistries(boolean provider) 类相关解析

protected List<URL> loadRegistries(boolean provider) {
        // 检查注册中心
        checkRegistry();
        List<URL> registryList = new ArrayList<URL>();
        if (registries != null && registries.size() > 0) {
            for (RegistryConfig config : registries) {
            //一般这个拿到的是注册中心地址,例如:zookeeper://1.6.5.5:2181
                String address = config.getAddress();
                if (address == null || address.length() == 0) {
                    address = Constants.ANYHOST_VALUE;
                }

                String sysaddress = System.getProperty("dubbo.registry.address");
                if (sysaddress != null && sysaddress.length() > 0) {
                    address = sysaddress;
                }
                if (address != null && address.length() > 0 
                        && ! RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
                    Map<String, String> map = new HashMap<String, String>();
                    appendParameters(map, application);
                    appendParameters(map, config);
                    map.put("path", RegistryService.class.getName());
                    map.put("dubbo", Version.getVersion());
                    map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
                    if (ConfigUtils.getPid() > 0) {
                        map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
                    }
                    if (! map.containsKey("protocol")) {
                        //查询注册中心是否支持remote协议
                        if (ExtensionLoader.getExtensionLoader(RegistryFactory.class).hasExtension("remote")) {
                            map.put("protocol", "remote");
                        } else {
                            map.put("protocol", "dubbo");
                        }
                    }
                    //目前到这里是zookeeper://ip地址:2181/com.alibaba.dubbo.registry.RegistryService?application=配置应用名&dubbo=2.8.4&file=缓存文件路径&logger=log4j&organization=22222&owner=weiythi&pid=20772&timestamp=1510040471140
                    List<URL> urls = UrlUtils.parseURLs(address, map);
                    for (URL url : urls) {
                        url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol());
                        //这个url会被转换成这种格式 registry://ip:2181/com.alibaba.dubbo.registry.RegistryService?application=配置的应用名&dubbo=2.8.4&file=缓存文件路径&logger=log4j&organization=22222&owner=weiythi&pid=20772&registry=zookeeper&timestamp=1510040471140 即会将注册中心转换成registry参数放到url中,并将url的protocol设置成registry
                        url = url.setProtocol(Constants.REGISTRY_PROTOCOL);
                        if ((provider && url.getParameter(Constants.REGISTER_KEY, true))
                                || (! provider && url.getParameter(Constants.SUBSCRIBE_KEY, true))) {
                            registryList.add(url);
                        }
                    }
                }
            }
        }
        return registryList;
    }

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs)

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
        //获得协议信息,默认dubbo
        String name = protocolConfig.getName();
        if (name == null || name.length() == 0) {
            name = "dubbo";
        }

        String host = protocolConfig.getHost();
        if (provider != null && (host == null || host.length() == 0)) {
            host = provider.getHost();
        }
        boolean anyhost = false;
        //判断host是不是为null,或localhost,等本地ip地址
        if (NetUtils.isInvalidLocalHost(host)) {
            //......省略 使用各种方式获取本机的实际ip地址........//
            host = InetAddress.getLocalHost().getHostAddress();
            //......省略 使用各种方式获取本机的实际ip地址........//
        }


        Integer port = protocolConfig.getPort();
        //.....省略,如果port为null,则尝试使用默认的port,如果默认的port无法使用,则会尝试使用随机的端口
        Map<String, String> map = new HashMap<String, String>();
        if (anyhost) {
            map.put(Constants.ANYHOST_KEY, "true");
        }
        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中,这里不做说明
        appendParameters(map, application);
        appendParameters(map, module);
        appendParameters(map, provider, Constants.DEFAULT_KEY);
        appendParameters(map, protocolConfig);
        appendParameters(map, this);
        // 常用配置方案下,methods为null,上文代码注释中有说明
        if (methods != null && methods.size() > 0) {
            //......省略,当有暴露指定方法的配置时,会暴露指定方法
        }
        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 {
                //拼接方法名为 a,b,c,d 这种形式
                map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
            }
        }
        if (! ConfigUtils.isEmpty(token)) { //处理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");
        }
        // 导出服务
        String contextPath = protocolConfig.getContextpath();
        if ((contextPath == null || contextPath.length() == 0) && provider != null) {
            contextPath = provider.getContextpath();
        }
        // 注意这里的URL是com.alibaba.dubbo.common.URL 对象,最后会被处理成一个类似这样的格式,以dubbo协议为例
        //dubbo://ip:port/接口名?其他信息
        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);
        //配置为none不暴露
        if (! Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {

            //配置不是remote的情况下做本地暴露 (配置为remote,则表示只暴露远程服务)
            if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
                exportLocal(url);
            }
            //如果配置不是local则暴露为远程服务.(配置为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.size() > 0
                        && url.getParameter("register", true)) {
                    for (URL registryURL : registryURLs) {//遍历注册中心

                        url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
                        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);
                        }
                        //ProxyFactory类的getInvoker方法使用ref生成一个AbstractProxyInvoker实例,到这一步就完成具体服务到Invoker的转化。接下来就是Invoker转换到Exporter的过程。
                        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
                        //Dubbo协议的Invoker转为Exporter发生在DubboProtocol类的export方法,它主要是打开socket侦听服务,并接收客户端发来的各种请求,通讯细节由Dubbo自己实现。
                        Exporter<?> exporter = protocol.export(invoker);
                        exporters.add(exporter);
                    }
                } else {
                    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);

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

下一篇集中处理如下代码流程,这一篇只是初步了解了dubbo 服务暴露预处理的一些逻辑,
至于为什么dubbo会选择生成 registry:// 和 dubbo:// 如下两种链接。以后篇幅讨论.
后续将继续跟踪以下代码片段的实现。

 //ProxyFactory类的getInvoker方法使用ref生成一个AbstractProxyInvoker实例,到这一步就完成具体服务到Invoker的转化。接下来就是Invoker转换到Exporter的过程。
                        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
                        //Dubbo协议的Invoker转为Exporter发生在DubboProtocol类的export方法,它主要是打开socket侦听服务,并接收客户端发来的各种请求,通讯细节由Dubbo自己实现。
                        Exporter<?> exporter = protocol.export(invoker);
                        exporters.add(exporter);
Dubbo的介绍以及Dubbox的区别 Dubbo官网:  http://dubbo.io/ Dubbox官网: https://github.com/dangdangdotcom/dubbox Dubbo 是阿里巴巴公司开源的一个基于Java的高性能开源RPC框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。后来因为某些原因没有维护,于是当当网在这之上推出了自己的Dubbox。 D... 阅读详情

相关推荐

Dubbo——各协议暴露和引用服务的逻辑

各协议暴露和引用服务的逻辑    目前Dubbox版本支持的协议有dubbo、injvm、rmi、hessian、thrift、memcached、redis、rest等九种,其中memcached和redis协议只支持服务引用不支持服务暴露;这些协议有的继承AbstractProxyProtocol类,有的实现了AbstractProtocol接口。服务暴露调用export方法,引用服务调用re...

meilong_whpu的专栏 5541

Dubbo和Zookeeper入门到实战,看这篇就够了

前沿:在当下流行的分布式架构中Dubbo是非常流行rpc框架,借着这几天有空学习学习,并在后面的项目中进行实战,为后面的分布式项目做铺垫。Dubbox简介Dubbox 是一个分布式rp...

weixin_44742132的博客 775

VS2015+Qt+OpenCV+open62541开发过程(05_VS2015中使用OPCUA open62541通过Kepware读写PLC数据)

此外还需要所需lib包:WS2_32.Lib(opcua通讯用到的库,opcua使用socket通讯,需使用此库),添加#pragma comment(lib,"ws2_32.lib") 语句,有的文章说需要添加ws2_32.lib文件或ws2_32.dll到项目资源中,貌似影响不大。2.在VS中选择x64平台会报错,选择x86平台可以用,应该是ws2_32.lib相关的库不支持64位,目前没有解决,继续后面的实验,看看用Qt后是否可以解决。6.VS中建立的变量,与读取的OPC点数据类型注意对应。

zzh17的博客 1862

Dubbox是什么,如何整合SpringBoot,有什么优势?

Dubbox是什么,如何整合SpringBoot,有什么优势?

杨荧的优快云博客 1410

VMD-CNN-BiLSTM-Attention预测模型 —— 数学模型介绍&完整实例代码

想解决电力负荷预测中的非线性、非平稳难题?这篇博客介绍了一种创新混合模型,结合变分模态分解(VMD)和CNN-BiLSTM-Attention深度学习架构,实现超高精度预测! ✨ 核心亮点: ✅ VMD分解:有效分离复杂负荷信号,提取关键频率特征 ✅ 混合深度学习:CNN捕捉局部模式 + BiLSTM学习长时序依赖 + 注意力机制聚焦关键时段 ✅ 端到端优化:从数据预处理(滑动窗口、归一化)到模型训练(MSE损失+Adam优化),完整流程公开! ✅ 工业级评估:提供MSE、MAE、MAPE、R²多指标验证

qq_42924330的博客 1653

时序基础模型Timer-S1:十亿参数如何革新时间序列预测

时间序列预测是数据分析与机器学习中的核心任务,旨在基于历史数据预测未来趋势。其原理在于捕捉数据中的趋势、周期性和季节性等时序依赖关系。这项技术的价值在于赋能业务决策,广泛应用于金融风控、能源管理、物联网监控和供应链优化等关键场景。传统方法依赖针对特定任务的专用模型,面临泛化能力弱和开发成本高的挑战。本文聚焦的时序基础模型,通过在海量跨领域数据上进行预训练,学习时序通用模式,并结合十亿级参数带来的强大容量,实现了性能的显著突破。这种范式转变,使得模型能够像“全科医生”一样,通过少量数据微调即可快速适应新任务,

weixin_29164843的博客 269

Dubbox——基本认识

1. 简介 Dubbo就是资源调度和治理中心的管理工具。 是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点 Dubbo 就是类似于webservice的关于系统...

武汉小喽啰 471

2023-ICCV-隐式神经网络实现低光照图像增强(NeRCo)论文解读+代码解析

NeRCo()提出了一种名为NeRCo的隐式神经表示方法,用于合作式低光图像增强。现有的低光图像增强方法存在以下三个限制:不可预测的亮度降低和噪声、度量友好版本和视觉友好版本之间的固有差距,以及有限的配对训练数据。为了解决这些限制,论文提出了NeRCo方法,它以无监督的方式稳健地恢复感知友好的结果。具体而言,NeRCo通过一个可控的拟合函数统一了现实场景中多样的退化因素,从而提高了鲁棒性。对于输出结果,论文引入了来自预训练视觉-语言模型的先验信息,采用语义导向的监督方法。

weixin_45595504的博客 3185

Dubbo 和 Dubbox 之间的区别

Dubbo 最早由阿里巴巴在 2011 年开源,是一个用于微服务架构的分布式服务框架。Dubbo 提供了高效的远程服务调用、服务注册与发现、负载均衡、服务容错等功能,帮助开发者构建和管理分布式系统。然而,在 2014 年左右,阿里巴巴停止了对 Dubbo 的维护。这段时间内,尽管 Dubbo 仍然在许多企业中广泛使用,但由于缺乏官方更新和维护,社区对 Dubbo 的发展感到担忧。Dubbo 和 Dubbox 都是强大的分布式服务框架,各自有其独特的功能和应用场景。

Flying_Fish_roe的博客 1075

EDKII环境配置完整版

参考博客【EDK2 UDK2018的环境搭建】:https://blog.youkuaiyun.com/qq_39155263/article/details/82965744下载EDK2 1.直接从https://github.com/tianocore/edk2/ 网站下载.zip压缩文件 2.运用svn 从http://svn.code.sf.net/p/edk2/code/trunk/edk2edk2下载 3.安装Visual Studio2017 安装其他Tool 1.IASL 从https..

tianpu2320959696的博客 1854

Bert+CNN文本分类(含代码实现)

一、什么是CNN? CNN的特点: (1)特定特征位移不变性 (2)特征缩放不变性 2. CNN模型构造过程 2.1 Convolution(卷积) (1)获取关键特征(减少参数) (2)共享权重(再次减少参数) 2.2 Max Pooling(池化) 2.3 Flatten 向量转换为如图所示可以进入全连接层的向量模式 3. TextCNN 上图可理解为: 通过不同的size(如上图2、3、4等),上图红色代表 size=2,黄色...

Python,数据分析,机器学习,深度学习 1万+

Dubbo详细介绍与安装使用过程

1 Dubbo介绍1.1 dubbox简介随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。 单一应用架构 当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。 此时,用于简化增删改查工作量的 数据访问框架(ORM) 是关键。 垂直应用架构 当访问量逐渐增大,单一应用

徐刘根的博客 19万+

Hermes Agent 彩蛋大盘点:藏在终端里的浪漫

本文主要介绍了Hermes Agent 彩蛋大盘点:藏在终端里的浪漫,希望能对使用Hermes Agent的同学们有所帮助。 文章目录 1. 前言 2. Spinner 动画 3. Kawaii 表情 4. 思考动词 THINKING_VERBS 5. 皮肤主题 6. 启动 Banner 7. 工具 Emoji 8. 内置人格 9. SOUL.md —— Agent 的灵魂 10. BOOT.md —— 启动自动执行 11. 随机 Tips 12. 统计总览

weixin_43178406的博客 7万+

Dubbo/Dubbox的dubbo协议实现(一)-服务端启动

之前已经分析的dubbo的服务的发现和注册,这里先看一下dubbo协议是如何实现的,之前已经知道了,调用DubboProtocol类的export来暴露服务的,协议实现比较复杂,这里只关系主体实现即排除一些特性功能的处理代码本章主要处理服务端对应的暴露流程,继续回到···com.alibaba.dubbo.config.ServiceConfig···的doExportUrlsFor1Protoco

weiythi的Blog 2322

倍福--实现TCP/IP的配置

控制器为CX5120,需要和上位机做通信,选择TCP/IP的通讯方式,本文介绍TCP/IP通信的操作步骤。 目 录 软硬件版本 3 1.1. 倍福Beckhoff 3 1.1.1. 控制器硬件 3 1.1.2. 控制软件 3 1.2. 串口调试助手 3 1.2.1. TCP调试通信助手 3 授权文件 3 2.1 Lib文件 3 2.2. CAB文件 4 PLC程序编写 4 3.1. 引入TCP/IP库文件 4 3.2. Client端程序 5 3.2.1. 建立相关变量 5 3.3.2. 编写连接功能块

weixin_41883890的博客 5730

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Dubbo/Dubbox的服务暴露(三)- 服务的注册

接上《 Dubbo/Dubbox的服务暴露(二)-扩展点机制》上文书依旧疑留的疑问,这两句到底在干啥Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()))

weiythi的Blog 525

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Dubbo 延迟服务暴露

前言 大家好,今天开始给大家分享 — Dubbo 专题之 Dubbo 延迟服务暴露。在前一个章节中我们介绍了 Dubbo Stub 和 Mock,我们例举了常见的使用场景并且进行了源码解析来分析其实现原理,同时我们知道 Dubbo Stub 和 Mock 都是基于对调用代理对象的包装实现的,这样可以为我们在调用服务时做一些前置或后置处理工作。有的小伙伴可能会遇到这样的场景:在我们的应用服务中有很多的本地缓存或者分布式缓存,这些缓存有可能需要加载一段时间那么在这个缓存加载过程中我们希望接口不要对外提供服务,那

liyong1028826685的专栏 875

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Dubbo vs Dubbox:深度解析面试必看!

Dubbo 是阿里巴巴开源的高性能 Java RPC 框架,专注于服务发现与调用,支持多种协议及扩展机制;而 Dubbox 则是基于 Dubbo 的封装版本,主要面向 Spring 用户,提供了更便捷的 Web 服务开发能力。两者核心区别在于功能定位和扩展性:Dubbo 更底层、灵活,适合复杂场景;Dubbox 则封装了更多特性,简化开发但灵活性稍逊。同...

蓝鲸鱼计算机软件开发工作室 435

Dubbo/Dubbox的服务暴露(二)-扩展点机制

接上《 Dubbo/Dubbox的服务暴露(一)》上文书留的疑问,这两句到底在干啥 Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.t

weiythi的Blog 688

Dubbox简介与入门实战

前言 什么是Dubbox?Dubbox是一个分布式服务框架,其前身是阿里巴巴开源项目Dubbo,被国内电商及互联网项目中使用,后期阿里巴巴停止了Dubbo项目的维护(现Dubbo已捐献给Apache基金会),因为阿里巴巴内部的HSF框架比Dubbo更高效,更贴合他们业务。当当网便在Dubbo基础上进行优化,并继续进行维护,为了与原有的Dubbo区别,故将其命名为Dubbox。 Dubbox作用 d...

Wim的博客 7743

dubbo服务搭建教程

本文在dubbo的基础上提供rest服务

z_xiaocun的博客 2192

Dubbox框架简介

Dubbox框架简介 Dubbox是一个分布式服务框架,其前身是阿里巴巴开源项目Dubbo,被国内电商及互联网项目中使用,后期阿里巴巴停止了该项目的维护,当当网便在Dubbo基础上进行优化,并继续维护,为了与原有的Dubbo区分,故将其命名为Dubbox。 Dubbox致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。简单的说,dubbox就是个服务框架,如果没有分布式需求...

Django的博客 7909

dubbo源码分析--预热warmup过程

阿飞Javaer,转载请注明原创出处,谢谢! 前言 今天群里小伙伴黄晓峰VIVO咨询一个问题:”dubbo接口怎么做预热呢,每次上线,都会有一小部分超时?”,熟悉JVM都知道,JVM重启后有一段预热过程,要运行一段时间,它的性能才能达到最佳状态;阿里JVM团队就针对这个缺陷进行了优化,其特性名曰:jwarmup,可以点击Alibaba JVM创新提效 获国际社区认可登台JVM圈顶会...

阿飞Javaer的专栏 4269

Dubbo和Dubbox

        Dubbox 是一个分布式服务框架,其前身是阿里巴巴开源项目Dubbo ,被国内电商及互联网项目中使用,后期阿里巴巴停止了该项目的维护,当当网便在Dubbo基础上进行优化,并继续维护,为了与原有的Dubbo区分,故将其命名为Dubbox。是个服务调用的东东,说白了就是个远程服务调用的分布式框架。                                    节点角色说明: ...

antushengV的博客 452

浅谈Dubbox原理

Dubbox介绍 Dubbox是一个分布式服务框架,前身是阿里旗下的开源项目Dubbo,后来阿里停止维护,当当网在Dubbo的基础上进行优化,并继续维护,为了与原来的Dubbo区分故将其改名为Dubbox,当当网在其原有的基础上实现了一些新功能REST(Representational State Transfer)风格,REST调用也是的Dubbox可以对当今特别流行的&quot;微服务&quot;架构提供支持...

迷途的博客 3218
上一篇: Java spi机制浅谈
下一篇: Dubbo/Dubbox的服务暴露(二)-扩展点机制
weiythi
博客等级 码龄16年 23粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值