成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【Dubbo源碼閱讀系列】之 Dubbo XML 配置加載

wangshijun / 1975人閱讀

摘要:在介紹自定義標(biāo)簽解析前,先放一張圖幫助大家理解以下是如何從文件中解析并加載的。自定義標(biāo)簽比如的值為根據(jù)獲取到的,獲取對應(yīng)的對象。關(guān)于和加載先后順序的問題最后再集合一個(gè)小例子總結(jié)下吧當(dāng)我們先解析了元素時(shí),我們會遍歷所有已經(jīng)注冊注冊表中。

今天我們來談?wù)?Dubbo XML 配置相關(guān)內(nèi)容。關(guān)于這部分內(nèi)容我打算分為以下幾個(gè)部分進(jìn)行介紹:

Dubbo XML

Spring 自定義 XML 標(biāo)簽解析

Dubbo 自定義 XML 標(biāo)簽解析

DubboBeanDefinitionParser.parse()

End

Dubbo XML

在本小節(jié)開始前我們先來看下 Dubbo XML 配置文件示例:

dubbo-demo-provider.xml


    

    
    
    

    
    

    
    

    
    

在這段配置文件中有一些以 dubbo 開頭的 xml 標(biāo)簽,直覺告訴我們這種標(biāo)簽和 dubbo 密切相關(guān)。那么這些標(biāo)簽的用途是什么?又是如何被識別的呢?
我們結(jié)合 Spring 自定義 xml 標(biāo)簽實(shí)現(xiàn)相關(guān)內(nèi)容來聊聊 Dubbo 是如何定義并加載這些自定義標(biāo)簽的。

Spring 自定義 XML 標(biāo)簽解析

Dubbo 中的自定義 XML 標(biāo)簽實(shí)際上是依賴于 Spring 解析自定義標(biāo)簽的功能實(shí)現(xiàn)的。網(wǎng)上關(guān)于 Spring 解析自定義 XML 標(biāo)簽的文章也比較多,這里我們僅介紹下實(shí)現(xiàn)相關(guān)功能需要的文件,給大家一個(gè)直觀的印象,不去深入的對 Spring 自定義標(biāo)簽實(shí)現(xiàn)作詳細(xì)分析。

定義 xsd 文件

XSD(XML Schemas Definition) 即 XML 結(jié)構(gòu)定義。我們通過 XSD 文件不僅可以定義新的元素和屬性,同時(shí)也使用它對我們的 XML 文件規(guī)范進(jìn)行約束。
在 Dubbo 項(xiàng)目中可以找類似實(shí)現(xiàn):dubbo.xsd

spring.schemas

該配置文件約定了自定義命名空間和 xsd 文件之間的映射關(guān)系,用于 spring 容器感知我們自定義的 xsd 文件位置。

http://dubbo.apache.org/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd
http://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/compat/dubbo.xsd

spring.handlers

該配置文件約定了自定義命名空間和 NamespaceHandler 類之間的映射關(guān)系。 NamespaceHandler 類用于注冊自定義標(biāo)簽解析器。

http://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler

命名空間處理器

命名空間處理器主要用來注冊 BeanDefinitionParser 解析器。對應(yīng)上面 spring.handlers 文件中的 DubboNamespaceHandler

public class DubboNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        // 省略...
        registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
    }
}

BeanDefinitionParser 解析器

實(shí)現(xiàn) BeanDefinitionParser 接口中的 parse 方法,用于自定義標(biāo)簽的解析。Dubbo 中對應(yīng) DubboBeanDefinitionParser 類。

Dubbo 解析自定義 XML 標(biāo)簽

終于進(jìn)入到本文的重頭戲環(huán)節(jié)了。在介紹 Dubbo 自定義 XML 標(biāo)簽解析前,先放一張圖幫助大家理解以下 Spring 是如何從 XML 文件中解析并加載 Bean 的。


上圖言盡于 handler.parse() 方法,如果你仔細(xì)看了上文,對 parse() 應(yīng)該是有印象的。
沒錯(cuò),在前一小結(jié)的第五點(diǎn)我們介紹了 DubboBeanDefinitionParser 類。該類有個(gè)方法就叫 parse()。那么這個(gè) parse() 方法有什么用? Spring 是如何感知到我就要調(diào)用 DubboBeanDefinitionParser 類中的 parse() 方法的呢?我們帶著這兩個(gè)問題接著往下看。

