├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── alibaba
│ │ └── dubbo
│ │ └── registry
│ │ └── nacos
│ │ ├── NacosExtensionFactory.java
│ │ ├── NacosRegistry.java
│ │ ├── NacosRegistryFactory.java
│ │ ├── NacosServiceDiscovery.java
│ │ ├── NacosServiceName.java
│ │ └── util
│ │ ├── NacosInstanceManageUtil.java
│ │ └── NacosNamingServiceUtils.java
└── resources
│ └── META-INF
│ └── dubbo
│ ├── org.apache.dubbo.registry.RegistryFactory
│ └── org.apache.dubbo.registry.client.ServiceDiscovery
└── test
├── java
└── com
│ └── alibaba
│ └── dubbo
│ ├── demo
│ ├── consumer
│ │ ├── DemoServiceConsumerBootstrap.java
│ │ └── DemoServiceConsumerXmlBootstrap.java
│ ├── provider
│ │ ├── DemoServiceProviderBootstrap.java
│ │ └── DemoServiceProviderXmlBootstrap.java
│ └── service
│ │ ├── DefaultService.java
│ │ └── DemoService.java
│ └── registry
│ └── nacos
│ ├── NacosRegistryFactoryTest.java
│ └── NacosRegistryTest.java
└── resources
├── META-INF
└── spring
│ ├── dubbo-consumer-context.xml
│ └── dubbo-provider-context.xml
├── consumer-config.properties
└── provider-config.properties
/.gitignore:
--------------------------------------------------------------------------------
1 | # maven ignore
2 | target/
3 | *.jar
4 | !.mvn/wrapper/*
5 | *.war
6 | *.zip
7 | *.tar
8 | *.tar.gz
9 |
10 | # eclipse ignore
11 | .settings/
12 | .project
13 | .classpath
14 |
15 | # idea ignore
16 | .idea/
17 | *.ipr
18 | *.iml
19 | *.iws
20 |
21 | # temp ignore
22 | *.log
23 | *.cache
24 | *.diff
25 | *.patch
26 | *.tmp
27 |
28 | # system ignore
29 | .DS_Store
30 | Thumbs.db
31 | *.orig
32 |
33 | # Maven ignore
34 | .flattened-pom.xml
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # dubbo-registry-nacos
2 |
3 | `dubbo-registry-nacos` is a [Dubbo](https://github.com/apache/dubbo)'s registry implementation integrating with
4 | [Nacos](https://github.com/alibaba/nacos) that is service registry server.
5 |
6 |
7 |
8 |
9 | ## Prerequisite
10 |
11 | Before you integrate `dubbo-registry-nacos` into your Dubbo project, you need to start a Nacos server in the backend.
12 | Refer to [Nacos Quick Start](https://nacos.io/en-us/docs/quick-start.html) for instructions on how to
13 | start a Nacos server.
14 |
15 |
16 |
17 |
18 | ## Getting started
19 |
20 |
21 |
22 |
23 | ### Maven dependency
24 |
25 | ```xml
26 |
27 |
28 | ...
29 |
30 |
31 |
32 | org.apache.dubbo
33 | dubbo
34 | [2.7.5,)
35 |
36 |
37 |
38 |
39 | com.alibaba
40 | dubbo-registry-nacos
41 | 2.7.7
42 |
43 |
44 |
45 |
46 | com.alibaba.nacos
47 | nacos-client
48 | 1.2.1
49 |
50 |
51 | ...
52 |
53 |
54 | ```
55 |
56 |
57 | ### Define service interface
58 |
59 | ```java
60 | package com.alibaba.dubbo.demo.service;
61 |
62 | public interface DemoService {
63 | String sayName(String name);
64 | }
65 | ```
66 |
67 |
68 | ### Implement service interface for the provider
69 |
70 | ```java
71 | package com.alibaba.dubbo.demo.service;
72 |
73 | @Service(version = "${demo.service.version}")
74 | public class DefaultService implements DemoService {
75 |
76 | @Value("${demo.service.name}")
77 | private String serviceName;
78 |
79 | public String sayName(String name) {
80 | RpcContext rpcContext = RpcContext.getContext();
81 | return String.format("Service [name :%s , port : %d] %s(\"%s\") : Hello,%s",
82 | serviceName,
83 | rpcContext.getLocalPort(),
84 | rpcContext.getMethodName(),
85 | name,
86 | name);
87 | }
88 | }
89 | ```
90 |
91 |
92 | ### Define service provider's configuration
93 |
94 | ```properties
95 | ## application
96 | dubbo.application.name = dubbo-provider-demo
97 |
98 | ## Nacos registry address
99 | dubbo.registry.address = nacos://127.0.0.1:8848/?username=nacos&password=nacos
100 |
101 | ## Dubbo Protocol
102 | dubbo.protocol.name = dubbo
103 | dubbo.protocol.port = -1
104 |
105 | # Provider @Service version
106 | demo.service.version=1.0.0
107 | demo.service.name = demoService
108 | ```
109 |
110 |
111 |
112 |
113 | ### Start service provider
114 |
115 | ```java
116 | package com.alibaba.dubbo.demo.provider;
117 |
118 | @EnableDubbo(scanBasePackages = "com.alibaba.dubbo.demo.service")
119 | @PropertySource(value = "classpath:/provider-config.properties")
120 | public class DemoServiceProviderBootstrap {
121 |
122 | public static void main(String[] args) throws IOException {
123 | AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
124 | context.register(DemoServiceProviderBootstrap.class);
125 | context.refresh();
126 | System.out.println("DemoService provider starting...");
127 | System.in.read();
128 | }
129 | }
130 | ```
131 |
132 |
133 | See [`DemoServiceProviderBootstrap.java`](src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderBootstrap.java) on GitHub.
134 |
135 |
136 |
137 |
138 | ### Define service consumer's configuration
139 |
140 | ```properties
141 | ## Dubbo Application info
142 | dubbo.application.name = dubbo-consumer-demo
143 |
144 | ## Nacos registry address
145 | dubbo.registry.address = nacos://127.0.0.1:8848/?username=nacos&password=nacos
146 |
147 | # @Reference version
148 | demo.service.version= 1.0.0
149 | ```
150 |
151 |
152 |
153 |
154 | ### Start service consumer
155 |
156 | ```java
157 | package com.alibaba.dubbo.demo.consumer;
158 |
159 | @EnableDubbo
160 | @PropertySource(value = "classpath:/consumer-config.properties")
161 | public class DemoServiceConsumerBootstrap {
162 |
163 | @Reference(version = "${demo.service.version}")
164 | private DemoService demoService;
165 |
166 | @PostConstruct
167 | public void init() {
168 | for (int i = 0; i < 10; i++) {
169 | System.out.println(demoService.sayName("Mercy"));
170 | }
171 | }
172 |
173 | public static void main(String[] args) throws IOException {
174 | AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
175 | context.register(DemoServiceConsumerBootstrap.class);
176 | context.refresh();
177 | context.close();
178 | }
179 | }
180 | ```
181 |
182 | See [`DemoServiceConsumerBootstrap.java`](src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java) on GitHub.
183 |
184 |
185 | ## Advanced
186 |
187 |
188 |
189 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | org.sonatype.oss
8 | oss-parent
9 | 7
10 |
11 |
12 | 4.0.0
13 |
14 | com.alibaba
15 | dubbo-registry-nacos
16 | ${revision}
17 |
18 |
19 | UTF-8
20 | UTF-8
21 |
22 | 1.8
23 | 1.8
24 | 2.7.7
25 | ${revision}
26 | 1.2.1
27 | 5.2.5.RELEASE
28 |
29 |
30 |
31 |
32 | org.apache.dubbo
33 | dubbo-registry-api
34 | ${dubbo.version}
35 |
36 |
37 | org.apache.dubbo
38 | dubbo-common
39 | ${dubbo.version}
40 |
41 |
42 | com.alibaba.nacos
43 | nacos-client
44 | ${nacos.version}
45 |
46 |
47 |
48 | org.apache.dubbo
49 | dubbo
50 | ${dubbo.version}
51 | test
52 |
53 |
54 |
55 | org.springframework
56 | spring-context
57 | ${spring.framework.version}
58 | test
59 |
60 |
61 | org.springframework
62 | spring-test
63 | ${spring.framework.version}
64 | test
65 |
66 |
67 |
68 |
69 |
70 | release
71 |
72 |
73 |
74 | org.apache.maven.plugins
75 | maven-gpg-plugin
76 |
77 |
78 | verify
79 |
80 | sign
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | org.apache.maven.plugins
95 | maven-javadoc-plugin
96 | 3.2.0
97 |
98 |
99 | package
100 |
101 | jar
102 |
103 |
104 |
105 |
106 |
107 | org.apache.maven.plugins
108 | maven-compiler-plugin
109 | 3.8.1
110 |
111 | ${maven.compiler.source}
112 | ${maven.compiler.target}
113 | false
114 |
115 |
116 |
117 | org.apache.maven.plugins
118 | maven-source-plugin
119 | 3.2.0
120 |
121 |
122 | attach-sources
123 |
124 | jar-no-fork
125 |
126 |
127 |
128 |
129 |
130 | org.codehaus.mojo
131 | flatten-maven-plugin
132 | 1.1.0
133 |
134 | true
135 | resolveCiFriendliesOnly
136 |
137 |
138 |
139 | flatten
140 | process-resources
141 |
142 | flatten
143 |
144 |
145 |
146 | flatten.clean
147 | clean
148 |
149 | clean
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/src/main/java/com/alibaba/dubbo/registry/nacos/NacosExtensionFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.alibaba.dubbo.registry.nacos;
18 |
19 | import org.apache.dubbo.common.extension.ExtensionFactory;
20 | import org.apache.dubbo.common.extension.ExtensionLoader;
21 | import org.apache.dubbo.common.lang.Prioritized;
22 | import org.apache.dubbo.registry.RegistryFactory;
23 |
24 | import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
25 |
26 | /**
27 | * Like a dummy implementation of Dubbo's {@link ExtensionFactory}, which will replace the "nacos" registry protocol
28 | * from Apache Dubbo, instead of getting any instance of extension.
29 | */
30 | @Deprecated
31 | public class NacosExtensionFactory implements ExtensionFactory, Prioritized {
32 |
33 | static {
34 | ExtensionLoader extensionLoader = getExtensionLoader(RegistryFactory.class);
35 | extensionLoader.replaceExtension("nacos", NacosRegistryFactory.class);
36 | }
37 |
38 | @Override
39 | public T getExtension(Class type, String name) {
40 | return null;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistry.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.alibaba.dubbo.registry.nacos;
18 |
19 | import org.apache.dubbo.common.URL;
20 | import org.apache.dubbo.common.URLBuilder;
21 | import org.apache.dubbo.common.logger.Logger;
22 | import org.apache.dubbo.common.logger.LoggerFactory;
23 | import org.apache.dubbo.common.utils.StringUtils;
24 | import org.apache.dubbo.common.utils.UrlUtils;
25 | import org.apache.dubbo.registry.NotifyListener;
26 | import org.apache.dubbo.registry.Registry;
27 | import org.apache.dubbo.registry.support.FailbackRegistry;
28 |
29 | import com.alibaba.dubbo.registry.nacos.util.NacosInstanceManageUtil;
30 | import com.alibaba.nacos.api.exception.NacosException;
31 | import com.alibaba.nacos.api.naming.NamingService;
32 | import com.alibaba.nacos.api.naming.listener.EventListener;
33 | import com.alibaba.nacos.api.naming.listener.NamingEvent;
34 | import com.alibaba.nacos.api.naming.pojo.Instance;
35 | import com.alibaba.nacos.api.naming.pojo.ListView;
36 | import com.google.common.collect.Lists;
37 |
38 | import java.util.ArrayList;
39 | import java.util.Arrays;
40 | import java.util.Collection;
41 | import java.util.HashMap;
42 | import java.util.LinkedHashSet;
43 | import java.util.LinkedList;
44 | import java.util.List;
45 | import java.util.Map;
46 | import java.util.Set;
47 | import java.util.concurrent.Executors;
48 | import java.util.concurrent.ScheduledExecutorService;
49 | import java.util.concurrent.TimeUnit;
50 | import java.util.stream.Collectors;
51 |
52 | import static com.alibaba.dubbo.registry.nacos.NacosServiceName.valueOf;
53 | import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
54 | import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
55 | import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
56 | import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
57 | import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
58 | import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
59 | import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
60 | import static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY;
61 | import static org.apache.dubbo.common.constants.RegistryConstants.CONSUMERS_CATEGORY;
62 | import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;
63 | import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
64 | import static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;
65 | import static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;
66 | import static org.apache.dubbo.registry.Constants.ADMIN_PROTOCOL;
67 |
68 | /**
69 | * Nacos {@link Registry}
70 | *
71 | * @see #SERVICE_NAME_SEPARATOR
72 | * @see #PAGINATION_SIZE
73 | * @see #LOOKUP_INTERVAL
74 | * @since 2.6.5
75 | */
76 | public class NacosRegistry extends FailbackRegistry {
77 |
78 | /**
79 | * All supported categories
80 | */
81 | private static final List ALL_SUPPORTED_CATEGORIES = Arrays.asList(
82 | PROVIDERS_CATEGORY,
83 | CONSUMERS_CATEGORY,
84 | ROUTERS_CATEGORY,
85 | CONFIGURATORS_CATEGORY
86 | );
87 |
88 | private static final int CATEGORY_INDEX = 0;
89 |
90 | private static final int SERVICE_INTERFACE_INDEX = 1;
91 |
92 | private static final int SERVICE_VERSION_INDEX = 2;
93 |
94 | private static final int SERVICE_GROUP_INDEX = 3;
95 |
96 | private static final String WILDCARD = "*";
97 |
98 | /**
99 | * The separator for service name
100 | * Change a constant to be configurable, it's designed for Windows file name that is compatible with old
101 | * Nacos binary release(< 0.6.1)
102 | */
103 | private static final String SERVICE_NAME_SEPARATOR = System.getProperty("nacos.service.name.separator", ":");
104 |
105 | /**
106 | * The pagination size of query for Nacos service names(only for Dubbo-OPS)
107 | */
108 | private static final int PAGINATION_SIZE = Integer.getInteger("nacos.service.names.pagination.size", 100);
109 |
110 | /**
111 | * The interval in second of lookup Nacos service names(only for Dubbo-OPS)
112 | */
113 | private static final long LOOKUP_INTERVAL = Long.getLong("nacos.service.names.lookup.interval", 30);
114 |
115 | /**
116 | * {@link ScheduledExecutorService} lookup Nacos service names(only for Dubbo-OPS)
117 | */
118 | private volatile ScheduledExecutorService scheduledExecutorService;
119 |
120 | private final Logger logger = LoggerFactory.getLogger(getClass());
121 |
122 | private final NamingService namingService;
123 |
124 | public NacosRegistry(URL url, NamingService namingService) {
125 | super(url);
126 | this.namingService = namingService;
127 | }
128 |
129 | @Override
130 | public boolean isAvailable() {
131 | return "UP".equals(namingService.getServerStatus());
132 | }
133 |
134 | @Override
135 | public List lookup(final URL url) {
136 | final List urls = new LinkedList<>();
137 | execute(namingService -> {
138 | Set serviceNames = getServiceNames(url, null);
139 | for (String serviceName : serviceNames) {
140 | List instances = namingService.getAllInstances(serviceName);
141 | urls.addAll(buildURLs(url, instances));
142 | }
143 | });
144 | return urls;
145 | }
146 |
147 | @Override
148 | public void doRegister(URL url) {
149 | final String serviceName = getServiceName(url);
150 | final Instance instance = createInstance(url);
151 | execute(namingService -> namingService.registerInstance(serviceName, instance));
152 | }
153 |
154 | @Override
155 | public void doUnregister(final URL url) {
156 | execute(namingService -> {
157 | String serviceName = getServiceName(url);
158 | Instance instance = createInstance(url);
159 | namingService.deregisterInstance(serviceName, instance.getIp(), instance.getPort());
160 | });
161 | }
162 |
163 | @Override
164 | public void doSubscribe(final URL url, final NotifyListener listener) {
165 | Set serviceNames = getServiceNames(url, listener);
166 |
167 | //Set corresponding serviceNames for easy search later
168 | if(isServiceNamesWithCompatibleMode(url)){
169 | for(String serviceName:serviceNames){
170 | NacosInstanceManageUtil.setCorrespondingServiceNames(serviceName, serviceNames);
171 | }
172 | }
173 |
174 | doSubscribe(url, listener, serviceNames);
175 | }
176 |
177 | private void doSubscribe(final URL url, final NotifyListener listener, final Set serviceNames) {
178 | execute(namingService -> {
179 | if (isServiceNamesWithCompatibleMode(url)) {
180 | List allCorrespondingInstanceList = Lists.newArrayList();
181 |
182 | /**
183 | * Get all instances with serviceNames to avoid instance overwrite and but with empty instance mentioned
184 | * in https://github.com/apache/dubbo/issues/5885 and https://github.com/apache/dubbo/issues/5899
185 | */
186 | for (String serviceName : serviceNames) {
187 | List instances = namingService.getAllInstances(serviceName);
188 | NacosInstanceManageUtil.initOrRefreshServiceInstanceList(serviceName, instances);
189 | allCorrespondingInstanceList.addAll(instances);
190 | }
191 | notifySubscriber(url, listener, allCorrespondingInstanceList);
192 | for (String serviceName : serviceNames) {
193 | subscribeEventListener(serviceName, url, listener);
194 | }
195 | } else {
196 | List instances = new LinkedList();
197 | for (String serviceName : serviceNames) {
198 | instances.addAll(namingService.getAllInstances(serviceName));
199 | notifySubscriber(url, listener, instances);
200 | subscribeEventListener(serviceName, url, listener);
201 | }
202 | }
203 |
204 | });
205 | }
206 |
207 | /**
208 | * Since 2.7.6 the legacy service name will be added to serviceNames
209 | * to fix bug with https://github.com/apache/dubbo/issues/5442
210 | *
211 | * @param url
212 | * @return
213 | */
214 | private boolean isServiceNamesWithCompatibleMode(final URL url) {
215 | if (!isAdminProtocol(url) && createServiceName(url).isConcrete()) {
216 | return true;
217 | } else {
218 | return false;
219 | }
220 | }
221 |
222 | @Override
223 | public void doUnsubscribe(URL url, NotifyListener listener) {
224 | if (isAdminProtocol(url)) {
225 | shutdownServiceNamesLookup();
226 | }
227 | }
228 |
229 | private void shutdownServiceNamesLookup() {
230 | if (scheduledExecutorService != null) {
231 | scheduledExecutorService.shutdown();
232 | }
233 | }
234 |
235 | /**
236 | * Get the service names from the specified {@link URL url}
237 | *
238 | * @param url {@link URL}
239 | * @param listener {@link NotifyListener}
240 | * @return non-null
241 | */
242 | private Set getServiceNames(URL url, NotifyListener listener) {
243 | if (isAdminProtocol(url)) {
244 | scheduleServiceNamesLookup(url, listener);
245 | return getServiceNamesForOps(url);
246 | } else {
247 | return getServiceNames0(url);
248 | }
249 | }
250 |
251 | private Set getServiceNames0(URL url) {
252 | NacosServiceName serviceName = createServiceName(url);
253 |
254 | final Set serviceNames;
255 |
256 | if (serviceName.isConcrete()) { // is the concrete service name
257 | serviceNames = new LinkedHashSet<>();
258 | serviceNames.add(serviceName.toString());
259 | // Add the legacy service name since 2.7.6
260 | String legacySubscribedServiceName = getLegacySubscribedServiceName(url);
261 | if (!serviceName.toString().equals(legacySubscribedServiceName)) {
262 | //avoid duplicated service names
263 | serviceNames.add(legacySubscribedServiceName);
264 | }
265 | } else {
266 | serviceNames = filterServiceNames(serviceName);
267 | }
268 |
269 | return serviceNames;
270 | }
271 |
272 | private Set filterServiceNames(NacosServiceName serviceName) {
273 | Set serviceNames = new LinkedHashSet<>();
274 |
275 | execute(namingService -> {
276 |
277 | serviceNames.addAll(namingService.getServicesOfServer(1, Integer.MAX_VALUE).getData()
278 | .stream()
279 | .map(NacosServiceName::new)
280 | .filter(serviceName::isCompatible)
281 | .map(NacosServiceName::toString)
282 | .collect(Collectors.toList()));
283 |
284 | });
285 |
286 | return serviceNames;
287 | }
288 |
289 | /**
290 | * Get the legacy subscribed service name for compatible with Dubbo 2.7.3 and below
291 | *
292 | * @param url {@link URL}
293 | * @return non-null
294 | * @since 2.7.6
295 | */
296 | private String getLegacySubscribedServiceName(URL url) {
297 | StringBuilder serviceNameBuilder = new StringBuilder(DEFAULT_CATEGORY);
298 | appendIfPresent(serviceNameBuilder, url, INTERFACE_KEY);
299 | appendIfPresent(serviceNameBuilder, url, VERSION_KEY);
300 | appendIfPresent(serviceNameBuilder, url, GROUP_KEY);
301 | return serviceNameBuilder.toString();
302 | }
303 |
304 | private void appendIfPresent(StringBuilder target, URL url, String parameterName) {
305 | String parameterValue = url.getParameter(parameterName);
306 | if (!org.apache.commons.lang3.StringUtils.isBlank(parameterValue)) {
307 | target.append(SERVICE_NAME_SEPARATOR).append(parameterValue);
308 | }
309 | }
310 |
311 |
312 | private boolean isAdminProtocol(URL url) {
313 | return ADMIN_PROTOCOL.equals(url.getProtocol());
314 | }
315 |
316 | private void scheduleServiceNamesLookup(final URL url, final NotifyListener listener) {
317 | if (scheduledExecutorService == null) {
318 | scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
319 | scheduledExecutorService.scheduleAtFixedRate(() -> {
320 | Set serviceNames = getAllServiceNames();
321 | filterData(serviceNames, serviceName -> {
322 | boolean accepted = false;
323 | for (String category : ALL_SUPPORTED_CATEGORIES) {
324 | String prefix = category + SERVICE_NAME_SEPARATOR;
325 | if (serviceName != null && serviceName.startsWith(prefix)) {
326 | accepted = true;
327 | break;
328 | }
329 | }
330 | return accepted;
331 | });
332 | doSubscribe(url, listener, serviceNames);
333 | }, LOOKUP_INTERVAL, LOOKUP_INTERVAL, TimeUnit.SECONDS);
334 | }
335 | }
336 |
337 | /**
338 | * Get the service names for Dubbo OPS
339 | *
340 | * @param url {@link URL}
341 | * @return non-null
342 | */
343 | private Set getServiceNamesForOps(URL url) {
344 | Set serviceNames = getAllServiceNames();
345 | filterServiceNames(serviceNames, url);
346 | return serviceNames;
347 | }
348 |
349 | private Set getAllServiceNames() {
350 |
351 | final Set serviceNames = new LinkedHashSet<>();
352 |
353 | execute(namingService -> {
354 |
355 | int pageIndex = 1;
356 | ListView listView = namingService.getServicesOfServer(pageIndex, PAGINATION_SIZE);
357 | // First page data
358 | List firstPageData = listView.getData();
359 | // Append first page into list
360 | serviceNames.addAll(firstPageData);
361 | // the total count
362 | int count = listView.getCount();
363 | // the number of pages
364 | int pageNumbers = count / PAGINATION_SIZE;
365 | int remainder = count % PAGINATION_SIZE;
366 | // remain
367 | if (remainder > 0) {
368 | pageNumbers += 1;
369 | }
370 | // If more than 1 page
371 | while (pageIndex < pageNumbers) {
372 | listView = namingService.getServicesOfServer(++pageIndex, PAGINATION_SIZE);
373 | serviceNames.addAll(listView.getData());
374 | }
375 |
376 | });
377 |
378 | return serviceNames;
379 | }
380 |
381 | private void filterServiceNames(Set serviceNames, URL url) {
382 |
383 | final List categories = getCategories(url);
384 |
385 | final String targetServiceInterface = url.getServiceInterface();
386 |
387 | final String targetVersion = url.getParameter(VERSION_KEY, "");
388 |
389 | final String targetGroup = url.getParameter(GROUP_KEY, "");
390 |
391 | filterData(serviceNames, serviceName -> {
392 | // split service name to segments
393 | // (required) segments[0] = category
394 | // (required) segments[1] = serviceInterface
395 | // (optional) segments[2] = version
396 | // (optional) segments[3] = group
397 | String[] segments = serviceName.split(SERVICE_NAME_SEPARATOR, -1);
398 | int length = segments.length;
399 | if (length != 4) { // must present 4 segments
400 | return false;
401 | }
402 |
403 | String category = segments[CATEGORY_INDEX];
404 | if (!categories.contains(category)) { // no match category
405 | return false;
406 | }
407 |
408 | String serviceInterface = segments[SERVICE_INTERFACE_INDEX];
409 | // no match service interface
410 | if (!WILDCARD.equals(targetServiceInterface) &&
411 | !StringUtils.isEquals(targetServiceInterface, serviceInterface)) {
412 | return false;
413 | }
414 |
415 | // no match service version
416 | String version = segments[SERVICE_VERSION_INDEX];
417 | if (!WILDCARD.equals(targetVersion) && !StringUtils.isEquals(targetVersion, version)) {
418 | return false;
419 | }
420 |
421 | String group = segments[SERVICE_GROUP_INDEX];
422 | return group == null || WILDCARD.equals(targetGroup) || StringUtils.isEquals(targetGroup, group);
423 | });
424 | }
425 |
426 | private void filterData(Collection collection, NacosDataFilter filter) {
427 | // remove if not accept
428 | collection.removeIf(data -> !filter.accept(data));
429 | }
430 |
431 | @Deprecated
432 | private List doGetServiceNames(URL url) {
433 | List categories = getCategories(url);
434 | List serviceNames = new ArrayList<>(categories.size());
435 | for (String category : categories) {
436 | final String serviceName = getServiceName(url, category);
437 | serviceNames.add(serviceName);
438 | }
439 | return serviceNames;
440 | }
441 |
442 | private List toUrlWithEmpty(URL consumerURL, Collection instances) {
443 | List urls = buildURLs(consumerURL, instances);
444 | if (urls.size() == 0) {
445 | URL empty = URLBuilder.from(consumerURL)
446 | .setProtocol(EMPTY_PROTOCOL)
447 | .addParameter(CATEGORY_KEY, DEFAULT_CATEGORY)
448 | .build();
449 | urls.add(empty);
450 | }
451 | return urls;
452 | }
453 |
454 | private List buildURLs(URL consumerURL, Collection instances) {
455 | List urls = new LinkedList<>();
456 | if (instances != null && !instances.isEmpty()) {
457 | for (Instance instance : instances) {
458 | URL url = buildURL(instance);
459 | if (UrlUtils.isMatch(consumerURL, url)) {
460 | urls.add(url);
461 | }
462 | }
463 | }
464 | return urls;
465 | }
466 |
467 | private void subscribeEventListener(String serviceName, final URL url, final NotifyListener listener)
468 | throws NacosException {
469 | EventListener eventListener = event -> {
470 | if (event instanceof NamingEvent) {
471 | NamingEvent e = (NamingEvent) event;
472 | List instances = e.getInstances();
473 |
474 |
475 | if(isServiceNamesWithCompatibleMode(url)){
476 | /**
477 | * Get all instances with corresponding serviceNames to avoid instance overwrite and but with empty instance mentioned
478 | * in https://github.com/apache/dubbo/issues/5885 and https://github.com/apache/dubbo/issues/5899
479 | */
480 | NacosInstanceManageUtil.initOrRefreshServiceInstanceList(serviceName, instances);
481 | instances = NacosInstanceManageUtil.getAllCorrespondingServiceInstanceList(serviceName);
482 | }
483 |
484 | notifySubscriber(url, listener, instances);
485 | }
486 | };
487 | namingService.subscribe(serviceName, eventListener);
488 | }
489 |
490 | /**
491 | * Notify the Healthy {@link Instance instances} to subscriber.
492 | *
493 | * @param url {@link URL}
494 | * @param listener {@link NotifyListener}
495 | * @param instances all {@link Instance instances}
496 | */
497 | private void notifySubscriber(URL url, NotifyListener listener, Collection instances) {
498 | List healthyInstances = new LinkedList<>(instances);
499 | if (healthyInstances.size() > 0) {
500 | // Healthy Instances
501 | filterHealthyInstances(healthyInstances);
502 | }
503 | List urls = toUrlWithEmpty(url, healthyInstances);
504 | NacosRegistry.this.notify(url, listener, urls);
505 | }
506 |
507 | /**
508 | * Get the categories from {@link URL}
509 | *
510 | * @param url {@link URL}
511 | * @return non-null array
512 | */
513 | private List getCategories(URL url) {
514 | return ANY_VALUE.equals(url.getServiceInterface()) ?
515 | ALL_SUPPORTED_CATEGORIES : Arrays.asList(DEFAULT_CATEGORY);
516 | }
517 |
518 | private URL buildURL(Instance instance) {
519 | Map metadata = instance.getMetadata();
520 | String protocol = metadata.get(PROTOCOL_KEY);
521 | String path = metadata.get(PATH_KEY);
522 | return new URL(protocol,
523 | instance.getIp(),
524 | instance.getPort(),
525 | path,
526 | instance.getMetadata());
527 | }
528 |
529 | private Instance createInstance(URL url) {
530 | // Append default category if absent
531 | String category = url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);
532 | URL newURL = url.addParameter(CATEGORY_KEY, category);
533 | newURL = newURL.addParameter(PROTOCOL_KEY, url.getProtocol());
534 | newURL = newURL.addParameter(PATH_KEY, url.getPath());
535 | String ip = url.getHost();
536 | int port = url.getPort();
537 | Instance instance = new Instance();
538 | instance.setIp(ip);
539 | instance.setPort(port);
540 | instance.setMetadata(new HashMap<>(newURL.getParameters()));
541 | return instance;
542 | }
543 |
544 | private NacosServiceName createServiceName(URL url) {
545 | return valueOf(url);
546 | }
547 |
548 | private String getServiceName(URL url) {
549 | return getServiceName(url, url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY));
550 | }
551 |
552 | private String getServiceName(URL url, String category) {
553 | return category + SERVICE_NAME_SEPARATOR + url.getColonSeparatedKey();
554 | }
555 |
556 | private void execute(NamingServiceCallback callback) {
557 | try {
558 | callback.callback(namingService);
559 | } catch (NacosException e) {
560 | if (logger.isErrorEnabled()) {
561 | logger.error(e.getErrMsg(), e);
562 | }
563 | }
564 | }
565 |
566 | private void filterHealthyInstances(Collection instances) {
567 | filterData(instances, Instance::isEnabled);
568 | }
569 |
570 | /**
571 | * A filter for Nacos data
572 | *
573 | * @since 2.6.5
574 | */
575 | private interface NacosDataFilter {
576 |
577 | /**
578 | * Tests whether or not the specified data should be accepted.
579 | *
580 | * @param data The data to be tested
581 | * @return true
if and only if data
582 | * should be accepted
583 | */
584 | boolean accept(T data);
585 |
586 | }
587 |
588 | /**
589 | * {@link NamingService} Callback
590 | *
591 | * @since 2.6.5
592 | */
593 | interface NamingServiceCallback {
594 |
595 | /**
596 | * Callback
597 | *
598 | * @param namingService {@link NamingService}
599 | * @throws NacosException
600 | */
601 | void callback(NamingService namingService) throws NacosException;
602 |
603 | }
604 | }
--------------------------------------------------------------------------------
/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.alibaba.dubbo.registry.nacos;
18 |
19 | import org.apache.dubbo.common.URL;
20 | import org.apache.dubbo.registry.Registry;
21 | import org.apache.dubbo.registry.RegistryFactory;
22 | import org.apache.dubbo.registry.support.AbstractRegistryFactory;
23 |
24 | import static com.alibaba.dubbo.registry.nacos.util.NacosNamingServiceUtils.createNamingService;
25 |
26 | /**
27 | * Nacos {@link RegistryFactory}
28 | *
29 | * @since 2.6.5
30 | */
31 | public class NacosRegistryFactory extends AbstractRegistryFactory {
32 |
33 | @Override
34 | protected Registry createRegistry(URL url) {
35 | return new NacosRegistry(url, createNamingService(url));
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/alibaba/dubbo/registry/nacos/NacosServiceDiscovery.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.alibaba.dubbo.registry.nacos;
18 |
19 | import org.apache.dubbo.common.URL;
20 | import org.apache.dubbo.common.function.ThrowableFunction;
21 | import org.apache.dubbo.registry.client.ServiceDiscovery;
22 | import org.apache.dubbo.registry.client.ServiceInstance;
23 | import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;
24 |
25 | import com.alibaba.dubbo.registry.nacos.util.NacosNamingServiceUtils;
26 | import com.alibaba.nacos.api.naming.NamingService;
27 | import com.alibaba.nacos.api.naming.listener.NamingEvent;
28 | import com.alibaba.nacos.api.naming.pojo.Instance;
29 | import com.alibaba.nacos.api.naming.pojo.ListView;
30 |
31 | import java.util.Collection;
32 | import java.util.LinkedHashSet;
33 | import java.util.List;
34 | import java.util.Set;
35 | import java.util.stream.Collectors;
36 |
37 | import static com.alibaba.dubbo.registry.nacos.util.NacosNamingServiceUtils.createNamingService;
38 | import static com.alibaba.dubbo.registry.nacos.util.NacosNamingServiceUtils.getGroup;
39 | import static com.alibaba.dubbo.registry.nacos.util.NacosNamingServiceUtils.toInstance;
40 | import static org.apache.dubbo.common.function.ThrowableConsumer.execute;
41 |
42 | /**
43 | * Nacos {@link ServiceDiscovery} implementation
44 | *
45 | * @see ServiceDiscovery
46 | * @since 2.7.5
47 | */
48 | public class NacosServiceDiscovery implements ServiceDiscovery {
49 |
50 | private String group;
51 |
52 | private NamingService namingService;
53 |
54 | @Override
55 | public void initialize(URL registryURL) throws Exception {
56 | this.namingService = createNamingService(registryURL);
57 | this.group = getGroup(registryURL);
58 | }
59 |
60 | @Override
61 | public void destroy() {
62 | this.namingService = null;
63 | }
64 |
65 | @Override
66 | public void register(ServiceInstance serviceInstance) throws RuntimeException {
67 | execute(namingService, service -> {
68 | Instance instance = toInstance(serviceInstance);
69 | service.registerInstance(instance.getServiceName(), group, instance);
70 | });
71 | }
72 |
73 | @Override
74 | public void update(ServiceInstance serviceInstance) throws RuntimeException {
75 | // TODO: Nacos should support
76 | unregister(serviceInstance);
77 | register(serviceInstance);
78 | }
79 |
80 | @Override
81 | public void unregister(ServiceInstance serviceInstance) throws RuntimeException {
82 | execute(namingService, service -> {
83 | Instance instance = toInstance(serviceInstance);
84 | service.deregisterInstance(instance.getServiceName(), group, instance);
85 | });
86 | }
87 |
88 | @Override
89 | public Set getServices() {
90 | return ThrowableFunction.execute(namingService, service -> {
91 | ListView view = service.getServicesOfServer(0, Integer.MAX_VALUE, group);
92 | return new LinkedHashSet<>(view.getData());
93 | });
94 | }
95 |
96 | @Override
97 | public List getInstances(String serviceName) throws NullPointerException {
98 | return ThrowableFunction.execute(namingService, service ->
99 | service.selectInstances(serviceName, true)
100 | .stream().map(NacosNamingServiceUtils::toServiceInstance)
101 | .collect(Collectors.toList())
102 | );
103 | }
104 |
105 | @Override
106 | public void addServiceInstancesChangedListener(ServiceInstancesChangedListener listener)
107 | throws NullPointerException, IllegalArgumentException {
108 | execute(namingService, service -> {
109 | service.subscribe(listener.getServiceName(), e -> { // Register Nacos EventListener
110 | if (e instanceof NamingEvent) {
111 | NamingEvent event = (NamingEvent) e;
112 | handleEvent(event, listener);
113 | }
114 | });
115 | });
116 | }
117 |
118 | private void handleEvent(NamingEvent event, ServiceInstancesChangedListener listener) {
119 | String serviceName = event.getServiceName();
120 | Collection serviceInstances = event.getInstances()
121 | .stream()
122 | .map(NacosNamingServiceUtils::toServiceInstance)
123 | .collect(Collectors.toList());
124 | dispatchServiceInstancesChangedEvent(serviceName, serviceInstances);
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/main/java/com/alibaba/dubbo/registry/nacos/NacosServiceName.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.alibaba.dubbo.registry.nacos;
18 |
19 | import org.apache.dubbo.common.URL;
20 | import org.apache.dubbo.common.utils.StringUtils;
21 |
22 | import java.util.Arrays;
23 | import java.util.Objects;
24 |
25 | import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
26 | import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
27 | import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
28 | import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
29 | import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;
30 | import static org.apache.dubbo.common.utils.StringUtils.isBlank;
31 |
32 | /**
33 | * The service name of Nacos
34 | *
35 | * @since 2.7.3
36 | */
37 | public class NacosServiceName {
38 |
39 | public static final String NAME_SEPARATOR = ":";
40 |
41 | public static final String VALUE_SEPARATOR = ",";
42 |
43 | public static final String WILDCARD = "*";
44 |
45 | public static final String DEFAULT_PARAM_VALUE = "";
46 |
47 | private static final int CATEGORY_INDEX = 0;
48 |
49 | private static final int SERVICE_INTERFACE_INDEX = 1;
50 |
51 | private static final int SERVICE_VERSION_INDEX = 2;
52 |
53 | private static final int SERVICE_GROUP_INDEX = 3;
54 |
55 | private String category;
56 |
57 | private String serviceInterface;
58 |
59 | private String version;
60 |
61 | private String group;
62 |
63 | private String value;
64 |
65 | public NacosServiceName() {
66 | }
67 |
68 | public NacosServiceName(URL url) {
69 | serviceInterface = url.getParameter(INTERFACE_KEY);
70 | category = isConcrete(serviceInterface) ? DEFAULT_CATEGORY : url.getParameter(CATEGORY_KEY);
71 | version = url.getParameter(VERSION_KEY, DEFAULT_PARAM_VALUE);
72 | group = url.getParameter(GROUP_KEY, DEFAULT_PARAM_VALUE);
73 | value = toValue();
74 | }
75 |
76 | public NacosServiceName(String value) {
77 | this.value = value;
78 | String[] segments = value.split(NAME_SEPARATOR, -1);
79 | this.category = segments[CATEGORY_INDEX];
80 | this.serviceInterface = segments[SERVICE_INTERFACE_INDEX];
81 | this.version = segments[SERVICE_VERSION_INDEX];
82 | this.group = segments[SERVICE_GROUP_INDEX];
83 | }
84 |
85 | /**
86 | * Build an instance of {@link NacosServiceName}
87 | *
88 | * @param url {@link URL}
89 | * @return {@link NacosServiceName} instance
90 | */
91 | public static NacosServiceName valueOf(URL url) {
92 | return new NacosServiceName(url);
93 | }
94 |
95 | /**
96 | * Is the concrete service name or not
97 | *
98 | * @return if concrete , return true
, or false
99 | */
100 | public boolean isConcrete() {
101 | return isConcrete(serviceInterface) && isConcrete(version) && isConcrete(group);
102 | }
103 |
104 | public boolean isCompatible(NacosServiceName concreteServiceName) {
105 |
106 | if (!concreteServiceName.isConcrete()) { // The argument must be the concrete NacosServiceName
107 | return false;
108 | }
109 |
110 | // Not match comparison
111 | if (!StringUtils.isEquals(this.category, concreteServiceName.category)
112 | && !matchRange(this.category, concreteServiceName.category)) {
113 | return false;
114 | }
115 |
116 | if (!StringUtils.isEquals(this.serviceInterface, concreteServiceName.serviceInterface)) {
117 | return false;
118 | }
119 |
120 | // wildcard condition
121 | if (isWildcard(this.version)) {
122 | return true;
123 | }
124 |
125 | if (isWildcard(this.group)) {
126 | return true;
127 | }
128 |
129 | // range condition
130 | if (!StringUtils.isEquals(this.version, concreteServiceName.version)
131 | && !matchRange(this.version, concreteServiceName.version)) {
132 | return false;
133 | }
134 |
135 | if (!StringUtils.isEquals(this.group, concreteServiceName.group) &&
136 | !matchRange(this.group, concreteServiceName.group)) {
137 | return false;
138 | }
139 |
140 | return true;
141 | }
142 |
143 | private boolean matchRange(String range, String value) {
144 | if (isBlank(range)) {
145 | return true;
146 | }
147 | if (!isRange(range)) {
148 | return false;
149 | }
150 | String[] values = range.split(VALUE_SEPARATOR);
151 | return Arrays.asList(values).contains(value);
152 | }
153 |
154 | private boolean isConcrete(String value) {
155 | return !isWildcard(value) && !isRange(value);
156 | }
157 |
158 | private boolean isWildcard(String value) {
159 | return WILDCARD.equals(value);
160 | }
161 |
162 | private boolean isRange(String value) {
163 | return value != null && value.indexOf(VALUE_SEPARATOR) > -1 && value.split(VALUE_SEPARATOR).length > 1;
164 | }
165 |
166 | public String getCategory() {
167 | return category;
168 | }
169 |
170 | public void setCategory(String category) {
171 | this.category = category;
172 | }
173 |
174 | public String getServiceInterface() {
175 | return serviceInterface;
176 | }
177 |
178 | public void setServiceInterface(String serviceInterface) {
179 | this.serviceInterface = serviceInterface;
180 | }
181 |
182 | public String getVersion() {
183 | return version;
184 | }
185 |
186 | public void setVersion(String version) {
187 | this.version = version;
188 | }
189 |
190 | public String getGroup() {
191 | return group;
192 | }
193 |
194 | public void setGroup(String group) {
195 | this.group = group;
196 | }
197 |
198 | public String getValue() {
199 | if (value == null) {
200 | value = toValue();
201 | }
202 | return value;
203 | }
204 |
205 | private String toValue() {
206 | return new StringBuilder(category)
207 | .append(NAME_SEPARATOR).append(serviceInterface)
208 | .append(NAME_SEPARATOR).append(version)
209 | .append(NAME_SEPARATOR).append(group)
210 | .toString();
211 | }
212 |
213 | @Override
214 | public boolean equals(Object o) {
215 | if (this == o) {
216 | return true;
217 | }
218 | if (!(o instanceof NacosServiceName)) {
219 | return false;
220 | }
221 | NacosServiceName that = (NacosServiceName) o;
222 | return Objects.equals(getValue(), that.getValue());
223 | }
224 |
225 | @Override
226 | public int hashCode() {
227 | return Objects.hash(getValue());
228 | }
229 |
230 | @Override
231 | public String toString() {
232 | return getValue();
233 | }
234 | }
235 |
--------------------------------------------------------------------------------
/src/main/java/com/alibaba/dubbo/registry/nacos/util/NacosInstanceManageUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.alibaba.dubbo.registry.nacos.util;
18 |
19 | import org.apache.dubbo.common.utils.CollectionUtils;
20 |
21 | import com.alibaba.nacos.api.naming.pojo.Instance;
22 | import com.google.common.collect.Lists;
23 | import com.google.common.collect.Maps;
24 |
25 | import java.util.List;
26 | import java.util.Map;
27 | import java.util.Set;
28 |
29 | /**
30 | * Instance manage util for multiple serviceNames
31 | * To resolve bug with https://github.com/apache/dubbo/issues/5885 and https://github.com/apache/dubbo/issues/5899
32 | *
33 | * @author laddcn
34 | * @since 2.7.6
35 | */
36 | public class NacosInstanceManageUtil {
37 |
38 | /**
39 | * serviceName -> refreshed instance list
40 | */
41 | private static final Map> SERVICE_INSTANCE_LIST_MAP = Maps.newConcurrentMap();
42 |
43 | /**
44 | * serviceName -> corresponding serviceName list
45 | */
46 | private static final Map> CORRESPONDING_SERVICE_NAMES_MAP = Maps.newConcurrentMap();
47 |
48 | public static void setCorrespondingServiceNames(String serviceName, Set serviceNames) {
49 | CORRESPONDING_SERVICE_NAMES_MAP.put(serviceName, serviceNames);
50 | }
51 |
52 | public static void initOrRefreshServiceInstanceList(String serviceName, List instanceList) {
53 | SERVICE_INSTANCE_LIST_MAP.put(serviceName, instanceList);
54 | }
55 |
56 | public static List getAllCorrespondingServiceInstanceList(String serviceName) {
57 | if (!CORRESPONDING_SERVICE_NAMES_MAP.containsKey(serviceName)) {
58 | return Lists.newArrayList();
59 | }
60 | List allInstances = Lists.newArrayList();
61 | for (String correspondingServiceName : CORRESPONDING_SERVICE_NAMES_MAP.get(serviceName)) {
62 | if (SERVICE_INSTANCE_LIST_MAP.containsKey(correspondingServiceName) && CollectionUtils.isNotEmpty(SERVICE_INSTANCE_LIST_MAP.get(correspondingServiceName))) {
63 | allInstances.addAll(SERVICE_INSTANCE_LIST_MAP.get(correspondingServiceName));
64 | }
65 | }
66 | return allInstances;
67 | }
68 |
69 | }
--------------------------------------------------------------------------------
/src/main/java/com/alibaba/dubbo/registry/nacos/util/NacosNamingServiceUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.alibaba.dubbo.registry.nacos.util;
18 |
19 | import org.apache.dubbo.common.URL;
20 | import org.apache.dubbo.common.logger.Logger;
21 | import org.apache.dubbo.common.logger.LoggerFactory;
22 | import org.apache.dubbo.registry.client.DefaultServiceInstance;
23 | import org.apache.dubbo.registry.client.ServiceInstance;
24 |
25 | import com.alibaba.nacos.api.NacosFactory;
26 | import com.alibaba.nacos.api.PropertyKeyConst;
27 | import com.alibaba.nacos.api.exception.NacosException;
28 | import com.alibaba.nacos.api.naming.NamingService;
29 | import com.alibaba.nacos.api.naming.pojo.Instance;
30 |
31 | import java.lang.reflect.Field;
32 | import java.util.Objects;
33 | import java.util.Properties;
34 | import java.util.stream.Stream;
35 |
36 | import static com.alibaba.nacos.api.PropertyKeyConst.NAMING_LOAD_CACHE_AT_START;
37 | import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
38 | import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
39 | import static com.alibaba.nacos.client.naming.utils.UtilAndComs.NACOS_NAMING_LOG_NAME;
40 | import static java.lang.reflect.Modifier.isFinal;
41 | import static java.lang.reflect.Modifier.isPublic;
42 | import static java.lang.reflect.Modifier.isStatic;
43 | import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;
44 | import static org.apache.dubbo.common.utils.StringUtils.isEmpty;
45 | import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;
46 |
47 | /**
48 | * The utilities class for {@link NamingService}
49 | *
50 | * @since 2.7.5
51 | */
52 | public class NacosNamingServiceUtils {
53 |
54 | private static final Logger logger = LoggerFactory.getLogger(NacosNamingServiceUtils.class);
55 |
56 | private static final String[] NACOS_PROPERTY_NAMES;
57 |
58 | static {
59 | NACOS_PROPERTY_NAMES = initNacosPropertyNames();
60 | }
61 |
62 | private static String[] initNacosPropertyNames() {
63 | return Stream.of(PropertyKeyConst.class.getFields())
64 | .filter(f -> isStatic(f.getModifiers())) // static
65 | .filter(f -> isPublic(f.getModifiers())) // public
66 | .filter(f -> isFinal(f.getModifiers())) // final
67 | .filter(f -> String.class.equals(f.getType())) // String type
68 | .map(NacosNamingServiceUtils::getConstantValue)
69 | .filter(Objects::nonNull)
70 | .map(String::valueOf)
71 | .toArray(String[]::new);
72 | }
73 |
74 | private static Object getConstantValue(Field field) {
75 | Object value = null;
76 | try {
77 | value = field.get(null);
78 | } catch (IllegalAccessException e) {
79 | }
80 | return value;
81 | }
82 |
83 | /**
84 | * Convert the {@link ServiceInstance} to {@link Instance}
85 | *
86 | * @param serviceInstance {@link ServiceInstance}
87 | * @return non-null
88 | * @since 2.7.5
89 | */
90 | public static Instance toInstance(ServiceInstance serviceInstance) {
91 | Instance instance = new Instance();
92 | instance.setInstanceId(serviceInstance.getId());
93 | instance.setServiceName(serviceInstance.getServiceName());
94 | instance.setIp(serviceInstance.getHost());
95 | instance.setPort(serviceInstance.getPort());
96 | instance.setMetadata(serviceInstance.getMetadata());
97 | instance.setEnabled(serviceInstance.isEnabled());
98 | instance.setHealthy(serviceInstance.isHealthy());
99 | return instance;
100 | }
101 |
102 | /**
103 | * Convert the {@link Instance} to {@link ServiceInstance}
104 | *
105 | * @param instance {@link Instance}
106 | * @return non-null
107 | * @since 2.7.5
108 | */
109 | public static ServiceInstance toServiceInstance(Instance instance) {
110 | DefaultServiceInstance serviceInstance = new DefaultServiceInstance(instance.getInstanceId(),
111 | instance.getServiceName(), instance.getIp(), instance.getPort());
112 | serviceInstance.setMetadata(instance.getMetadata());
113 | serviceInstance.setEnabled(instance.isEnabled());
114 | serviceInstance.setHealthy(instance.isHealthy());
115 | return serviceInstance;
116 | }
117 |
118 | /**
119 | * The group of {@link NamingService} to register
120 | *
121 | * @param connectionURL {@link URL connection url}
122 | * @return non-null, "default" as default
123 | * @since 2.7.5
124 | */
125 | public static String getGroup(URL connectionURL) {
126 | return connectionURL.getParameter("nacos.group", DEFAULT_GROUP);
127 | }
128 |
129 | /**
130 | * Create an instance of {@link NamingService} from specified {@link URL connection url}
131 | *
132 | * @param connectionURL {@link URL connection url}
133 | * @return {@link NamingService}
134 | * @since 2.7.5
135 | */
136 | public static NamingService createNamingService(URL connectionURL) {
137 | Properties nacosProperties = buildNacosProperties(connectionURL);
138 | NamingService namingService;
139 | try {
140 | namingService = NacosFactory.createNamingService(nacosProperties);
141 | } catch (NacosException e) {
142 | if (logger.isErrorEnabled()) {
143 | logger.error(e.getErrMsg(), e);
144 | }
145 | throw new IllegalStateException(e);
146 | }
147 | return namingService;
148 | }
149 |
150 | private static Properties buildNacosProperties(URL url) {
151 | Properties properties = new Properties();
152 | setServerAddr(url, properties);
153 | setProperties(url, properties);
154 | return properties;
155 | }
156 |
157 | private static void setServerAddr(URL url, Properties properties) {
158 | StringBuilder serverAddrBuilder =
159 | new StringBuilder(url.getHost()) // Host
160 | .append(":")
161 | .append(url.getPort()); // Port
162 |
163 | // Append backup parameter as other servers
164 | String backup = url.getParameter(BACKUP_KEY);
165 | if (backup != null) {
166 | serverAddrBuilder.append(",").append(backup);
167 | }
168 |
169 | String serverAddr = serverAddrBuilder.toString();
170 | properties.put(SERVER_ADDR, serverAddr);
171 | }
172 |
173 | private static void setProperties(URL url, Properties properties) {
174 |
175 | putPropertyIfAbsent(url, properties, NACOS_NAMING_LOG_NAME);
176 | putPropertyIfAbsent(url, properties, NAMING_LOAD_CACHE_AT_START, "true");
177 |
178 | for (String propertyName : NACOS_PROPERTY_NAMES) {
179 | putPropertyIfAbsent(url, properties, propertyName);
180 | }
181 | }
182 |
183 | private static void putPropertyIfAbsent(URL url, Properties properties, String propertyName) {
184 | putPropertyIfAbsent(url, properties, propertyName, null);
185 | }
186 |
187 | private static void putPropertyIfAbsent(URL url, Properties properties, String propertyName, String defaultValue) {
188 | String propertyValue = url.getParameter(propertyName);
189 | putPropertyIfAbsent(properties, propertyName, propertyValue, defaultValue);
190 | }
191 |
192 | private static void putPropertyIfAbsent(Properties properties, String propertyName, String propertyValue) {
193 | putPropertyIfAbsent(properties, propertyName, propertyValue, null);
194 | }
195 |
196 | private static void putPropertyIfAbsent(Properties properties, String propertyName, String propertyValue,
197 | String defaultValue) {
198 | if (isEmpty(propertyName) && properties.containsKey(propertyName)) {
199 | return;
200 | }
201 |
202 | String value = isEmpty(propertyValue) ? defaultValue : propertyValue;
203 |
204 | if (isNotEmpty(value)) {
205 | properties.setProperty(propertyName, value);
206 | }
207 | }
208 | }
--------------------------------------------------------------------------------
/src/main/resources/META-INF/dubbo/org.apache.dubbo.registry.RegistryFactory:
--------------------------------------------------------------------------------
1 | nacos=com.alibaba.dubbo.registry.nacos.NacosRegistryFactory
--------------------------------------------------------------------------------
/src/main/resources/META-INF/dubbo/org.apache.dubbo.registry.client.ServiceDiscovery:
--------------------------------------------------------------------------------
1 | nacos=com.alibaba.dubbo.registry.nacos.NacosServiceDiscovery
--------------------------------------------------------------------------------
/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.alibaba.dubbo.demo.consumer;
18 |
19 | import org.apache.dubbo.config.annotation.Reference;
20 | import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
21 |
22 | import com.alibaba.dubbo.demo.service.DemoService;
23 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
24 | import org.springframework.context.annotation.PropertySource;
25 |
26 | import javax.annotation.PostConstruct;
27 | import java.io.IOException;
28 | import java.util.concurrent.TimeUnit;
29 |
30 | /**
31 | * {@link DemoService} consumer demo
32 | */
33 | @EnableDubbo
34 | @PropertySource(value = "classpath:/consumer-config.properties")
35 | public class DemoServiceConsumerBootstrap {
36 |
37 | @Reference(version = "${demo.service.version}")
38 | private DemoService demoService;
39 |
40 | @PostConstruct
41 | public void init() throws InterruptedException {
42 | for (int i = 0; i < 20; i++) {
43 | for (int j = 0; j < 10; j++) {
44 | System.out.println(demoService.sayName("小马哥(mercyblitz)"));
45 | }
46 | Thread.sleep(TimeUnit.SECONDS.toMillis(5));
47 | }
48 | }
49 |
50 | public static void main(String[] args) throws IOException {
51 | AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
52 | context.register(DemoServiceConsumerBootstrap.class);
53 | context.refresh();
54 | System.in.read();
55 | context.close();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.alibaba.dubbo.demo.consumer;
18 |
19 | import com.alibaba.dubbo.demo.service.DemoService;
20 |
21 | import org.springframework.context.support.ClassPathXmlApplicationContext;
22 |
23 | import java.io.IOException;
24 |
25 | /**
26 | * {@link DemoService} consumer demo XML bootstrap
27 | */
28 | public class DemoServiceConsumerXmlBootstrap {
29 |
30 | public static void main(String[] args) throws IOException {
31 | ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
32 | context.setConfigLocation("/META-INF/spring/dubbo-consumer-context.xml");
33 | context.refresh();
34 | System.out.println("DemoService consumer (XML) is starting...");
35 | DemoService demoService = context.getBean("demoService", DemoService.class);
36 | for (int i = 0; i < 10; i++) {
37 | System.out.println(demoService.sayName("小马哥(mercyblitz)"));
38 | }
39 | System.in.read();
40 | context.close();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderBootstrap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.alibaba.dubbo.demo.provider;
18 |
19 | import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
20 |
21 | import com.alibaba.dubbo.demo.service.DemoService;
22 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
23 | import org.springframework.context.annotation.PropertySource;
24 |
25 | import java.io.IOException;
26 |
27 | /**
28 | * {@link DemoService} provider demo
29 | */
30 | @EnableDubbo(scanBasePackages = "com.alibaba.dubbo.demo.service")
31 | @PropertySource(value = "classpath:/provider-config.properties")
32 | public class DemoServiceProviderBootstrap {
33 |
34 | public static void main(String[] args) throws IOException {
35 | AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
36 | context.register(DemoServiceProviderBootstrap.class);
37 | context.refresh();
38 | System.out.println("DemoService provider is starting...");
39 | System.in.read();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.alibaba.dubbo.demo.provider;
18 |
19 | import com.alibaba.dubbo.demo.service.DemoService;
20 |
21 | import org.springframework.context.support.ClassPathXmlApplicationContext;
22 |
23 | import java.io.IOException;
24 |
25 | /**
26 | * {@link DemoService} provider demo XML bootstrap
27 | */
28 | public class DemoServiceProviderXmlBootstrap {
29 |
30 | public static void main(String[] args) throws IOException {
31 | ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
32 | context.setConfigLocation("/META-INF/spring/dubbo-provider-context.xml");
33 | context.refresh();
34 | System.out.println("DemoService provider (XML) is starting...");
35 | System.in.read();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/test/java/com/alibaba/dubbo/demo/service/DefaultService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.alibaba.dubbo.demo.service;
18 |
19 | import org.apache.dubbo.config.annotation.Service;
20 | import org.apache.dubbo.rpc.RpcContext;
21 |
22 | import org.springframework.beans.factory.annotation.Value;
23 |
24 |
25 | /**
26 | * Default {@link DemoService}
27 | *
28 | * @since 2.6.5
29 | */
30 | @Service(version = "${demo.service.version}")
31 | public class DefaultService implements DemoService {
32 |
33 | @Value("${demo.service.name}")
34 | private String serviceName;
35 |
36 | public String sayName(String name) {
37 | RpcContext rpcContext = RpcContext.getContext();
38 | return String.format("Service [name :%s , port : %d] %s(\"%s\") : Hello,%s",
39 | serviceName,
40 | rpcContext.getLocalPort(),
41 | rpcContext.getMethodName(),
42 | name,
43 | name);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/java/com/alibaba/dubbo/demo/service/DemoService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.alibaba.dubbo.demo.service;
18 |
19 | /**
20 | * DemoService
21 | *
22 | * @since 2.6.5
23 | */
24 | public interface DemoService {
25 |
26 | String sayName(String name);
27 |
28 | }
--------------------------------------------------------------------------------
/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactoryTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.alibaba.dubbo.registry.nacos;
18 |
19 | /**
20 | * {@link NacosRegistryFactory} Test
21 | *
22 | * @since 2.6.5
23 | */
24 | public class NacosRegistryFactoryTest {
25 | }
26 |
--------------------------------------------------------------------------------
/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.alibaba.dubbo.registry.nacos;
18 |
19 | /**
20 | * {@link NacosRegistry} Test
21 | *
22 | * @since 2.6.5
23 | */
24 | public class NacosRegistryTest {
25 |
26 | // Test case Dubbo OPS :
27 | // URL : admin://30.5.124.12?category=providers,consumers,routers,configurators&check=false&classifier=*&enabled=*&group=*&interface=*&version=*
28 | public void testDoSubscribeForDubboOps() {
29 |
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/test/resources/META-INF/spring/dubbo-consumer-context.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/test/resources/META-INF/spring/dubbo-provider-context.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/test/resources/consumer-config.properties:
--------------------------------------------------------------------------------
1 | ## Dubbo Application info
2 | dubbo.application.name = dubbo-consumer-demo
3 |
4 | ## Nacos registry address
5 | dubbo.registry.address = nacos://127.0.0.1:8848/?encode=UTF-88&username=nacos&password=nacos
6 |
7 | # @Reference version
8 | demo.service.version= 1.0.0
--------------------------------------------------------------------------------
/src/test/resources/provider-config.properties:
--------------------------------------------------------------------------------
1 | ## Dubbo Application info
2 | dubbo.application.name = dubbo-provider-demo
3 |
4 | ## Nacos registry address
5 | dubbo.registry.protocol = nacos
6 | dubbo.registry.address = nacos://127.0.0.1:8848/?encode=UTF-8&username=nacos&password=nacos
7 |
8 | ## Dubbo Protocol using random port
9 | dubbo.protocol.name = dubbo
10 | dubbo.protocol.port = -1
11 |
12 | # Provider @Service info
13 | demo.service.version=1.0.0
14 | demo.service.name = demoService
--------------------------------------------------------------------------------