This is an automated email from the ASF dual-hosted git repository.
iluo pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/incubator-dubbo-website.git
The following commit(s) were added to refs/heads/asf-site by this push:
new 4611086 Add Chinese blogs (#227)
4611086 is described below
commit 461108642b26fbde350afebef05909043c617ecb
Author: 小马哥 <[email protected]>
AuthorDate: Wed Jan 2 15:09:21 2019 +0800
Add Chinese blogs (#227)
---
blog/zh-cn/dubbo-annotation-driven.md | 809 +++++++++++++++++++++++++
blog/zh-cn/dubbo-externalized-configuration.md | 690 +++++++++++++++++++++
blog/zh-cn/dubbo-registry-nacos-integration.md | 555 +++++++++++++++++
img/blog/dubbo-registry-nacos-1.png | Bin 0 -> 188399 bytes
img/blog/dubbo-registry-nacos-2.png | Bin 0 -> 299453 bytes
img/blog/dubbo-registry-nacos-3.png | Bin 0 -> 229934 bytes
img/blog/dubbo-registry-nacos-4.png | Bin 0 -> 28984 bytes
img/blog/dubbo-registry-nacos-5.png | Bin 0 -> 28984 bytes
8 files changed, 2054 insertions(+)
diff --git a/blog/zh-cn/dubbo-annotation-driven.md
b/blog/zh-cn/dubbo-annotation-driven.md
new file mode 100644
index 0000000..5e0a988
--- /dev/null
+++ b/blog/zh-cn/dubbo-annotation-driven.md
@@ -0,0 +1,809 @@
+# Dubbo 注解驱动(Annotation-Driven)
+
+
+
+
+## 注解驱动(Annotation-Driven)
+
+
+
+
+
+### `@DubboComponentScan`
+
+
+
+
+
+#### 起始版本: `2.5.7`
+
+
+
+
+
+
+
+#### `<dubbo:annotation> `历史遗留问题
+
+
+
+
+
+##### 1. 注解支持不充分
+
+
+
+在 Dubbo `2.5.7`之前的版本 ,Dubbo 提供了两个核心注解 `@Service` 以及 `@Reference`,分别用于Dubbo
服务提供和 Dubbo 服务引用。
+
+
+
+其中,`@Service` 作为 XML 元素 `<dubbo:service>`的替代注解,与 Spring Framework
`@org.springframework.stereotype.Service` 类似,用于服务提供方 Dubbo
服务暴露。与之相对应的`@Reference`,则是替代`<dubbo:reference` 元素,类似于 Spring 中的 `@Autowired`。
+
+
+
+ `2.5.7` 之前的Dubbo,与早期的 Spring Framework 2.5 存在类似的不足,即注解支持不够充分。注解需要和 XML
配置文件配合使用,如下所示:
+
+```xml
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
+ xmlns="http://www.springframework.org/schema/beans"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+ http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
+
+ <dubbo:application name="annotation-provider"/>
+ <dubbo:registry address="127.0.0.1:4548"/>
+ <dubbo:annotation
package="com.alibaba.dubbo.config.spring.annotation.provider"/>
+
+</beans>
+```
+
+
+
+
+
+##### 2. `@Service` Bean 不支持 Spring AOP
+
+
+
+同时,使用 `<dubbo:annotation> ` 方式扫描后的Dubbo `@Service` ,在 Spring 代理方面存在问题,如 GitHub
上的 issue https://github.com/alibaba/dubbo/issues/794:
+
+> 关于dubbo @Service注解生成ServiceBean时, interface获取成spring 的代理对象的bug
+>
+> >在项目里, 我使用了
+> >
+> >```java
+> >@Service
+> >@Transactional
+> >@com.alibaba.dubbo.config.annotation.Service
+> >public class SUserJpushServiceImp
+> >```
+> >
+> >的形式, 来暴露服务。但是在发布服务的时候, interface class 是通过
+> >``
+> >serviceConfig.setInterface(bean.getClass().getInterfaces()[0]);
+> >``
+> >的形式获取, 刚好, 我的service都使用了@Transactional注解,
对象被代理了。所以获取到的interface是Spring的代理接口...
+
+
+
+不少热心的小伙伴不仅发现这个历史遗留问题,而且提出了一些修复方案。同时,为了更好地适配 Spring 生命周期以及将 Dubbo
完全向注解驱动编程模型过渡,因此,引入了全新 Dubbo 组件扫描注解 - `@DubboComponentScan`。
+
+
+
+> 注: `<dubbo:annotation> ` Spring AOP 问题将在 `2.5.9`
中修复:https://github.com/alibaba/dubbo/issues/1125
+
+
+
+
+
+##### 3. @Reference 不支持字段继承性
+
+
+
+假设有一个 Spring Bean `AnnotationAction` 直接通过字段`annotationService` 标记 `@Reference`
引用 `AnnotationService` :
+
+```java
+package com.alibaba.dubbo.examples.annotation.action;
+
+import com.alibaba.dubbo.config.annotation.Reference;
+import com.alibaba.dubbo.examples.annotation.api.AnnotationService;
+import org.springframework.stereotype.Component;
+
+
+@Component("annotationAction")
+public class AnnotationAction {
+
+ @Reference
+ private AnnotationService annotationService;
+
+ public String doSayHello(String name) {
+ return annotationService.sayHello(name);
+ }
+
+}
+```
+
+
+
+当`AnnotationAction` 被 XML 元素 `<dubbo:annotation>` 扫描后:
+
+```xml
+<dubbo:annotation package="com.alibaba.dubbo.examples.annotation.action"/>
+```
+
+
+
+字段 `annotationService` 能够引用到 `AnnotationService`,执行 `doSayHello` 方法能够正常返回。
+
+
+
+如果将字段`annotationService` 抽取到`AnnotationAction` 的父类`BaseAction`
后,`AnnotationService` 无法再被引用,改造如下所示:
+
+`AnnotationAction.java`
+
+```java
+@Component("annotationAction")
+public class AnnotationAction extends BaseAction {
+
+ public String doSayHello(String name) {
+ return getAnnotationService().sayHello(name);
+ }
+
+}
+```
+
+
+
+`BaseAction.java`
+
+```java
+public abstract class BaseAction {
+
+ @Reference
+ private AnnotationService annotationService;
+
+ protected AnnotationService getAnnotationService() {
+ return annotationService;
+ }
+}
+```
+
+
+
+改造后,再次执行 `doSayHello` 方法,`NullPointerException` 将会被抛出。说明`<dubbo:annotation>`
并不支持`@Reference` 字段继承性。
+
+
+
+了解了历史问题,集合整体愿景,下面介绍`@DubboComponentScan` 的设计原则。
+
+
+
+
+
+
+
+#### 设计原则
+
+
+
+
+
+Spring Framework 3.1 引入了新 Annotation - `@ComponentScan` , 完全替代了 XML 元素 `
<context:component-scan>` 。同样, `@DubboComponentScan` 作为 Dubbo `2.5.7` 新增的
Annotation,也是XML 元素 `<dubbo:annotation>` 的替代方案。
+
+
+
+在命名上(类名以及属性方法),为了简化使用和关联记忆,Dubbo 组件扫描 Annotation `@DubboComponentScan`,借鉴了
Spring Boot 1.3 引入的 `@ServletComponentScan`。定义如下:
+
+```java
+public @interface DubboComponentScan {
+
+ /**
+ * Alias for the {@link #basePackages()} attribute. Allows for more
concise annotation
+ * declarations e.g.: {@code @DubboComponentScan("org.my.pkg")} instead of
+ * {@code @DubboComponentScan(basePackages="org.my.pkg")}.
+ *
+ * @return the base packages to scan
+ */
+ String[] value() default {};
+
+ /**
+ * Base packages to scan for annotated @Service classes. {@link #value()}
is an
+ * alias for (and mutually exclusive with) this attribute.
+ * <p>
+ * Use {@link #basePackageClasses()} for a type-safe alternative to
String-based
+ * package names.
+ *
+ * @return the base packages to scan
+ */
+ String[] basePackages() default {};
+
+ /**
+ * Type-safe alternative to {@link #basePackages()} for specifying the
packages to
+ * scan for annotated @Service classes. The package of each class
specified will be
+ * scanned.
+ *
+ * @return classes from the base packages to scan
+ */
+ Class<?>[] basePackageClasses() default {};
+
+}
+```
+
+
+
+> 注意:`basePackages()` 和 `value()` 均能支持占位符(placeholder)指定的包名
+
+
+
+在职责上,`@DubboComponentScan` 相对于 Spring Boot `@ServletComponentScan` 更为繁重,原因在于处理
Dubbo `@Service` 类暴露 Dubbo 服务外,还有帮助 Spring Bean `@Reference`字段或者方法注入 Dubbo
服务代理。
+
+
+
+ 在场景上,Spring Framework `@ComponentScan` 组件扫描逻辑更为复杂。而在 `@DubboComponentScan`
只需关注 `@Service` 和 `@Reference` 处理。
+
+
+
+在功能上, `@DubboComponentScan` 不但需要提供完整 Spring AOP 支持的能力,而且还得具备`@Reference `
字段可继承性的能力。
+
+
+
+了解基本设计原则后,下面通过完整的示例,简介`@DubboComponentScan` 使用方法以及注意事项。
+
+
+
+
+
+
+
+#### 使用方法
+
+
+
+后续通过服务提供方(`@Serivce`)以及服务消费方(`@Reference`)两部分来介绍`@DubboComponentScan` 使用方法。
+
+
+
+假设,服务提供方和服务消费分均依赖服务接口`DemoService`:
+
+```java
+package com.alibaba.dubbo.demo;
+
+public interface DemoService {
+
+ String sayHello(String name);
+
+}
+```
+
+
+
+
+
+##### 服务提供方(`@Serivce`)
+
+
+
+###### 实现 `DemoService`
+
+
+
+服务提供方实现`DemoService` - `AnnotationDemoService` ,同时标注 Dubbo `@Service` :
+
+```java
+package com.alibaba.dubbo.demo.provider;
+
+import com.alibaba.dubbo.config.annotation.Service;
+import com.alibaba.dubbo.demo.DemoService;
+
+/**
+ * Annotation {@link DemoService} 实现
+ *
+ * @author <a href="mailto:[email protected]">Mercy</a>
+ */
+@Service
+public class AnnotationDemoService implements DemoService {
+
+ @Override
+ public String sayHello(String name) {
+ return "Hello , " + name;
+ }
+
+}
+```
+
+
+
+
+
+###### 服务提供方 Annotation 配置
+
+
+
+将 `AnnotationDemoService` 暴露成Dubbo 服务,需要依赖 Spring
Bean:`AplicationConfig`、`ProtocolConfig` 以及 `RegistryConfig` 。这三个 Spring Bean
过去可通过 XML 文件方式组装 Spring Bean:
+
+```xml
+<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
+ xmlns="http://www.springframework.org/schema/beans"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+ http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
+ ">
+
+ <!-- 当前应用信息配置 -->
+ <dubbo:application name="dubbo-annotation-provider"/>
+
+ <!-- 连接注册中心配置 -->
+ <dubbo:registry id="my-registry" address="N/A"/>
+
+ <dubbo:protocol name="dubbo" port="12345"/>
+
+</beans>
+```
+
+
+
+以上装配方式不予推荐,推荐使用 Annotation 配置,因此可以换成 Spring `@Configuration` Bean 的形式:
+
+```java
+package com.alibaba.dubbo.demo.config;
+
+import com.alibaba.dubbo.config.ApplicationConfig;
+import com.alibaba.dubbo.config.ProtocolConfig;
+import com.alibaba.dubbo.config.RegistryConfig;
+import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 服务提供方配置
+ *
+ * @author <a href="mailto:[email protected]">Mercy</a>
+ */
+@Configuration
+@DubboComponentScan("com.alibaba.dubbo.demo.provider") // 扫描 Dubbo 组件
+public class ProviderConfiguration {
+
+ /**
+ * 当前应用配置
+ */
+ @Bean("dubbo-annotation-provider")
+ public ApplicationConfig applicationConfig() {
+ ApplicationConfig applicationConfig = new ApplicationConfig();
+ applicationConfig.setName("dubbo-annotation-provider");
+ return applicationConfig;
+ }
+
+ /**
+ * 当前连接注册中心配置
+ */
+ @Bean("my-registry")
+ public RegistryConfig registryConfig() {
+ RegistryConfig registryConfig = new RegistryConfig();
+ registryConfig.setAddress("N/A");
+ return registryConfig;
+ }
+
+ /**
+ * 当前连接注册中心配置
+ */
+ @Bean("dubbo")
+ public ProtocolConfig protocolConfig() {
+ ProtocolConfig protocolConfig = new ProtocolConfig();
+ protocolConfig.setName("dubbo");
+ protocolConfig.setPort(12345);
+ return protocolConfig;
+ }
+}
+```
+
+
+
+
+
+###### 服务提供方引导类
+
+
+
+```java
+package com.alibaba.dubbo.demo.bootstrap;
+
+import com.alibaba.dubbo.demo.DemoService;
+import com.alibaba.dubbo.demo.config.ProviderConfiguration;
+import
org.springframework.context.annotation.AnnotationConfigApplicationContext;
+
+/**
+ * 服务提供方引导类
+ *
+ * @author <a href="mailto:[email protected]">Mercy</a>
+ */
+public class ProviderBootstrap {
+
+ public static void main(String[] args) {
+ // 创建 Annotation 配置上下文
+ AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext();
+ // 注册配置 Bean
+ context.register(ProviderConfiguration.class);
+ // 启动上下文
+ context.refresh();
+ // 获取 DemoService Bean
+ DemoService demoService = context.getBean(DemoService.class);
+ // 执行 sayHello 方法
+ String message = demoService.sayHello("World");
+ // 控制台输出信息
+ System.out.println(message);
+ }
+
+}
+```
+
+
+
+`ProviderBootstrap` 启动并执行后,控制输出与预期一致:
+
+```
+Hello , World
+```
+
+
+
+以上直接结果说明 `@DubboComponentScan("com.alibaba.dubbo.demo.provider")` 扫描后,标注 Dubbo
`@Service` 的 `AnnotationDemoService` 被注册成 Spring Bean,可从 Spring
ApplicationContext 自由获取。
+
+
+
+
+
+##### 服务消费方(`@Reference`)
+
+
+
+###### 服务 `DemoService`
+
+
+
+```java
+package com.alibaba.dubbo.demo.consumer;
+
+import com.alibaba.dubbo.config.annotation.Reference;
+import com.alibaba.dubbo.demo.DemoService;
+
+/**
+ * Annotation 驱动 {@link DemoService} 消费方
+ *
+ * @author <a href="mailto:[email protected]">Mercy</a>
+ */
+public class AnnotationDemoServiceConsumer {
+
+ @Reference(url = "dubbo://127.0.0.1:12345")
+ private DemoService demoService;
+
+ public String doSayHell(String name) {
+ return demoService.sayHello(name);
+ }
+}
+```
+
+
+
+
+
+###### 服务消费方 Annotation 配置
+
+
+
+与服务提供方配置类似,服务消费方也许 Dubbo 相关配置 Bean - `ConsumerConfiguration`
+
+```java
+package com.alibaba.dubbo.demo.config;
+
+import com.alibaba.dubbo.config.ApplicationConfig;
+import com.alibaba.dubbo.config.RegistryConfig;
+import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
+import com.alibaba.dubbo.demo.consumer.AnnotationDemoServiceConsumer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 服务消费方配置
+ *
+ * @author <a href="mailto:[email protected]">Mercy</a>
+ */
+@Configuration
+@DubboComponentScan
+public class ConsumerConfiguration {
+
+ /**
+ * 当前应用配置
+ */
+ @Bean
+ public ApplicationConfig applicationConfig() {
+ ApplicationConfig applicationConfig = new ApplicationConfig();
+ applicationConfig.setName("dubbo-annotation-consumer");
+ return applicationConfig;
+ }
+
+ /**
+ * 当前连接注册中心配置
+ */
+ @Bean
+ public RegistryConfig registryConfig() {
+ RegistryConfig registryConfig = new RegistryConfig();
+ registryConfig.setAddress("N/A");
+ return registryConfig;
+ }
+
+ /**
+ * 注册 AnnotationDemoServiceConsumer,@DubboComponentScan 将处理其中 @Reference
字段。
+ * 如果 AnnotationDemoServiceConsumer 非 Spring Bean 的话,
+ * 即使 @DubboComponentScan 指定 package 也不会进行处理,与 Spring @Autowired 同理
+ */
+ @Bean
+ public AnnotationDemoServiceConsumer annotationDemoServiceConsumer() {
+ return new AnnotationDemoServiceConsumer();
+ }
+
+}
+```
+
+
+
+###### 服务消费方引导类
+
+
+
+服务消费方需要先引导服务提供方,下面的实例将会启动两个 Spring 应用上下文,首先引导服务提供方 Spring
应用上下文,同时,需要复用前面Annotation 配置 `ProviderConfiguration`:
+
+```java
+ /**
+ * 启动服务提供方上下文
+ */
+ private static void startProviderContext() {
+ // 创建 Annotation 配置上下文
+ AnnotationConfigApplicationContext providerContext = new
AnnotationConfigApplicationContext();
+ // 注册配置 Bean
+ providerContext.register(ProviderConfiguration.class);
+ // 启动服务提供方上下文
+ providerContext.refresh();
+ }
+```
+
+
+
+然后引导服务消费方Spring 应用上下文:
+
+```java
+ /**
+ * 启动并且返回服务消费方上下文
+ *
+ * @return AnnotationConfigApplicationContext
+ */
+ private static ApplicationContext startConsumerContext() {
+ // 创建服务消费方 Annotation 配置上下文
+ AnnotationConfigApplicationContext consumerContext = new
AnnotationConfigApplicationContext();
+ // 注册服务消费方配置 Bean
+ consumerContext.register(ConsumerConfiguration.class);
+ // 启动服务消费方上下文
+ consumerContext.refresh();
+ // 返回服务消费方 Annotation 配置上下文
+ return consumerContext;
+ }
+```
+
+
+
+完整的引导类实现:
+
+```java
+package com.alibaba.dubbo.demo.bootstrap;
+
+import com.alibaba.dubbo.demo.config.ConsumerConfiguration;
+import com.alibaba.dubbo.demo.config.ProviderConfiguration;
+import com.alibaba.dubbo.demo.consumer.AnnotationDemoServiceConsumer;
+import org.springframework.context.ApplicationContext;
+import
org.springframework.context.annotation.AnnotationConfigApplicationContext;
+
+/**
+ * 服务消费端引导类
+ *
+ * @author <a href="mailto:[email protected]">Mercy</a>
+ */
+public class ConsumerBootstrap {
+
+ public static void main(String[] args) {
+ // 启动服务提供方上下文
+ startProviderContext();
+ // 启动并且返回服务消费方上下文
+ ApplicationContext consumerContext = startConsumerContext();
+ // 获取 AnnotationDemoServiceConsumer Bean
+ AnnotationDemoServiceConsumer consumer =
consumerContext.getBean(AnnotationDemoServiceConsumer.class);
+ // 执行 doSayHello 方法
+ String message = consumer.doSayHello("World");
+ // 输出执行结果
+ System.out.println(message);
+ }
+
+ /**
+ * 启动并且返回服务消费方上下文
+ *
+ * @return AnnotationConfigApplicationContext
+ */
+ private static ApplicationContext startConsumerContext() {
+ // 创建服务消费方 Annotation 配置上下文
+ AnnotationConfigApplicationContext consumerContext = new
AnnotationConfigApplicationContext();
+ // 注册服务消费方配置 Bean
+ consumerContext.register(ConsumerConfiguration.class);
+ // 启动服务消费方上下文
+ consumerContext.refresh();
+ // 返回服务消费方 Annotation 配置上下文
+ return consumerContext;
+ }
+
+ /**
+ * 启动服务提供方上下文
+ */
+ private static void startProviderContext() {
+ // 创建 Annotation 配置上下文
+ AnnotationConfigApplicationContext providerContext = new
AnnotationConfigApplicationContext();
+ // 注册配置 Bean
+ providerContext.register(ProviderConfiguration.class);
+ // 启动服务提供方上下文
+ providerContext.refresh();
+ }
+
+}
+```
+
+
+
+运行`ConsumerBootstrap`结果,仍然符合期望,`AnnotationDemoServiceConsumer` 输出:
+
+```
+Hello , World
+```
+
+
+
+
+
+
+
+#### Spring AOP 支持
+
+
+
+前面提到 `<dubbo:annotation> ` 注册 Dubbo `@Service` 组件后,在 Spring AOP 支持方面存在问题。事务作为
Spring AOP 的功能扩展,自然也会在 `<dubbo:annotation> `中不支持。
+
+
+
+`@DubboComponentScan` 针对以上问题,实现了对 Spring AOP 是完全兼容。将上述服务提供方 Annotation
配置做出一定的调整,标注`@EnableTransactionManagement` 以及自定义实现`PlatformTransactionManager` :
+
+```java
+@Configuration
+@DubboComponentScan("com.alibaba.dubbo.demo.provider") // 扫描 Dubbo 组件
+@EnableTransactionManagement // 激活事务管理
+public class ProviderConfiguration {
+ // 省略其他配置 Bean 定义
+
+ /**
+ * 自定义事务管理器
+ */
+ @Bean
+ @Primary
+ public PlatformTransactionManager transactionManager() {
+ return new PlatformTransactionManager() {
+
+ @Override
+ public TransactionStatus getTransaction(TransactionDefinition
definition) throws TransactionException {
+ System.out.println("get transaction ...");
+ return new SimpleTransactionStatus();
+ }
+
+ @Override
+ public void commit(TransactionStatus status) throws
TransactionException {
+ System.out.println("commit transaction ...");
+ }
+
+ @Override
+ public void rollback(TransactionStatus status) throws
TransactionException {
+ System.out.println("rollback transaction ...");
+ }
+ };
+ }
+}
+```
+
+
+
+同时调整 `AnnotationDemoService` - 增加`@Transactional` 注解:
+
+```java
+@Service
+@Transactional
+public class AnnotationDemoService implements DemoService {
+ // 省略实现,保持不变
+}
+```
+
+
+
+再次运行`ConsumerBootstrap` , 观察控制台输出内容:
+
+```
+get transaction ...
+commit transaction ...
+Hello , World
+```
+
+
+
+输入内容中多处了两行,说明自定义 `PlatformTransactionManager`
`getTransaction(TransactionDefinition)` 以及 `commit(TransactionStatus) `
方法被执行,进而说明 `AnnotationDemoService` 的`sayHello(String)` 方法执行时,事务也伴随执行。
+
+
+
+
+
+#### 注意事项
+
+
+
+`ConsumerConfiguration` 上的 `@DubboComponentScan` 并没有指定 `basePackages`
扫描,这种情况会将`ConsumerConfiguration` 当做 `basePackageClasses`
,即扫描`ConsumerConfiguration` 所属的 package `com.alibaba.dubbo.demo.config` 以及子
package。由于当前示例中,不存在标注 Dubbo `@Service`的类,因此在运行时日志(如果开启的话)会输出警告信息:
+
+```
+WARN : [DUBBO] No Spring Bean annotating Dubbo's @Service was found in Spring
BeanFactory, dubbo version: 2.0.0, current host: 127.0.0.1
+```
+
+
+
+以上信息大可不必担忧,因为 `@DubboComponentScan` 除了扫描 Dubbo `@Service` 组件以外,还将处理
`@Reference`字段注入。然而读者特别关注`@Reference`字段注入的规则。
+
+
+
+以上实现为例,`AnnotationDemoServiceConsumer` 必须申明为 Spring `@Bean` 或者
`@Component`(或者其派生注解),否则 `@DubboComponentScan` 不会主动将标注 `@Reference`字段所在的声明类提成为
Spring Bean,换句话说,如果 `@Reference`字段所在的声明类不是 Spring Bean 的话,
`@DubboComponentScan` 不会处理`@Reference`注入,其原理与 Spring `@Autowired` 一致。
+
+
+
+以上使用不当可能会导致相关问题,如 GitHub 上曾有小伙伴提问:https://github.com/alibaba/dubbo/issues/825
+
+> **li362692680** 提问:
+>
+> > @DubboComponentScan注解在消费端扫描包时扫描的是 @Service注解??不是@Reference注解??
+> > 启动时报
+> > DubboComponentScanRegistrar-85]-[main]-[INFO] 0 annotated @Service
Components { [] }
+>
+> 笔者(**mercyblitz**)回复:
+>
+> > `@Reference` 类似于 `@Autowired` 一样,首先其申明的类必须被 Spring 上下文当做一个Bean,因此,Dubbo
并没有直接将 `@Reference` 字段所在的类提升成 Bean。
+> >
+> > 综上所述,这并不是一个问题,而是用法不当!
+
+
+
+
+
+#### 已知问题
+
+
+
+最新发布的 Dubbo `2.5.8` 中,`@DubboComponentScan` 在以下特殊场景下存在 Spring `@Service`
不兼容情况:
+
+> 假设有两个服务实现类 `A` 和 `B`,同时存放在`com.acme` 包下:
+>
+> * `A` 标注 Dubbo `@Service`
+> * `B` 标注 Dubbo `@Service` 和 Spring `@Service`
+>
+> 当 Spring `@ComponentScan` 先扫描`com.acme` 包时,`B` 被当做 Spring Bean
的候选类。随后,`@DubboComponentScan` 也扫描相同的包。当应用启动时,`A` 和 `B` 虽然都是 Spring Bean,可仅
`A` 能够暴露 Dubbo 服务,`B` 则丢失。
+
+
+
+问题版本:`2.5.7`、`2.5.8`
+
+问题详情:https://github.com/alibaba/dubbo/issues/1120
+
+修复版本:`2.5.9`(下个版本)
+
+
+
+
+
+
+
diff --git a/blog/zh-cn/dubbo-externalized-configuration.md
b/blog/zh-cn/dubbo-externalized-configuration.md
new file mode 100644
index 0000000..1cd03d8
--- /dev/null
+++ b/blog/zh-cn/dubbo-externalized-configuration.md
@@ -0,0 +1,690 @@
+# Dubbo 外部化配置(Externalized Configuration)
+
+
+
+
+## 外部化配置(External Configuration)
+
+
+
+在[Dubbo 注解驱动](Dubbo-Annotation-Driven.md)例子中,无论是服务提供方,还是服务消费方,均需要转配相关配置Bean:
+
+```java
+ @Bean
+ public ApplicationConfig applicationConfig() {
+ ApplicationConfig applicationConfig = new ApplicationConfig();
+ applicationConfig.setName("dubbo-annotation-consumer");
+ return applicationConfig;
+ }
+```
+
+
+
+虽然实现类似于`ProviderConfiguration` 和 `ConsumerConfiguration` 这样的 Spring
`@Configuration` Bean 成本并不高,不过通过 Java Code 的方式定义配置 Bean,或多或少是一种 Hard
Code(硬编码)的行为,缺少弹性。
+
+
+
+尽管在 Spring 应用中,可以通过 `@Value` 或者 `Environment`
的方式获取外部配置,其代码简洁性以及类型转换灵活性存在明显的不足。因此,Spring Boot 提出了外部化配置(External
Configuration)的感念,即通过程序以外的配置源,动态地绑定指定类型。
+
+
+
+随着 Spring Boot / Spring Cloud 应用的流行,开发人员逐渐地接受并且使用 Spring Boot 外部化配置(External
Configuration),即通过 `application.properties` 或者 `bootstrap.properties` 装配配置 Bean。
+
+
+
+下列表格记录了 Dubbo 内置配置类:
+
+| 配置类 | 标签 | 用途 | 解释
|
+| ------------------- | ---------------------- | ------ |
---------------------------------------- |
+| `ProtocolConfig` | `<dubbo:protocol/>` | 协议配置 |
用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受 |
+| `ApplicationConfig` | `<dubbo:application/>` | 应用配置 |
用于配置当前应用信息,不管该应用是提供者还是消费者 |
+| `ModuleConfig` | `<dubbo:module/>` | 模块配置 | 用于配置当前模块信息,可选
|
+| `RegistryConfig` | `<dubbo:registry/>` | 注册中心配置 | 用于配置连接注册中心相关信息
|
+| `MonitorConfig` | `<dubbo:monitor/>` | 监控中心配置 | 用于配置连接监控中心相关信息,可选
|
+| `ProviderConfig` | `<dubbo:provider/>` | 提供方配置 | 当 ProtocolConfig 和
ServiceConfig 某属性没有配置时,采用此缺省值,可选 |
+| `ConsumerConfig` | `<dubbo:consumer/>` | 消费方配置 | 当 ReferenceConfig
某属性没有配置时,采用此缺省值,可选 |
+| `MethodConfig` | `<dubbo:method/>` | 方法配置 | 用于 ServiceConfig 和
ReferenceConfig 指定方法级的配置信息 |
+| `ArgumentConfig` | `<dubbo:argument/>` | 参数配置 | 用于指定方法参数配置
|
+
+
+
+通过申明对应的 Spring 扩展标签,在 Spring 应用上下文中将自动生成相应的配置 Bean。
+
+
+
+在 Dubbo
官方用户手册的[“属性配置”](http://dubbo.io/books/dubbo-user-book/configuration/properties.html)章节中,`dubbo.properties`
配置属性能够映射到 `ApplicationConfig` 、`ProtocolConfig` 以及 `RegistryConfig`
的字段。从某种意义上来说,`dubbo.properties` 也是 Dubbo 的外部化配置。
+
+
+
+其中,引用“映射规则”的内容:
+
+>## 映射规则
+>
+>将 XML 配置的标签名,加属性名,用点分隔,多个属性拆成多行
+>
+>* 比如:`dubbo.application.name=foo`等价于`<dubbo:application name="foo" />`
+>*
比如:`dubbo.registry.address=10.20.153.10:9090`等价于`<dubbo:registryaddress="10.20.153.10:9090"
/>`
+>
+>如果 XML 有多行同名标签配置,可用 id 号区分,如果没有 id 号将对所有同名标签生效
+>
+>* 比如:`dubbo.protocol.rmi.port=1234`等价于`<dubbo:protocol id="rmi" name="rmi"
port="1099"
/>`[2](http://dubbo.io/books/dubbo-user-book/configuration/properties.html#fn_2)
+>* 比如:`dubbo.registry.china.address=10.20.153.10:9090`等价于`<dubbo:registry
id="china"address="10.20.153.10:9090" />`
+>
+>下面是 dubbo.properties 的一个典型配置:
+>
+>```
+>dubbo.application.name=foo
+>dubbo.application.owner=bar
+>dubbo.registry.address=10.20.153.10:9090
+>```
+
+
+
+根据“映射规则”,Dubbo 即支持单配置 Bean 映射,也支持多 Bean 映射。综合以上需求,既要兼容 Dubbo 已有的一个或多个 Bean
字段映射绑定,也支持外部化配置。
+
+> 特别提醒:外部化配置(External Configuration)并非 Spring Boot 特有,即使在 Spring Framework
场景下亦能支持。也就是说 Dubbo 外部化配置即可在 Spring Framework 中工作,也能在 Spring Boot 中运行。
+
+
+
+Dubbo 外部化配置(External Configuration) 支持起始版本为:`2.5.8`
+
+
+
+
+
+### `@EnableDubboConfig`
+
+
+
+#### 起始版本:`2.5.8`
+
+
+
+#### 使用说明
+
+
+
+##### `@EnableDubboConfig` 定义
+
+```java
+public @interface EnableDubboConfig {
+
+ /**
+ * It indicates whether binding to multiple Spring Beans.
+ *
+ * @return the default value is <code>false</code>
+ * @revised 2.5.9
+ */
+ boolean multiple() default false;
+
+}
+```
+
+
+
+* `multiple` : 表示是否支持多Dubbo 配置 Bean 绑定。默认值为 `false` ,即单 Dubbo 配置 Bean 绑定
+
+
+
+##### 单 Dubbo 配置 Bean 绑定
+
+
+
+为了更好地向下兼容,`@EnableDubboConfig` 提供外部化配置属性与 Dubbo 配置类之间的绑定,其中映射关系如下:
+
+| 配置类 | 外部化配置属性前缀 | 用途 |
+| ------------------- | ------------------- | ------ |
+| `ProtocolConfig` | `dubbo.protocol` | 协议配置 |
+| `ApplicationConfig` | `dubbo.application` | 应用配置 |
+| `ModuleConfig` | `dubbo.module` | 模块配置 |
+| `RegistryConfig` | `dubbo.registry` | 注册中心配置 |
+| `MonitorConfig` | `dubbo.monitor` | 监控中心配置 |
+| `ProviderConfig` | `dubbo.provider` | 提供方配置 |
+| `ConsumerConfig` | `dubbo.consumer` | 消费方配置 |
+
+
+
+当标注 `@EnableDubboConfig` 的类被扫描注册后,同时 Spring(Spring
Boot)应用配置(`PropertySources`)中存在`dubbo.application.*` 时,`ApplicationConfig`
Bean 将被注册到在 Spring 上下文。否则,不会被注册。如果出现`dubbo.registry.*`的配置,那么,`RegistryConfig`
Bean 将会创建,以此类推。即按需装配 Dubbo 配置 Bean。
+
+
+
+如果需要指定配置 Bean的 id,可通过`**.id` 属性设置,以`dubbo.application` 为例:
+
+```properties
+## application
+dubbo.application.id = applicationBean
+dubbo.application.name = dubbo-demo-application
+```
+
+
+
+以上配置等同于以下 Java Config Bean:
+
+```java
+ @Bean("applicationBean")
+ public ApplicationConfig applicationBean() {
+ ApplicationConfig applicationConfig = new ApplicationConfig();
+ applicationConfig.setName("dubbo-demo-application");
+ return applicationConfig;
+ }
+```
+
+
+
+大致上配置属性与配置类绑定模式 - `dubbo.application.* ` 映射到 `ApplicationConfig` 中的字段。
+
+> 注:当配置属性名称无法在配置类中找到字段时,将会忽略绑定
+
+
+
+
+
+##### 多 Dubbo 配置 Bean 绑定
+
+
+
+Dubbo `@Service` 和 `@Reference` 允许 Dubbo 应用关联`ApplicationConfig` Bean
或者指定多个`RegistryConfig` Bean 等能力。换句话说,Dubbo 应用上下文中可能存在多个`ApplicationConfig` 等
Bean定义。
+
+
+
+为了适应以上需要,因此从Dubbo `2.5.9` 开始,`@EnableDubboConfig` 支持多 Dubbo 配置 Bean
绑定,同时按照业界规约标准,与单 Dubbo 配置 Bean 绑定约定不同,配置属性前缀均为英文复数形式:
+
+> 详情请参考 :https://github.com/alibaba/dubbo/issues/1141
+
+
+
+* `dubbo.applications`
+* `dubbo.modules`
+* `dubbo.registries`
+* `dubbo.protocols`
+* `dubbo.monitors`
+* `dubbo.providers`
+* `dubbo.consumers`
+
+
+
+以`dubbo.applications` 为例,基本的模式如下:
+
+```properties
+dubbo.applications.${bean-name}.property-name = ${property-value}
+```
+
+
+
+请读者注意,在单 Dubbo 配置 Bean 绑定时,可以通过指定`id` 属性的方式,定义`ApplicationConfig` Bean
的ID,即`dubbo.application.id`。
+
+而在多 Dubbo 配置 Bean 绑定时,Bean ID
则由`dubbo.applications.`与属性字段名称(`.property-name`)之间的字符来表达。
+
+
+
+如下配置:
+
+```properties
+# multiple Bean definition
+dubbo.applications.applicationBean.name = dubbo-demo-application
+dubbo.applications.applicationBean2.name = dubbo-demo-application2
+dubbo.applications.applicationBean3.name = dubbo-demo-application3
+```
+
+
+
+该配置内容中,绑定了三个`ApplicationConfig`
Bean,分别是`applicationBean`、`applicationBean2`以及`applicationBean3`
+
+
+
+#### 示例说明
+
+
+
+`@EnableDubboConfig` 的使用方法很简答, 再次强调一点,当规约的外部配置存在时,相应的 Dubbo 配置类 才会提升为 Spring
Bean。简言之,按需装配。
+
+
+
+
+
+##### 单 Dubbo 配置 Bean 绑定
+
+
+
+###### 外部化配置文件
+
+
+
+将以下内容的外部化配置文件物理路径为:`classpath:/META-INF/config.properties`:
+
+```properties
+# 单 Dubbo 配置 Bean 绑定
+## application
+dubbo.application.id = applicationBean
+dubbo.application.name = dubbo-demo-application
+
+## module
+dubbo.module.id = moduleBean
+dubbo.module.name = dubbo-demo-module
+
+## registry
+dubbo.registry.address = zookeeper://192.168.99.100:32770
+
+## protocol
+dubbo.protocol.name = dubbo
+dubbo.protocol.port = 20880
+
+## monitor
+dubbo.monitor.address = zookeeper://127.0.0.1:32770
+
+## provider
+dubbo.provider.host = 127.0.0.1
+
+## consumer
+dubbo.consumer.client = netty
+```
+
+
+
+###### `@EnableDubboConfig` 配置 Bean
+
+
+
+```java
+/**
+ * Dubbo 配置 Bean
+ *
+ * @author <a href="mailto:[email protected]">Mercy</a>
+ */
+@EnableDubboConfig
+@PropertySource("META-INF/config.properties")
+@Configuration
+public class DubboConfiguration {
+
+}
+```
+
+
+
+###### 实现引导类
+
+
+
+```java
+/**
+ * Dubbo 配置引导类
+ *
+ * @author <a href="mailto:[email protected]">Mercy</a>
+ */
+public class DubboConfigurationBootstrap {
+
+ public static void main(String[] args) {
+ // 创建配置上下文
+ AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext();
+ // 注册当前配置 Bean
+ context.register(DubboConfiguration.class);
+ context.refresh();
+ // application
+ ApplicationConfig applicationConfig =
context.getBean("applicationBean", ApplicationConfig.class);
+ System.out.printf("applicationBean.name = %s \n",
applicationConfig.getName());
+
+ // module
+ ModuleConfig moduleConfig = context.getBean("moduleBean",
ModuleConfig.class);
+ System.out.printf("moduleBean.name = %s \n", moduleConfig.getName());
+
+ // registry
+ RegistryConfig registryConfig = context.getBean(RegistryConfig.class);
+ System.out.printf("registryConfig.name = %s \n",
registryConfig.getAddress());
+
+ // protocol
+ ProtocolConfig protocolConfig = context.getBean(ProtocolConfig.class);
+ System.out.printf("protocolConfig.name = %s \n",
protocolConfig.getName());
+ System.out.printf("protocolConfig.port = %s \n",
protocolConfig.getPort());
+
+ // monitor
+ MonitorConfig monitorConfig = context.getBean(MonitorConfig.class);
+ System.out.printf("monitorConfig.name = %s \n",
monitorConfig.getAddress());
+
+ // provider
+ ProviderConfig providerConfig = context.getBean(ProviderConfig.class);
+ System.out.printf("providerConfig.name = %s \n",
providerConfig.getHost());
+
+ // consumer
+ ConsumerConfig consumerConfig = context.getBean(ConsumerConfig.class);
+ System.out.printf("consumerConfig.name = %s \n",
consumerConfig.getClient());
+ }
+}
+```
+
+
+
+###### 执行结果
+
+
+
+```
+applicationBean.name = dubbo-demo-application
+moduleBean.name = dubbo-demo-module
+registryConfig.name = zookeeper://192.168.99.100:32770
+protocolConfig.name = dubbo
+protocolConfig.port = 20880
+monitorConfig.name = zookeeper://127.0.0.1:32770
+providerConfig.name = 127.0.0.1
+consumerConfig.name = netty
+```
+
+
+
+不难发现,`@EnableDubboConfig` 配置 Bean 配合外部化文件
`classpath:/META-INF/config.properties`,与执行输出内容相同。
+
+
+
+
+
+##### 多 Dubbo 配置 Bean 绑定
+
+
+
+###### 外部化配置文件
+
+
+
+将以下内容的外部化配置文件物理路径为:`classpath:/META-INF/multiple-config.properties`:
+
+```properties
+# 多 Dubbo 配置 Bean 绑定
+## dubbo.applications
+dubbo.applications.applicationBean.name = dubbo-demo-application
+dubbo.applications.applicationBean2.name = dubbo-demo-application2
+dubbo.applications.applicationBean3.name = dubbo-demo-application3
+```
+
+
+
+###### `@EnableDubboConfig` 配置 Bean(多)
+
+
+
+```java
+@EnableDubboConfig(multiple = true)
+@PropertySource("META-INF/multiple-config.properties")
+private static class DubboMultipleConfiguration {
+
+}
+```
+
+
+
+###### 实现引导类
+
+
+
+```java
+/**
+ * Dubbo 配置引导类
+ *
+ * @author <a href="mailto:[email protected]">Mercy</a>
+ */
+public class DubboConfigurationBootstrap {
+ public static void main(String[] args) {
+ // 创建配置上下文
+ AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext();
+ // 注册当前配置 Bean
+ context.register(DubboMultipleConfiguration.class);
+ context.refresh();
+
+ // 获取 ApplicationConfig Bean:"applicationBean"、"applicationBean2" 和
"applicationBean3"
+ ApplicationConfig applicationBean = context.getBean("applicationBean",
ApplicationConfig.class);
+ ApplicationConfig applicationBean2 =
context.getBean("applicationBean2", ApplicationConfig.class);
+ ApplicationConfig applicationBean3 =
context.getBean("applicationBean3", ApplicationConfig.class);
+
+ System.out.printf("applicationBean.name = %s \n",
applicationBean.getName());
+ System.out.printf("applicationBean2.name = %s \n",
applicationBean2.getName());
+ System.out.printf("applicationBean3.name = %s \n",
applicationBean3.getName());
+ }
+}
+```
+
+
+
+###### 执行结果
+
+
+
+```
+applicationBean.name = dubbo-demo-application
+applicationBean2.name = dubbo-demo-application2
+applicationBean3.name = dubbo-demo-application3
+```
+
+
+
+`@EnableDubboConfig(multiple = true)` 执行后,运行结果说明`ApplicationConfig` Bean 以及 ID
的定义方式。
+
+
+
+
+
+### `@EnableDubboConfigBinding` & `@EnableDubboConfigBindings`
+
+
+
+`@EnableDubboConfig`适合绝大多数外部化配置场景,然而无论是单 Bean 绑定,还是多 Bean
绑定,其**外部化配置属性前缀**是固化的,如`dubbo.application` 以及 `dubbo.applications` 。
+
+
+
+当应用需要自定义**外部化配置属性前缀**,`@EnableDubboConfigBinding`能提供更大的弹性,支持单个外部化配置属性前缀(`prefix`)
与 Dubbo 配置 Bean 类型(`AbstractConfig`
子类)绑定,如果需要多次绑定时,可使用`@EnableDubboConfigBindings`。
+
+> 尽管 Dubbo 推荐使用 Java 8 ,然而实际的情况,运行时的 JDK 的版本可能从 6到8
均有。因此,`@EnableDubboConfigBinding`
没有实现`java.lang.annotation.Repeatable`,即允许实现类不支持重复标注`@EnableDubboConfigBinding`。
+
+
+
+`@EnableDubboConfigBinding` 在支持外部化配置属性与 Dubbo 配置类绑定时,与 Dubbo 过去的映射行为不同,被绑定的
Dubbo 配置类将会提升为 Spring Bean,无需提前装配 Dubbo 配置类。同时,支持多 Dubbo 配置Bean 装配。其 Bean
的绑定规则与`@EnableDubboConfig`一致。
+
+
+
+#### 起始版本: `2.5.8`
+
+
+
+#### 使用说明
+
+
+
+##### `@EnableDubboConfigBinding` 定义
+
+
+
+```java
+public @interface EnableDubboConfigBinding {
+
+ /**
+ * The name prefix of the properties that are valid to bind to {@link
AbstractConfig Dubbo Config}.
+ *
+ * @return the name prefix of the properties to bind
+ */
+ String prefix();
+
+ /**
+ * @return The binding type of {@link AbstractConfig Dubbo Config}.
+ * @see AbstractConfig
+ * @see ApplicationConfig
+ * @see ModuleConfig
+ * @see RegistryConfig
+ */
+ Class<? extends AbstractConfig> type();
+
+ /**
+ * It indicates whether {@link #prefix()} binding to multiple Spring Beans.
+ *
+ * @return the default value is <code>false</code>
+ */
+ boolean multiple() default false;
+
+}
+```
+
+
+
+* `prefix()` : 指定待绑定 Dubbo 配置类的外部化配置属性的前缀,比如`dubbo.application` 为
`ApplicationConfig` 的外部化配置属性的前缀。`prefix()` 支持占位符(Placeholder), 并且其关联前缀值是否以"."
作为结尾字符是可选的,即`prefix() = "dubbo.application"` 与 `prefix() =
"dubbo.application."` 效果相同
+* `type()` : 指定 Dubbo 配置类,所有 `AbstractConfig` 的实现子类即可,如`ApplicationConfig`
、`RegistryConfig` 以及 `ProtocolConfig` 等
+* `multiple()` : 表明是否需要将`prefix()` 作为多个 `type()` 类型的 Spring Bean
外部化配置属性。默认值为`false`,即默认支持单个类型的 Spring 配置 Bean
+
+
+
+
+假设标注 `@EnableDubboConfigBinding` 的实现类被 Spring 应用上下文扫描并且注册后,其中`prefix()` =
`dubbo.app` 、 `type()` = `ApplicationConfig.class` ,且外部配置内容为:
+
+```properties
+dubbo.app.id = applicationBean
+dubbo.app.name = dubbo-demo-application
+```
+
+
+
+Spring 应用上下文启动后,一个 ID 为 "applicationBean" 的 `ApplicationConfig` Bean 被初始化,其
`name` 字段被设置为 "dubbo-demo-application"。
+
+
+
+##### `EnableDubboConfigBindings` 定义
+
+
+
+```java
+public @interface EnableDubboConfigBindings {
+
+ /**
+ * The value of {@link EnableDubboConfigBindings}
+ *
+ * @return non-null
+ */
+ EnableDubboConfigBinding[] value();
+
+}
+```
+
+
+
+* `value` : 指定多个`EnableDubboConfigBinding`,用于实现外部化配置属性前缀(`prefix`) 与 Dubbo 配置
Bean 类型(`AbstractConfig` 子类)绑定。
+
+
+
+#### 示例说明
+
+
+
+##### 外部化配置文件
+
+
+
+将以下内容的外部化配置文件物理路径为:`classpath:/META-INF/bindings.properties`
+
+```properties
+# classpath:/META-INF/bindings.properties
+## 占位符值 : ApplicationConfig 外部配置属性前缀
+applications.prefix = dubbo.apps.
+
+## 多 ApplicationConfig Bean 绑定
+dubbo.apps.applicationBean.name = dubbo-demo-application
+dubbo.apps.applicationBean2.name = dubbo-demo-application2
+dubbo.apps.applicationBean3.name = dubbo-demo-application3
+
+## 单 ModuleConfig Bean 绑定
+dubbo.module.id = moduleBean
+dubbo.module.name = dubbo-demo-module
+
+## 单 RegistryConfig Bean 绑定
+dubbo.registry.address = zookeeper://192.168.99.100:32770
+```
+
+
+
+
+
+##### `EnableDubboConfigBindings` 配置 Bean
+
+
+
+`DubboConfiguration` 作为 Dubbo 配置 Bean,除通过 `@EnableDubboConfigBinding` 绑定之外,还需要
`@PropertySource` 指定外部化配置文件(`classpath:/META-INF/bindings.properties`):
+
+```java
+/**
+ * Dubbo 配置 Bean
+ *
+ * @author <a href="mailto:[email protected]">Mercy</a>
+ */
+@EnableDubboConfigBindings({
+ @EnableDubboConfigBinding(prefix = "${applications.prefix}",
+ type = ApplicationConfig.class, multiple = true), // 多
ApplicationConfig Bean 绑定
+ @EnableDubboConfigBinding(prefix = "dubbo.module", // 不带 "." 后缀
+ type = ModuleConfig.class), // 单 ModuleConfig Bean 绑定
+ @EnableDubboConfigBinding(prefix = "dubbo.registry.", // 带 "." 后缀
+ type = RegistryConfig.class) // 单 RegistryConfig Bean 绑定
+})
+@PropertySource("META-INF/bindings.properties")
+@Configuration
+public class DubboConfiguration {
+
+}
+```
+
+
+
+
+
+##### 实现引导类
+
+
+
+通过之前的使用说明,当 `EnableDubboConfigBinding`
将外部配置化文件`classpath:/META-INF/dubbo.properties` 绑定到 `ApplicationConfig`后,其中
Spring Bean "applicationBean" 的 name 字段被设置成 "dubbo-demo-application"。同时,
`EnableDubboConfigBinding` 所标注的 `DubboConfiguration` 需要被 Sring 应用上下文注册:
+
+```java
+/**
+ * Dubbo 配置引导类
+ *
+ * @author <a href="mailto:[email protected]">Mercy</a>
+ */
+public class DubboConfigurationBootstrap {
+
+ public static void main(String[] args) {
+ // 创建配置上下文
+ AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext();
+ // 注册当前配置 Bean
+ context.register(DubboConfiguration.class);
+ context.refresh();
+ // 获取 ApplicationConfig
Bean:"applicationBean"、"applicationBean2" 和 "applicationBean3"
+ ApplicationConfig applicationBean = context.getBean("applicationBean",
ApplicationConfig.class);
+ ApplicationConfig applicationBean2 =
context.getBean("applicationBean2", ApplicationConfig.class);
+ ApplicationConfig applicationBean3 =
context.getBean("applicationBean3", ApplicationConfig.class);
+
+ System.out.printf("applicationBean.name = %s \n",
applicationBean.getName());
+ System.out.printf("applicationBean2.name = %s \n",
applicationBean2.getName());
+ System.out.printf("applicationBean3.name = %s \n",
applicationBean3.getName());
+
+ // 获取 ModuleConfig Bean:"moduleBean"
+ ModuleConfig moduleBean = context.getBean("moduleBean",
ModuleConfig.class);
+
+ System.out.printf("moduleBean.name = %s \n", moduleBean.getName());
+
+ // 获取 RegistryConfig Bean
+ RegistryConfig registry = context.getBean(RegistryConfig.class);
+
+ System.out.printf("registry.address = %s \n", registry.getAddress());
+ }
+}
+```
+
+
+
+##### 运行结果
+
+
+
+`DubboConfigurationBootstrap` 运行后控制台输出:
+
+```
+applicationBean.name = dubbo-demo-application
+applicationBean2.name = dubbo-demo-application2
+applicationBean3.name = dubbo-demo-application3
+moduleBean.name = dubbo-demo-module
+registry.address = zookeeper://192.168.99.100:32770
+```
+
+
+
+输出的内容与`classpath:/META-INF/bindings.properties` 绑定的内容一致,符合期望。
diff --git a/blog/zh-cn/dubbo-registry-nacos-integration.md
b/blog/zh-cn/dubbo-registry-nacos-integration.md
new file mode 100644
index 0000000..9eee7d0
--- /dev/null
+++ b/blog/zh-cn/dubbo-registry-nacos-integration.md
@@ -0,0 +1,555 @@
+# Dubbo 融合 Nacos 成为注册中心
+
+Nacos 作为 Dubbo 生态系统中重要的注册中心实现,其中
[`dubbo-registry-nacos`](https://github.com/dubbo/dubbo-registry-nacos) 则是
Dubbo 融合 Nacos 注册中心的实现。
+
+
+
+## 预备工作
+
+当您将 [`dubbo-registry-nacos`](https://github.com/dubbo/dubbo-registry-nacos)
整合到您的 Dubbo 工程之前,请确保后台已经启动 Nacos 服务。如果您尚且不熟悉 Nacos 的基本使用的话,可先行参考 [Nacos
快速入门](https://nacos.io/en-us/docs/quick-start.html):https://nacos.io/en-us/docs/quick-start.html。建议使用
Nacos `0.6.1` 以上的版本。
+
+
+
+## 快速上手
+
+Dubbo 融合 Nacos 成为注册中心的操作步骤非常简单,大致步骤可分为“增加 Maven 依赖”以及“配置注册中心“。
+
+
+
+### 增加 Maven 依赖
+
+首先,您需要 `dubbo-registry-nacos` 的 Maven 依赖添加到您的项目中 `pom.xml` 文件中,并且强烈地推荐您使用
Dubbo `2.6.5`:
+
+```xml
+<dependencies>
+
+ ...
+
+ <!-- Dubbo Nacos registry dependency -->
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>dubbo-registry-nacos</artifactId>
+ <version>0.0.2</version>
+ </dependency>
+
+ <!-- Keep latest Nacos client version -->
+ <dependency>
+ <groupId>com.alibaba.nacos</groupId>
+ <artifactId>nacos-client</artifactId>
+ <version>[0.6.1,)</version>
+ </dependency>
+
+ <!-- Dubbo dependency -->
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>dubbo</artifactId>
+ <version>2.6.5</version>
+ </dependency>
+
+ <!-- Alibaba Spring Context extension -->
+ <dependency>
+ <groupId>com.alibaba.spring</groupId>
+ <artifactId>spring-context-support</artifactId>
+ <version>1.0.2</version>
+ </dependency>
+
+ ...
+
+</dependencies>
+```
+
+
+
+当项目中添加 `dubbo-registry-nacos` 后,您无需显示地编程实现服务发现和注册逻辑,实际实现由该三方包提供,接下来配置 Naocs
注册中心。
+
+
+
+### 配置注册中心
+
+假设您 Dubbo 应用使用 Spring Framework 装配,将有两种配置方法可选,分别为:[Dubbo Spring
外部化配置](https://mercyblitz.github.io/2018/01/18/Dubbo-%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE/)以及
Spring XML 配置文件以及 ,笔者强烈推荐前者。
+
+
+
+### [Dubbo Spring
外部化配置](https://mercyblitz.github.io/2018/01/18/Dubbo-%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE/)
+
+Dubbo Spring 外部化配置是由 Dubbo `2.5.8` 引入的新特性,可通过 Spring `Environment` 属性自动地生成并绑定
Dubbo 配置 Bean,实现配置简化,并且降低微服务开发门槛。
+
+假设您 Dubbo 应用的使用 Zookeeper 作为注册中心,并且其服务器 IP 地址为:`10.20.153.10`,同时,该注册地址作为 Dubbo
外部化配置属性存储在 `dubbo-config.properties` 文件,如下所示:
+
+```properties
+## application
+dubbo.application.name = your-dubbo-application
+
+## Zookeeper registry address
+dubbo.registry.address = zookeeper://10.20.153.10:2181
+...
+```
+
+
+
+假设您的 Nacos Server 同样运行在服务器 `10.20.153.10` 上,并使用默认 Nacos 服务端口 `8848`,您只需将
`dubbo.registry.address` 属性调整如下:
+
+
+
+```properties
+## 其他属性保持不变
+
+## Nacos registry address
+dubbo.registry.address = nacos://10.20.153.10:8848
+...
+```
+
+
+
+随后,重启您的 Dubbo 应用,Dubbo 的服务提供和消费信息在 Nacos 控制台中可以显示:
+
+
+
+
+
+如图所示,服务名前缀为 `providers:` 的信息为服务提供者的元信息,`consumers:`
则代表服务消费者的元信息。点击“**详情**”可查看服务状态详情:
+
+
+
+
+
+如果您正在使用 Spring XML 配置文件装配 Dubbo 注册中心的话,请参考下一节。
+
+
+
+### Spring XML 配置文件
+
+同样,假设您 Dubbo 应用的使用 Zookeeper 作为注册中心,并且其服务器 IP 地址为:`10.20.153.10`,并且装配 Spring
Bean 在 XML 文件中,如下所示:
+
+```xml
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
+
+ <!-- 提供方应用信息,用于计算依赖关系 -->
+ <dubbo:application name="dubbo-provider-xml-demo" />
+
+ <!-- 使用 Zookeeper 注册中心 -->
+ <dubbo:registry address="zookeeper://10.20.153.10:2181" />
+ ...
+</beans>
+```
+
+
+
+与 [Dubbo Spring
外部化配置](https://mercyblitz.github.io/2018/01/18/Dubbo-%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE/)
配置类似,只需要调整 `address` 属性配置即可:
+
+```xml
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
+
+ <!-- 提供方应用信息,用于计算依赖关系 -->
+ <dubbo:application name="dubbo-provider-xml-demo" />
+
+ <!-- 使用 Nacos 注册中心 -->
+ <dubbo:registry address="nacos://10.20.153.10:8848" />
+ ...
+</beans>
+```
+
+
+
+重启 Dubbo 应用后,您同样也能发现服务提供方和消费方的注册元信息呈现在 Nacos 控制台中:
+
+
+
+
+
+您是否绝对配置或切换 Nacos 注册中心超级 Easy 呢?如果您仍旧意犹未尽或者不甚明白的话,可参考以下完整的示例。
+
+
+
+## 完整示例
+
+以上图片中的元数据源于 Dubbo Spring 注解驱动示例以及 Dubbo Spring XML
配置驱动示例,下面将分别介绍两者,您可以选择自己偏好的编程模型。在正式讨论之前,先来介绍两者的预备工作,因为它们皆依赖 Java
服务接口和实现。同时,**请确保本地(`127.0.0.1`)环境已启动 Nacos 服务**。
+
+
+
+### 示例接口与实现
+
+
+
+首先定义示例接口,如下所示:
+
+```java
+package com.alibaba.dubbo.demo.service;
+
+/**
+ * DemoService
+ *
+ * @since 2.6.5
+ */
+public interface DemoService {
+
+ String sayName(String name);
+
+}
+```
+
+
+
+提供以上接口的实现类:
+
+```java
+package com.alibaba.dubbo.demo.service;
+
+import com.alibaba.dubbo.config.annotation.Service;
+import com.alibaba.dubbo.rpc.RpcContext;
+
+import org.springframework.beans.factory.annotation.Value;
+
+/**
+ * Default {@link DemoService}
+ *
+ * @since 2.6.5
+ */
+@Service(version = "${demo.service.version}")
+public class DefaultService implements DemoService {
+
+ @Value("${demo.service.name}")
+ private String serviceName;
+
+ public String sayName(String name) {
+ RpcContext rpcContext = RpcContext.getContext();
+ return String.format("Service [name :%s , port : %d] %s(\"%s\") :
Hello,%s",
+ serviceName,
+ rpcContext.getLocalPort(),
+ rpcContext.getMethodName(),
+ name,
+ name);
+ }
+}
+```
+
+
+
+接口与实现准备妥当后,下面将采用注解驱动和 XML 配置驱动各自实现。
+
+
+
+### Spring 注解驱动示例
+
+ Dubbo `2.5.7` 重构了 Spring 注解驱动的编程模型。
+
+
+
+#### 服务提供方注解驱动实现
+
+- 定义 Dubbo 提供方外部化配置属性源 - `provider-config.properties`
+
+```properties
+## application
+dubbo.application.name = dubbo-provider-demo
+
+## Nacos registry address
+dubbo.registry.address = nacos://127.0.0.1:8848
+
+## Dubbo Protocol
+dubbo.protocol.name = dubbo
+dubbo.protocol.port = -1
+
+# Provider @Service version
+demo.service.version=1.0.0
+demo.service.name = demoService
+```
+
+
+
+- 实现服务提供方引导类 - `DemoServiceProviderBootstrap`
+
+```java
+package com.alibaba.dubbo.demo.provider;
+
+import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
+import com.alibaba.dubbo.demo.service.DemoService;
+
+import
org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.PropertySource;
+
+import java.io.IOException;
+
+/**
+ * {@link DemoService} provider demo
+ */
+@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.demo.service")
+@PropertySource(value = "classpath:/provider-config.properties")
+public class DemoServiceProviderBootstrap {
+
+ public static void main(String[] args) throws IOException {
+ AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext();
+ context.register(DemoServiceProviderBootstrap.class);
+ context.refresh();
+ System.out.println("DemoService provider is starting...");
+ System.in.read();
+ }
+}
+
+```
+
+其中注解 `@EnableDubbo` 激活 Dubbo 注解驱动以及外部化配置,其 `scanBasePackages` 属性扫描指定 Java
包,将所有标注 `@Service` 的服务接口实现类暴露为 Spring Bean,随即被导出 Dubbo 服务。
+
+ `@PropertySource` 是 Spring Framework 3.1 引入的标准导入属性配置资源注解,它将为 Dubbo 提供外部化配置。
+
+
+
+#### 服务消费方注解驱动实现
+
+- 定义 Dubbo 消费方外部化配置属性源 - `consumer-config.properties`
+
+```properties
+## Dubbo Application info
+dubbo.application.name = dubbo-consumer-demo
+
+## Nacos registry address
+dubbo.registry.address = nacos://127.0.0.1:8848
+
+# @Reference version
+demo.service.version= 1.0.0
+```
+
+同样地,`dubbo.registry.address` 属性指向 Nacos 注册中心,其他 Dubbo 服务相关的元信息通过 Nacos 注册中心获取。
+
+
+
+- 实现服务消费方引导类 - `DemoServiceConsumerBootstrap`
+
+```java
+package com.alibaba.dubbo.demo.consumer;
+
+import com.alibaba.dubbo.config.annotation.Reference;
+import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
+import com.alibaba.dubbo.demo.service.DemoService;
+
+import
org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.PropertySource;
+
+import javax.annotation.PostConstruct;
+import java.io.IOException;
+
+/**
+ * {@link DemoService} consumer demo
+ */
+@EnableDubbo
+@PropertySource(value = "classpath:/consumer-config.properties")
+public class DemoServiceConsumerBootstrap {
+
+ @Reference(version = "${demo.service.version}")
+ private DemoService demoService;
+
+ @PostConstruct
+ public void init() {
+ for (int i = 0; i < 10; i++) {
+ System.out.println(demoService.sayName("小马哥(mercyblitz)"));
+ }
+ }
+
+ public static void main(String[] args) throws IOException {
+ AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext();
+ context.register(DemoServiceConsumerBootstrap.class);
+ context.refresh();
+ context.close();
+ }
+}
+
+```
+
+
+
+同样地,`@EnableDubbo` 注解激活 Dubbo 注解驱动和外部化配置,不过当前属于服务消费者,无需指定 Java 包名扫描标注
`@Service` 的服务实现。
+
+`@Reference` 是 Dubbo
远程服务的依赖注入注解,需要服务提供方和消费端约定接口(interface)、版本(version)以及分组(group)信息。在当前服务消费示例中,`DemoService`
的服务版本来源于属性配置文件 `consumer-config.properties`。
+
+`@PostConstruct` 部分代码则说明当 `DemoServiceConsumerBootstrap` Bean 初始化时,执行十次 Dubbo
远程方法调用。
+
+
+
+#### 运行注解驱动示例
+
+在本地启动两次 `DemoServiceProviderBootstrap`,注册中心将出现两个健康服务:
+
+
+
+再运行 `DemoServiceConsumerBootstrap`,运行结果如下:
+
+```
+Service [name :demoService , port : 20880] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :demoService , port : 20881] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :demoService , port : 20880] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :demoService , port : 20880] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :demoService , port : 20881] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :demoService , port : 20881] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :demoService , port : 20880] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :demoService , port : 20880] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :demoService , port : 20881] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :demoService , port : 20881] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+```
+
+运行无误,并且服务消费方使用了负载均衡策略,将十次 RPC 调用平均分摊到两个 Dubbo 服务提供方实例中。
+
+
+
+### Spring XML 配置驱动示例
+
+Spring XML 配置驱动是传统 Spring 装配组件的编程模型。
+
+
+
+#### 服务提供方 XML 配置驱动
+
+- 定义服务提供方 XML 上下文配置文件 - `/META-INF/spring/dubbo-provider-context.xml`
+
+```xml
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
+
+ <!-- 提供方应用信息,用于计算依赖关系 -->
+ <dubbo:application name="dubbo-provider-xml-demo"/>
+
+ <!-- 使用 Nacos 注册中心 -->
+ <dubbo:registry address="nacos://127.0.0.1:8848"/>
+
+ <!-- 用dubbo协议在随机端口暴露服务 -->
+ <dubbo:protocol name="dubbo" port="-1"/>
+
+ <!-- 声明需要暴露的服务接口 -->
+ <dubbo:service interface="com.alibaba.dubbo.demo.service.DemoService"
ref="demoService" version="2.0.0"/>
+
+ <!-- 和本地bean一样实现服务 -->
+ <bean id="demoService"
class="com.alibaba.dubbo.demo.service.DefaultService"/>
+</beans>
+```
+
+
+
+- 实现服务提供方引导类 - `DemoServiceProviderXmlBootstrap`
+
+```xml
+package com.alibaba.dubbo.demo.provider;
+
+import com.alibaba.dubbo.demo.service.DemoService;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import java.io.IOException;
+
+/**
+ * {@link DemoService} provider demo XML bootstrap
+ */
+public class DemoServiceProviderXmlBootstrap {
+
+ public static void main(String[] args) throws IOException {
+ ClassPathXmlApplicationContext context = new
ClassPathXmlApplicationContext();
+
context.setConfigLocation("/META-INF/spring/dubbo-provider-context.xml");
+ context.refresh();
+ System.out.println("DemoService provider (XML) is starting...");
+ System.in.read();
+ }
+}
+```
+
+
+
+#### 服务消费方 XML 配置驱动
+
+- 定义服务消费方 XML 上下文配置文件 - `/META-INF/spring/dubbo-consumer-context.xml`
+
+```xml
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
+
+ <!-- 提供方应用信息,用于计算依赖关系 -->
+ <dubbo:application name="dubbo-consumer-xml-demo"/>
+
+ <!-- 使用 Nacos 注册中心 -->
+ <dubbo:registry address="nacos://127.0.0.1:8848"/>
+
+ <!-- 引用服务接口 -->
+ <dubbo:reference id="demoService"
interface="com.alibaba.dubbo.demo.service.DemoService" version="2.0.0"/>
+
+</beans>
+```
+
+
+
+- 实现服务消费方引导类 - `DemoServiceConsumerXmlBootstrap`
+
+```java
+package com.alibaba.dubbo.demo.consumer;
+
+import com.alibaba.dubbo.demo.service.DemoService;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import java.io.IOException;
+
+/**
+ * {@link DemoService} consumer demo XML bootstrap
+ */
+public class DemoServiceConsumerXmlBootstrap {
+
+ public static void main(String[] args) throws IOException {
+ ClassPathXmlApplicationContext context = new
ClassPathXmlApplicationContext();
+
context.setConfigLocation("/META-INF/spring/dubbo-consumer-context.xml");
+ context.refresh();
+ System.out.println("DemoService consumer (XML) is starting...");
+ DemoService demoService = context.getBean("demoService",
DemoService.class);
+ for (int i = 0; i < 10; i++) {
+ System.out.println(demoService.sayName("小马哥(mercyblitz)"));
+ }
+ context.close();
+ }
+}
+```
+
+
+
+#### 运行 XML 配置驱动示例
+
+同样地,先启动两个 `DemoServiceProviderXmlBootstrap` 引导类,观察 Nacos 注册中心服务提供者变化:
+
+
+
+XML 配置驱动的服务版本为 `2.0.0`,因此注册服务无误。
+
+
+
+再运行服务消费者引导类 `DemoServiceConsumerXmlBootstrap`,观察控制台输出内容:
+
+```
+Service [name :null , port : 20882] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :null , port : 20882] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :null , port : 20883] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :null , port : 20882] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :null , port : 20882] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :null , port : 20883] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :null , port : 20882] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :null , port : 20883] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :null , port : 20883] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+Service [name :null , port : 20883] sayName("小马哥(mercyblitz)") :
Hello,小马哥(mercyblitz)
+```
+
+结果同样运行和负载均衡正常,不过由于当前示例尚未添加属性 `demo.service.name` 的缘故,因此,“name”部分信息输出为
`null`。更多内容请参考:https://github.com/dubbo/dubbo-registry-nacos。
+
+
+
+如果您关注或喜爱 Dubbo 以及 Nacos 等开源工程,不妨为它们点 “star”,加油打气链接:
+
+- Apache Dubbo:https://github.com/apache/incubator-dubbo
+- Dubbo Nacos Registry:https://github.com/dubbo/dubbo-registry-nacos
+- Alibaba Nacos:https://github.com/alibaba/nacos
\ No newline at end of file
diff --git a/img/blog/dubbo-registry-nacos-1.png
b/img/blog/dubbo-registry-nacos-1.png
new file mode 100644
index 0000000..743b435
Binary files /dev/null and b/img/blog/dubbo-registry-nacos-1.png differ
diff --git a/img/blog/dubbo-registry-nacos-2.png
b/img/blog/dubbo-registry-nacos-2.png
new file mode 100644
index 0000000..eccfaf6
Binary files /dev/null and b/img/blog/dubbo-registry-nacos-2.png differ
diff --git a/img/blog/dubbo-registry-nacos-3.png
b/img/blog/dubbo-registry-nacos-3.png
new file mode 100644
index 0000000..6b8888d
Binary files /dev/null and b/img/blog/dubbo-registry-nacos-3.png differ
diff --git a/img/blog/dubbo-registry-nacos-4.png
b/img/blog/dubbo-registry-nacos-4.png
new file mode 100644
index 0000000..4ee99cb
Binary files /dev/null and b/img/blog/dubbo-registry-nacos-4.png differ
diff --git a/img/blog/dubbo-registry-nacos-5.png
b/img/blog/dubbo-registry-nacos-5.png
new file mode 100644
index 0000000..4ee99cb
Binary files /dev/null and b/img/blog/dubbo-registry-nacos-5.png differ