BeanDefinitionParserDelegate

上面圖的流程比較長,我們先著重看下 BeanDefinitionParserDelegate 類中的幾個(gè)關(guān)鍵方法。

BeanDefinitionParserDelegate.java
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    // 獲取當(dāng)前 element 的 namespaceURI
    // 比如 dubbo.xsd 中的為 http://dubbo.apache.org/schema/dubbo
    String namespaceUri = this.getNamespaceURI(ele);
    // 根據(jù) URI 獲取對應(yīng)的 NamespaceHandler
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
        this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
        return null;
    } else {
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }
}

這個(gè)方法干了三件事

獲取 element 元素的 namespaceURI,并據(jù)此獲取對應(yīng)的 NamespaceHandler 對象。Dubbo 自定義標(biāo)簽(比如 Dubbo:provider) namespaceUri 的值為 http://dubbo.apache.org/schema/dubbo;

根據(jù) step1 獲取到的 namespaceUri ,獲取對應(yīng)的 NamespaceHandler 對象。這里會調(diào)用 DefaultNamespaceHandlerResolver 類的 resolve() 方法,我們下面會分析;

調(diào)用 handler 的 parse 方法,我們自定以的 handler 會繼承 NamespaceHandlerSupport 類,所以這里調(diào)用的其實(shí)是 NamespaceHandlerSupport 類的 parse() 方法,后文分析;

一圖勝千言
在詳細(xì)分析 step2 和 step3 中涉及的 resolver()parse() 方法前,先放一張時(shí)序圖讓大家有個(gè)基本概念:

DefaultNamespaceHandlerResolver.java
public NamespaceHandler resolve(String namespaceUri) {
    Map handlerMappings = this.getHandlerMappings();
    // 以 namespaceUri 為 Key 獲取對應(yīng)的 handlerOrClassName
    Object handlerOrClassName = handlerMappings.get(namespaceUri);
    if (handlerOrClassName == null) {
        return null;
    } else if (handlerOrClassName instanceof NamespaceHandler) {
        return (NamespaceHandler)handlerOrClassName;
    } else {
        // 如果不為空且不為 NamespaceHandler 的實(shí)例,轉(zhuǎn)換為 String 類型
        // DubboNamespaceHandler 執(zhí)行的便是這段邏輯
        String className = (String)handlerOrClassName;

        try {
            Class handlerClass = ClassUtils.forName(className, this.classLoader);
            // handlerClass 是否為 NamespaceHandler 的實(shí)現(xiàn)類,若不是則拋出異常
            if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
            } else {
                // 初始化 handlerClass
                NamespaceHandler namespaceHandler = (NamespaceHandler)BeanUtils.instantiateClass(handlerClass);
                // 執(zhí)行 handlerClass類的 init() 方法
                namespaceHandler.init();
                handlerMappings.put(namespaceUri, namespaceHandler);
                return namespaceHandler;
            }
        } catch (ClassNotFoundException var7) {
            throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "] not found", var7);
        } catch (LinkageError var8) {
            throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]: problem with handler class file or dependent class", var8);
        }
    }
}

resolve() 方法用途是根據(jù)方法參數(shù)中的 namespaceUri 獲取對應(yīng)的 NamespaceHandler 對象。這里會先嘗試以 namespaceUri 為 key 去 handlerMappings 集合中取對象。
如果 handlerOrClassName 不為 null 且不為 NamespaceHandler 的實(shí)例。那么嘗試將 handlerOrClassName 作為 className 并調(diào)用 BeanUtils.instantiateClass() 方法初始化一個(gè)
NamespaceHandler 實(shí)例。初始化后,調(diào)用其 init() 方法。這個(gè) init() 方法比較重要,我們接著往下看。

DubboNamespaceHandler
public void init() {
    registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
    registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
    registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
    registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
    registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
    registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
    registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
    registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
    registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
    registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}

NamespaceHandlerSupport
private final Map parsers = new HashMap();
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
    this.parsers.put(elementName, parser);
}

DubboNamespaceHandler 類中的 init() 方法干的事情特別簡單,就是新建 DubboBeanDefinitionParser 對象并將其放入 NamespaceHandlerSupport 類的 parsers 集合中。我們再回顧一下 parseCustomElement() 方法。

BeanDefinitionParserDelegate.java
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    // 省略...
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    // 省略...
}

這里會調(diào)用 NamespaceHandlerSupport 類的 parse() 方法。我們繼續(xù)跟蹤一下。

public BeanDefinition parse(Element element, ParserContext parserContext) {
    return this.findParserForElement(element, parserContext).parse(element, parserContext);
}
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
    String localName = parserContext.getDelegate().getLocalName(element);
    BeanDefinitionParser parser = (BeanDefinitionParser)this.parsers.get(localName);
    if (parser == null) {
        parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
    }

    return parser;
}

看到這里大家有沒有一絲豁然開朗的感覺?之前的 resolve() 方法實(shí)際上就是根據(jù)當(dāng)前 element 的 namespaceURI 獲取對應(yīng)的 NamespaceHandler 對象(對于 Dubbo 來說是 DubboNamespaceHandler),
然后調(diào)用 DubboNamespaceHandler 中的 init() 方法新建 DubboBeanDefinitionParser 對象并注冊到 NamespaceHandlerSupport 類的 parsers 集合中。
然后 parser 方法會根據(jù)當(dāng)前 element 對象從 parsers 集合中獲取合適的 BeanDefinitionParser 對象。對于 Dubbo 元素來說,實(shí)際上最后執(zhí)行的是 DubboBeanDefinitionParser 的 parse() 方法。

DubboBeanDefinitionParser.parse()

最后我們再來看看 Dubbo 解析 XML 文件的詳細(xì)實(shí)現(xiàn)吧。如果對具體實(shí)現(xiàn)沒有興趣可直接直接跳過。

private static BeanDefinition parse(Element element, ParserContext parserContext, Class beanClass, boolean required) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(beanClass);
        beanDefinition.setLazyInit(false);
        String id = element.getAttribute("id");
        // DubboBeanDefinitionParser 構(gòu)造方法中有對 required 值進(jìn)行初始化;
        // DubboNamespaceHandler 類中的 init 方法會創(chuàng)建并注冊 DubboBeanDefinitionParser 類
        if ((id == null || id.length() == 0) && required) {
            String generatedBeanName = element.getAttribute("name");
            if (generatedBeanName == null || generatedBeanName.length() == 0) {
                if (ProtocolConfig.class.equals(beanClass)) {
                    generatedBeanName = "dubbo";
                } else {
                    // name 屬性為空且不為 ProtocolConfig 類型,取 interface 值
                    generatedBeanName = element.getAttribute("interface");
                }
            }
            if (generatedBeanName == null || generatedBeanName.length() == 0) {
                // 獲取 beanClass 的全限定類名
                generatedBeanName = beanClass.getName();
            }
            id = generatedBeanName;
            int counter = 2;
            while (parserContext.getRegistry().containsBeanDefinition(id)) {
                id = generatedBeanName + (counter++);
            }
        }
        if (id != null && id.length() > 0) {
            if (parserContext.getRegistry().containsBeanDefinition(id)) {
                throw new IllegalStateException("Duplicate spring bean id " + id);
            }
            // 注冊 beanDefinition
            parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
            // 為 beanDefinition 添加 id 屬性
            beanDefinition.getPropertyValues().addPropertyValue("id", id);
        }
        
        // 如果當(dāng)前 beanClass 類型為 ProtocolConfig
        // 遍歷已經(jīng)注冊過的 bean 對象,如果 bean 對象含有 protocol 屬性
        // protocol 屬性值為 ProtocolConfig 實(shí)例且 name 和當(dāng)前 id 值一致,為當(dāng)前 beanClass 對象添加 protocl 屬性
        if (ProtocolConfig.class.equals(beanClass)) {
            for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
                BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
                PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
                if (property != null) {
                    Object value = property.getValue();
                    if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) {
                        definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
                    }
                }
            }
        } else if (ServiceBean.class.equals(beanClass)) {
            // 如果當(dāng)前元素包含 class 屬性,調(diào)用 ReflectUtils.forName() 方法加載類對象
            // 調(diào)用 parseProperties 解析其他屬性設(shè)置到 classDefinition 對象中
            // 最后設(shè)置 beanDefinition 的 ref 屬性為 BeanDefinitionHolder 包裝類
            String className = element.getAttribute("class");
            if (className != null && className.length() > 0) {
                RootBeanDefinition classDefinition = new RootBeanDefinition();
                classDefinition.setBeanClass(ReflectUtils.forName(className));
                classDefinition.setLazyInit(false);
                parseProperties(element.getChildNodes(), classDefinition);
                beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
            }
        } else if (ProviderConfig.class.equals(beanClass)) {
            parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);
        } else if (ConsumerConfig.class.equals(beanClass)) {
            parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);
        }
        Set props = new HashSet();
        ManagedMap parameters = null;
        for (Method setter : beanClass.getMethods()) {
            String name = setter.getName();
            if (name.length() > 3 && name.startsWith("set")
                    && Modifier.isPublic(setter.getModifiers())
                    && setter.getParameterTypes().length == 1) {
                Class type = setter.getParameterTypes()[0];
                String propertyName = name.substring(3, 4).toLowerCase() + name.substring(4);
                String property = StringUtils.camelToSplitName(propertyName, "-");
                props.add(property);
                Method getter = null;
                try {
                    getter = beanClass.getMethod("get" + name.substring(3), new Class[0]);
                } catch (NoSuchMethodException e) {
                    try {
                        getter = beanClass.getMethod("is" + name.substring(3), new Class[0]);
                    } catch (NoSuchMethodException e2) {
                    }
                }
                if (getter == null
                        || !Modifier.isPublic(getter.getModifiers())
                        || !type.equals(getter.getReturnType())) {
                    continue;
                }
                if ("parameters".equals(property)) {
                    parameters = parseParameters(element.getChildNodes(), beanDefinition);
                } else if ("methods".equals(property)) {
                    parseMethods(id, element.getChildNodes(), beanDefinition, parserContext);
                } else if ("arguments".equals(property)) {
                    parseArguments(id, element.getChildNodes(), beanDefinition, parserContext);
                } else {
                    String value = element.getAttribute(property);
                    if (value != null) {
                        value = value.trim();
                        if (value.length() > 0) {
                        // 如果屬性為 registry,且 registry 屬性的值為"N/A",標(biāo)識不會注冊到任何注冊中心
                        // 新建 RegistryConfig 并將其設(shè)置為 beanDefinition 的 registry 屬性
                            if ("registry".equals(property) && RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(value)) {
                                RegistryConfig registryConfig = new RegistryConfig();
                                registryConfig.setAddress(RegistryConfig.NO_AVAILABLE);
                                beanDefinition.getPropertyValues().addPropertyValue(property, registryConfig);
                            } else if ("registry".equals(property) && value.indexOf(",") != -1) {
                                // 多注冊中心解析
                                parseMultiRef("registries", value, beanDefinition, parserContext);
                            } else if ("provider".equals(property) && value.indexOf(",") != -1) {
                                parseMultiRef("providers", value, beanDefinition, parserContext);
                            } else if ("protocol".equals(property) && value.indexOf(",") != -1) {
                                // 多協(xié)議
                                parseMultiRef("protocols", value, beanDefinition, parserContext);
                            } else {
                                Object reference;
                                if (isPrimitive(type)) {
                                    // type 為方法參數(shù),type 類型是否為基本類型
                                    if ("async".equals(property) && "false".equals(value)
                                            || "timeout".equals(property) && "0".equals(value)
                                            || "delay".equals(property) && "0".equals(value)
                                            || "version".equals(property) && "0.0.0".equals(value)
                                            || "stat".equals(property) && "-1".equals(value)
                                            || "reliable".equals(property) && "false".equals(value)) {
                                        // 新老版本 xsd 兼容性處理
                                        // backward compatibility for the default value in old version"s xsd
                                        value = null;
                                    }
                                    reference = value;
                                } else if ("protocol".equals(property)
                                        && ExtensionLoader.getExtensionLoader(Protocol.class).hasExtension(value)
                                        && (!parserContext.getRegistry().containsBeanDefinition(value)
                                        || !ProtocolConfig.class.getName().equals(parserContext.getRegistry().getBeanDefinition(value).getBeanClassName()))) {
                                    // 如果 protocol 屬性值有對應(yīng)的擴(kuò)展實(shí)現(xiàn),而且沒有被注冊到 spring 注冊表中
                                    // 或者 spring 注冊表中對應(yīng)的 bean 的類型不為 ProtocolConfig.class
                                    if ("dubbo:provider".equals(element.getTagName())) {
                                        logger.warn("Recommended replace  to ");
                                    }
                                    // backward compatibility
                                    ProtocolConfig protocol = new ProtocolConfig();
                                    protocol.setName(value);
                                    reference = protocol;
                                } else if ("onreturn".equals(property)) {
                                    int index = value.lastIndexOf(".");
                                    String returnRef = value.substring(0, index);
                                    String returnMethod = value.substring(index + 1);
                                    reference = new RuntimeBeanReference(returnRef);
                                    beanDefinition.getPropertyValues().addPropertyValue("onreturnMethod", returnMethod);
                                } else if ("onthrow".equals(property)) {
                                    int index = value.lastIndexOf(".");
                                    String throwRef = value.substring(0, index);
                                    String throwMethod = value.substring(index + 1);
                                    reference = new RuntimeBeanReference(throwRef);
                                    beanDefinition.getPropertyValues().addPropertyValue("onthrowMethod", throwMethod);
                                } else if ("oninvoke".equals(property)) {
                                    int index = value.lastIndexOf(".");
                                    String invokeRef = value.substring(0, index);
                                    String invokeRefMethod = value.substring(index + 1);
                                    reference = new RuntimeBeanReference(invokeRef);
                                    beanDefinition.getPropertyValues().addPropertyValue("oninvokeMethod", invokeRefMethod);
                                } else {
                                    // 如果 ref 屬性值已經(jīng)被注冊到 spring 注冊表中
                                    if ("ref".equals(property) && parserContext.getRegistry().containsBeanDefinition(value)) {
                                        BeanDefinition refBean = parserContext.getRegistry().getBeanDefinition(value);
                                        // 非單例拋出異常
                                        if (!refBean.isSingleton()) {
                                            throw new IllegalStateException("The exported service ref " + value + " must be singleton! Please set the " + value + " bean scope to singleton, eg: ");
                                        }
                                    }
                                    reference = new RuntimeBeanReference(value);
                                }
                                beanDefinition.getPropertyValues().addPropertyValue(propertyName, reference);
                            }
                        }
                    }
                }
            }
        }
        NamedNodeMap attributes = element.getAttributes();
        int len = attributes.getLength();
        for (int i = 0; i < len; i++) {
            Node node = attributes.item(i);
            String name = node.getLocalName();
            if (!props.contains(name)) {
                if (parameters == null) {
                    parameters = new ManagedMap();
                }
                String value = node.getNodeValue();
                parameters.put(name, new TypedStringValue(value, String.class));
            }
        }
        if (parameters != null) {
            beanDefinition.getPropertyValues().addPropertyValue("parameters", parameters);
        }
        return beanDefinition;
    }

上面這一大段關(guān)于配置的解析的代碼需要大家自己結(jié)合實(shí)際的代碼進(jìn)行調(diào)試才能更好的理解。我在理解 Dubbo XML 解析的時(shí)候,也是耐著性子一遍一遍的來。
關(guān)于 ProtocolConfig 和 protocol 加載先后順序的問題最后再集合一個(gè)小例子總結(jié)下吧:

    dubbo-demo-provider.xml
    

當(dāng)我們先解析了 ProtocolConfig 元素時(shí),我們會遍歷所有已經(jīng)注冊 spring 注冊表中 bean。如果 bean 對象存在 protocol 屬性且與 name 和當(dāng)前 ProtolConfig id 匹配,則會新建 RuntimeBeanReference 對象覆蓋 protocol 屬性。對于上面這行配置,最后會新建一個(gè)擁有 name 和 port 的 beanDefinition 對象。

先解析了 protocol 元素,ProtocolConfig 未被解析。此時(shí)我們在 spring 注冊表中找不到對應(yīng)的 ProtocolConfig bean。此時(shí)我們將需要新建一個(gè) ProtocolConfig 并將其 name 屬性
設(shè)置為當(dāng)前屬性值。最后將其設(shè)置為 beanDefinition 對象的 protocol 屬性。后面加載到了 ProtocolConfig 元素時(shí),會替換 protocol 的值。

End

Dubbo 對于自定義 XML 標(biāo)簽的定義和解析實(shí)際上借助了 Spring 框架對自定義 XML 標(biāo)簽的支持。本篇水文雖然又臭又長,但是對于理解 Dubbo 的初始化過程還是很重要的。后面我們會介紹關(guān)于 Dubbo 服務(wù)暴露相關(guān)內(nèi)容。

本BLOG上原創(chuàng)文章未經(jīng)本人許可,不得用于商業(yè)用途及傳統(tǒng)媒體。網(wǎng)絡(luò)媒體轉(zhuǎn)載請注明出處,否則屬于侵權(quán)行為。https://juejin.im/post/5c1753b65188250850604ebe

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/11959.html

相關(guān)文章

  • dubbo源碼解析(一)Hello,Dubbo

    摘要:英文全名為,也叫遠(yuǎn)程過程調(diào)用,其實(shí)就是一個(gè)計(jì)算機(jī)通信協(xié)議,它是一種通過網(wǎng)絡(luò)從遠(yuǎn)程計(jì)算機(jī)程序上請求服務(wù)而不需要了解底層網(wǎng)絡(luò)技術(shù)的協(xié)議。 Hello,Dubbo 你好,dubbo,初次見面,我想和你交個(gè)朋友。 Dubbo你到底是什么? 先給出一套官方的說法:Apache Dubbo是一款高性能、輕量級基于Java的RPC開源框架。 那么什么是RPC? 文檔地址:http://dubbo.a...

    evin2016 評論0 收藏0
  • dubbo服務(wù)發(fā)布一服務(wù)暴露

    摘要:整體流程以調(diào)試來演示服務(wù)的發(fā)布流程。暴露遠(yuǎn)程服務(wù)假如服務(wù)沒有配置了屬性,或者配置了但是值不是,就會執(zhí)行遠(yuǎn)程暴露。封裝了一個(gè)服務(wù)的相關(guān)信息,是一個(gè)服務(wù)可執(zhí)行體。是一個(gè)服務(wù)域,他是引用和暴露的主要入口,它負(fù)責(zé)的生命周期管理。 整體流程以調(diào)試 om.alibaba.dubbo.demo.provider.DemoProvider來演示dubbo服務(wù)的發(fā)布流程。 1、啟動(dòng)Spring容器 參照...

    xialong 評論0 收藏0
  • Dubbo Spring Cloud 重塑微服務(wù)治理

    摘要:在服務(wù)治理方面,相較于而言,并不成熟。遺憾的是,往往被部分開發(fā)者片面地視作服務(wù)治理的框架,而非微服務(wù)基礎(chǔ)設(shè)施。因此,建議開發(fā)人員將或者遷移為服務(wù)。因此,下一步需要將其配置服務(wù)遠(yuǎn)程。當(dāng)服務(wù)提供方啟動(dòng)后,下一步實(shí)現(xiàn)一個(gè)服務(wù)消費(fèi)方。 原文鏈接:Dubbo Spring Cloud 重塑微服務(wù)治理,來自于微信公眾號:次靈均閣 摘要 在 Java 微服務(wù)生態(tài)中,Spring Cloud1 成為...

    wh469012917 評論0 收藏0
  • Dubbo 一篇文章就夠了:從入門到實(shí)戰(zhàn)

    摘要:啟動(dòng)容器,加載,運(yùn)行服務(wù)提供者。服務(wù)提供者在啟動(dòng)時(shí),在注冊中心發(fā)布注冊自己提供的服務(wù)。注冊中心返回服務(wù)提供者地址列表給消費(fèi)者,如果有變更,注冊中心將基于長連接推送變更數(shù)據(jù)給消費(fèi)者。 一 為什么需要 dubbo 很多時(shí)候,其實(shí)我們使用這個(gè)技術(shù)的時(shí)候,可能都是因?yàn)轫?xiàng)目需要,所以,我們就用了,但是,至于為什么我們需要用到這個(gè)技術(shù),可能自身并不是很了解的,但是,其實(shí)了解技術(shù)的來由及背景知識,對...

    tomener 評論0 收藏0
  • Spring Cloud與Dubbo的完美融合手「Spring Cloud Alibaba」

    摘要:構(gòu)建服務(wù)接口創(chuàng)建一個(gè)簡單的項(xiàng)目,并在下面定義一個(gè)抽象接口,比如構(gòu)建服務(wù)接口提供方第一步創(chuàng)建一個(gè)項(xiàng)目,在中引入第一步中構(gòu)建的包以及對和的依賴,比如第一步中構(gòu)建的包這里需要注意兩點(diǎn)必須包含包,不然啟動(dòng)會報(bào)錯(cuò)。 很早以前,在剛開始搞Spring Cloud基礎(chǔ)教程的時(shí)候,寫過這樣一篇文章:《微服務(wù)架構(gòu)的基礎(chǔ)框架選擇:Spring Cloud還是Dubbo?》,可能不少讀者也都看過。之后也就一...

    wpw 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<