You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by mi...@apache.org on 2019/02/25 09:26:33 UTC
[incubator-dubbo] branch 2.6.x updated: [Enhancement] inline the
source code of spring-context-support (#3225)
This is an automated email from the ASF dual-hosted git repository.
min pushed a commit to branch 2.6.x
in repository https://gitbox.apache.org/repos/asf/incubator-dubbo.git
The following commit(s) were added to refs/heads/2.6.x by this push:
new fec3363 [Enhancement] inline the source code of spring-context-support (#3225)
fec3363 is described below
commit fec3363b749140dd7c96a4009f826f84c2941a82
Author: Mercy Ma <me...@gmail.com>
AuthorDate: Mon Feb 25 17:26:06 2019 +0800
[Enhancement] inline the source code of spring-context-support (#3225)
* Manually merge pull request #1486, to make travis ci and codecov work after apache incubator transition.
* Polish alibaba/dubbo#1306
* Optimize imports
* Optimize imports
* Remove invalid JavaDoc
* Update DubboConfigBinder.java
Remove invalid JavaDoc
* Fix apache/incubator-dubbo#1653
* Fixed apache/incubator-dubbo#1772
* Reactor ReferenceAnnotationBeanPostProcessor
* Fixed incubator-dubbo-spring-boot-project#243
* Add ServiceBeanNameBuilder
* Polish apache/incubator-dubbo/#2235
* Polish incubator-dubbo#2251
* Update spring-context-supprt version to be release
* Rename ServiceBeanExportEvent to be ServiceBeanExportedEvent
* Poblish apache/incubator-dubbo#2297
* Polish apache/incubator-dubbo#2301
* Polish apache/incubator-dubbo#2315
* Polish apache/incubator-dubbo#2897 : DubboConfigConfigurationSelector precedence is too high
* Polish apache/incubator-dubbo#2897 : implements ImportBeanDefinitionRegistrar in order to reduce precedence
* Polish apache/incubator-dubbo#2897 : rename DubboConfigConfigurationSelector to DubboConfigConfigurationRegistrar
* Polish apache/incubator-dubbo#3192 : inline the source code of spring-context-support
* Fixed the issues of the test-cases
* Polish apache/incubator-dubbo#3193 : [Enhancement] Change the default behavior of @EnableDubboConfig.multiple()
* Polish apache/incubator-dubbo#3192 : inline the source code of spring-context-support
* Polish apache/incubator-dubbo#3189 Simplify externalized configuration of Dubbo Protocol name
* Polish apache/incubator-dubbo#3193
* Polish apache/incubator-dubbo#2987
* Polish apache/incubator-dubbo#3355 : Add the "protocol" attribute
* Polish apache/incubator-dubbo#3355 : Still exists the issues in service discovery.
* Polish apache/incubator-dubbo#3355 : fix the issues in samples
* Polish apache/incubator-dubbo#3355 : fix the issues in samples
* Polish apache/incubator-dubbo#3296 : Merge and enhancement dubbo-registry-nacos
* Polish apache/incubator-dubbo#3251 : @Service supports the hierarchical interface
* Polish apache/incubator-dubbo#3275 : ReferenceBeanInvocationHandler does not throw the actual exception
* Polish apache/incubator-dubbo#3429 : Fix the NPE
* add license header
* Polish apache/incubator-dubbo#3296 : Supports Docker
---
dependencies-bom/pom.xml | 12 +-
.../alibaba/dubbo/config/annotation/Reference.java | 238 ++++-----
dubbo-config/dubbo-config-spring/pom.xml | 93 +++-
.../AbstractAnnotationConfigBeanBuilder.java | 4 +-
.../annotation/AnnotationBeanNameBuilder.java | 142 ++++++
.../AnnotationInjectedBeanPostProcessor.java | 529 +++++++++++++++++++++
.../AnnotationPropertyValuesAdapter.java | 2 +-
.../DubboConfigBindingBeanPostProcessor.java | 56 ++-
.../ReferenceAnnotationBeanPostProcessor.java | 23 +-
.../factory/annotation/ReferenceBeanBuilder.java | 4 +-
.../ServiceAnnotationBeanPostProcessor.java | 13 +-
.../factory/annotation/ServiceBeanNameBuilder.java | 2 +
.../annotation/DubboConfigBindingRegistrar.java | 14 +-
...java => DubboConfigConfigurationRegistrar.java} | 35 +-
.../spring/context/annotation/EnableDubbo.java | 2 +-
.../context/annotation/EnableDubboConfig.java | 13 +-
.../context/config/DubboConfigBeanCustomizer.java | 46 ++
...pertyDefaultValueDubboConfigBeanCustomizer.java | 75 +++
.../properties/DefaultDubboConfigBinder.java | 2 +-
.../spring/extension/SpringExtensionFactory.java | 222 ++++-----
.../spring/status/DataSourceStatusChecker.java | 192 ++++----
.../config/spring/status/SpringStatusChecker.java | 184 +++----
.../util/AnnotatedBeanDefinitionRegistryUtils.java | 62 +++
.../dubbo/config/spring/util/AnnotationUtils.java | 214 ++++++++-
.../dubbo/config/spring/util/BeanFactoryUtils.java | 63 ++-
.../dubbo/config/spring/util/BeanRegistrar.java | 2 +-
.../dubbo/config/spring/util/ClassUtils.java} | 21 +-
.../dubbo/config/spring/util/ObjectUtils.java} | 21 +-
.../config/spring/util/PropertySourcesUtils.java | 112 +++++
.../dubbo/config/spring/api/HelloService.java | 9 +-
...est.java => AnnotationBeanNameBuilderTest.java} | 47 +-
.../DubboConfigBindingBeanPostProcessorTest.java | 50 +-
.../ReferenceAnnotationBeanPostProcessorTest.java | 6 +-
.../annotation/ReferenceBeanBuilderTest.java | 124 +++++
.../annotation/ServiceBeanNameBuilderTest.java | 1 +
.../annotation/multiple/EmbeddedZooKeeper.java | 252 ++++++++++
.../consumer/MultipleProtocolsServiceConsumer.java | 77 +++
.../multiple/provider/DefaultHelloService.java} | 14 +-
.../MultipleProtocolsServiceProvider.java} | 48 +-
.../DubboComponentScanRegistrarTest.java | 26 +
.../DubboConfigBindingRegistrarTest.java | 14 +-
.../DubboConfigBindingsRegistrarTest.java | 2 +-
.../annotation/DubboConfigConfigurationTest.java | 4 +-
.../context/annotation/EnableDubboConfigTest.java | 31 +-
.../spring/context/annotation/EnableDubboTest.java | 38 +-
.../annotation/provider/DemoServiceImpl.java | 9 +-
.../AnnotatedBeanDefinitionRegistryUtilsTest.java | 59 +++
.../spring/util/PropertySourcesUtilsTest.java | 80 ++++
.../src/test/resources/META-INF/config.properties | 6 +-
.../resources/META-INF/dubbo-common.properties | 2 +
.../multiple-protocols-consumer.properties | 1 +
.../multiple-protocols-provider.properties | 6 +
.../META-INF/spring/dubbo-rest-consumer.xml | 32 ++
.../dubbo/registry/support/DubboRegistration.java | 93 ++++
.../dubbo/registry/support/Registration.java | 37 +-
.../registry/support/ServiceInstanceRegistry.java | 474 ++++++++++++++++++
dubbo-registry/dubbo-registry-nacos/pom.xml | 160 +++++++
.../dubbo/registry/nacos/NacosRegistry.java | 198 ++++++++
.../dubbo/registry/nacos/NacosRegistryFactory.java | 108 +++++
.../com.alibaba.dubbo.registry.RegistryFactory | 1 +
.../consumer/DemoServiceConsumerBootstrap.java | 59 +++
.../consumer/DemoServiceConsumerXmlBootstrap.java | 42 ++
.../provider/DemoServiceProviderBootstrap.java | 45 +-
.../provider/DemoServiceProviderXmlBootstrap.java | 21 +-
.../alibaba/dubbo/demo/service/DefaultService.java | 46 ++
.../alibaba/dubbo/demo/service/DemoService.java | 20 +-
.../registry/nacos/NacosRegistryFactoryTest.java | 11 +-
.../dubbo/registry/nacos/NacosRegistryTest.java | 16 +-
.../META-INF/spring/dubbo-consumer-context.xml | 16 +
.../META-INF/spring/dubbo-provider-context.xml | 21 +
.../src/test/resources/consumer-config.properties | 6 +
.../src/test/resources/provider-config.properties | 14 +
dubbo-registry/pom.xml | 1 +
.../dubbo/rpc/protocol/rest/RestProtocol.java | 10 +-
74 files changed, 4081 insertions(+), 654 deletions(-)
diff --git a/dependencies-bom/pom.xml b/dependencies-bom/pom.xml
index 205abac..cf8f2ec 100644
--- a/dependencies-bom/pom.xml
+++ b/dependencies-bom/pom.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
@@ -101,6 +102,7 @@
<rs_api_version>2.0</rs_api_version>
<resteasy_version>3.0.19.Final</resteasy_version>
<tomcat_embed_version>8.5.31</tomcat_embed_version>
+
<!-- Log libs -->
<slf4j_version>1.7.25</slf4j_version>
<jcl_version>1.2</jcl_version>
@@ -302,6 +304,7 @@
<artifactId>tomcat-embed-logging-juli</artifactId>
<version>${tomcat_embed_version}</version>
</dependency>
+
<!-- Log libs -->
<dependency>
<groupId>org.slf4j</groupId>
@@ -363,13 +366,6 @@
<!-- Alibaba extensions -->
- <!-- Spring Context Support -->
- <dependency>
- <groupId>com.alibaba.spring</groupId>
- <artifactId>spring-context-support</artifactId>
- <version>${alibaba_spring_context_support_version}</version>
- </dependency>
-
<!-- YAML -->
<dependency>
<groupId>org.yaml</groupId>
diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/annotation/Reference.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/annotation/Reference.java
index c043cb3..b3a93d7 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/annotation/Reference.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/annotation/Reference.java
@@ -1,115 +1,123 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.alibaba.dubbo.config.annotation;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Reference
- *
- * @export
- */
-@Documented
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
-public @interface Reference {
-
- Class<?> interfaceClass() default void.class;
-
- String interfaceName() default "";
-
- String version() default "";
-
- String group() default "";
-
- String url() default "";
-
- String client() default "";
-
- boolean generic() default false;
-
- boolean injvm() default false;
-
- boolean check() default true;
-
- boolean init() default false;
-
- boolean lazy() default false;
-
- boolean stubevent() default false;
-
- String reconnect() default "";
-
- boolean sticky() default false;
-
- String proxy() default "";
-
- String stub() default "";
-
- String cluster() default "";
-
- int connections() default 0;
-
- int callbacks() default 0;
-
- String onconnect() default "";
-
- String ondisconnect() default "";
-
- String owner() default "";
-
- String layer() default "";
-
- int retries() default 2;
-
- String loadbalance() default "";
-
- boolean async() default false;
-
- int actives() default 0;
-
- boolean sent() default false;
-
- String mock() default "";
-
- String validation() default "";
-
- int timeout() default 0;
-
- String cache() default "";
-
- String[] filter() default {};
-
- String[] listener() default {};
-
- String[] parameters() default {};
-
- String application() default "";
-
- String module() default "";
-
- String consumer() default "";
-
- String monitor() default "";
-
- String[] registry() default {};
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Reference
+ *
+ * @export
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+public @interface Reference {
+
+ Class<?> interfaceClass() default void.class;
+
+ String interfaceName() default "";
+
+ String version() default "";
+
+ String group() default "";
+
+ String url() default "";
+
+ String client() default "";
+
+ boolean generic() default false;
+
+ boolean injvm() default false;
+
+ boolean check() default true;
+
+ boolean init() default false;
+
+ boolean lazy() default false;
+
+ boolean stubevent() default false;
+
+ String reconnect() default "";
+
+ boolean sticky() default false;
+
+ String proxy() default "";
+
+ String stub() default "";
+
+ String cluster() default "";
+
+ int connections() default 0;
+
+ int callbacks() default 0;
+
+ String onconnect() default "";
+
+ String ondisconnect() default "";
+
+ String owner() default "";
+
+ String layer() default "";
+
+ int retries() default 2;
+
+ String loadbalance() default "";
+
+ boolean async() default false;
+
+ int actives() default 0;
+
+ boolean sent() default false;
+
+ String mock() default "";
+
+ String validation() default "";
+
+ int timeout() default 0;
+
+ String cache() default "";
+
+ String[] filter() default {};
+
+ String[] listener() default {};
+
+ String[] parameters() default {};
+
+ String application() default "";
+
+ String module() default "";
+
+ String consumer() default "";
+
+ String monitor() default "";
+
+ String[] registry() default {};
+
+ /**
+ * The communication protocol of Dubbo Service
+ *
+ * @return the default value is ""
+ * @since 2.6.6
+ */
+ String protocol() default "";
+
+}
diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml
index f2c29c3..e6f895f 100644
--- a/dubbo-config/dubbo-config-spring/pom.xml
+++ b/dubbo-config/dubbo-config-spring/pom.xml
@@ -14,7 +14,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.alibaba</groupId>
@@ -47,91 +48,173 @@
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
- <groupId>com.alibaba.spring</groupId>
- <artifactId>spring-context-support</artifactId>
- </dependency>
- <dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
+
+ <!-- Test -->
+ <!-- Netty -->
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- REST support dependencies -->
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxrs</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-client</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-netty4</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.validation</groupId>
+ <artifactId>validation-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jackson-provider</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxb-provider</artifactId>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-registry-default</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>dubbo-registry-zookeeper</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-monitor-default</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-rpc-dubbo</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>dubbo-rpc-rest</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-rpc-rmi</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-rpc-injvm</artifactId>
<version>${project.parent.version}</version>
</dependency>
+
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-remoting-netty4</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-serialization-hessian2</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<scope>test</scope>
</dependency>
+ <!-- Zookeeper -->
+ <dependency>
+ <groupId>org.apache.zookeeper</groupId>
+ <artifactId>zookeeper</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.curator</groupId>
+ <artifactId>curator-framework</artifactId>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
<build>
<plugins>
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java
index 7a4129f..0357ff0 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java
@@ -30,8 +30,8 @@ import org.springframework.util.Assert;
import java.lang.annotation.Annotation;
import java.util.List;
-import static com.alibaba.spring.util.BeanFactoryUtils.getBeans;
-import static com.alibaba.spring.util.BeanFactoryUtils.getOptionalBean;
+import static com.alibaba.dubbo.config.spring.util.BeanFactoryUtils.getBeans;
+import static com.alibaba.dubbo.config.spring.util.BeanFactoryUtils.getOptionalBean;
/**
* Abstract Configurable {@link Annotation} Bean Builder
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java
new file mode 100644
index 0000000..cf72a4a
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.spring.beans.factory.annotation;
+
+import com.alibaba.dubbo.common.Constants;
+import com.alibaba.dubbo.config.annotation.Reference;
+import com.alibaba.dubbo.config.annotation.Service;
+import com.alibaba.dubbo.registry.Registry;
+
+import org.springframework.core.env.Environment;
+
+import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY;
+import static com.alibaba.dubbo.common.Constants.DEFAULT_PROTOCOL;
+import static com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY;
+import static com.alibaba.dubbo.config.spring.util.AnnotationUtils.resolveInterfaceName;
+import static org.springframework.util.StringUtils.arrayToCommaDelimitedString;
+import static org.springframework.util.StringUtils.hasText;
+
+/**
+ * The Bean Name Builder for the annotations {@link Service} and {@link Reference}
+ * <p>
+ * The naming rule is consistent with the the implementation {@link Registry} that is based on the service-name aware
+ * infrastructure, e.g Spring Cloud, Cloud Native and so on.
+ * <p>
+ * The pattern of bean name : ${category}:${protocol}:${serviceInterface}:${version}:${group}.
+ * <p>
+ * ${version} and ${group} are optional.
+ *
+ * @since 2.6.6
+ */
+class AnnotationBeanNameBuilder {
+
+ private static final String SEPARATOR = ":";
+
+ // Required properties
+
+ private final String category;
+
+ private final String protocol;
+
+ private final String interfaceClassName;
+
+ // Optional properties
+
+ private String version;
+
+ private String group;
+
+ private Environment environment;
+
+ private AnnotationBeanNameBuilder(String category, String protocol, String interfaceClassName) {
+ this.category = category;
+ this.protocol = protocol;
+ this.interfaceClassName = interfaceClassName;
+ }
+
+ private AnnotationBeanNameBuilder(Service service, Class<?> interfaceClass) {
+ this(PROVIDERS_CATEGORY, resolveProtocol(service.protocol()), resolveInterfaceName(service, interfaceClass));
+ this.group(service.group());
+ this.version(service.version());
+ }
+
+ private AnnotationBeanNameBuilder(Reference reference, Class<?> interfaceClass) {
+ this(CONSUMERS_CATEGORY, resolveProtocol(reference.protocol()), resolveInterfaceName(reference, interfaceClass));
+ this.group(reference.group());
+ this.version(reference.version());
+ }
+
+ public static AnnotationBeanNameBuilder create(Service service, Class<?> interfaceClass) {
+ return new AnnotationBeanNameBuilder(service, interfaceClass);
+ }
+
+ public static AnnotationBeanNameBuilder create(Reference reference, Class<?> interfaceClass) {
+ return new AnnotationBeanNameBuilder(reference, interfaceClass);
+ }
+
+ private static void append(StringBuilder builder, String value) {
+ if (hasText(value)) {
+ builder.append(SEPARATOR).append(value);
+ }
+ }
+
+ public AnnotationBeanNameBuilder group(String group) {
+ this.group = group;
+ return this;
+ }
+
+ public AnnotationBeanNameBuilder version(String version) {
+ this.version = version;
+ return this;
+ }
+
+ public AnnotationBeanNameBuilder environment(Environment environment) {
+ this.environment = environment;
+ return this;
+ }
+
+ /**
+ * Resolve the protocol
+ *
+ * @param protocols one or more protocols
+ * @return if <code>protocols</code> == <code>null</code>, it will return
+ * {@link Constants#DEFAULT_PROTOCOL "dubbo"} as the default protocol
+ * @see Constants#DEFAULT_PROTOCOL
+ */
+ private static String resolveProtocol(String... protocols) {
+ String protocol = arrayToCommaDelimitedString(protocols);
+ return hasText(protocol) ? protocol : DEFAULT_PROTOCOL;
+ }
+
+ /**
+ * Build bean name while resolve the placeholders if possible.
+ *
+ * @return pattern : ${category}:${protocol}:${serviceInterface}:${version}:${group}
+ */
+ public String build() {
+ // Append the required properties
+ StringBuilder beanNameBuilder = new StringBuilder(category);
+ append(beanNameBuilder, protocol);
+ append(beanNameBuilder, interfaceClassName);
+ // Append the optional properties
+ append(beanNameBuilder, version);
+ append(beanNameBuilder, group);
+ String beanName = beanNameBuilder.toString();
+ // Resolve placeholders
+ return environment != null ? environment.resolvePlaceholders(beanName) : beanName;
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java
new file mode 100644
index 0000000..95ecdfb
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java
@@ -0,0 +1,529 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.spring.beans.factory.annotation;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.PropertyValues;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.BeanCreationException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.annotation.InjectionMetadata;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
+import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.core.Ordered;
+import org.springframework.core.PriorityOrdered;
+import org.springframework.core.env.Environment;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.ReflectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import static com.alibaba.dubbo.config.spring.util.ClassUtils.resolveGenericType;
+import static org.springframework.core.BridgeMethodResolver.findBridgedMethod;
+import static org.springframework.core.BridgeMethodResolver.isVisibilityBridgeMethodPair;
+import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
+import static org.springframework.core.annotation.AnnotationUtils.getAnnotation;
+
+/**
+ * Abstract generic {@link BeanPostProcessor} implementation for customized annotation that annotated injected-object.
+ *
+ * The source code is cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java
+ *
+ * @since 2.6.6
+ */
+public abstract class AnnotationInjectedBeanPostProcessor<A extends Annotation> extends
+ InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered,
+ BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, DisposableBean {
+
+ private final static int CACHE_SIZE = Integer.getInteger("", 32);
+
+ private final Log logger = LogFactory.getLog(getClass());
+
+ private final Class<A> annotationType;
+
+ private final ConcurrentMap<String, AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata> injectionMetadataCache =
+ new ConcurrentHashMap<String, AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata>(CACHE_SIZE);
+
+ private final ConcurrentMap<String, Object> injectedObjectsCache = new ConcurrentHashMap<String, Object>(CACHE_SIZE);
+
+ private ConfigurableListableBeanFactory beanFactory;
+
+ private Environment environment;
+
+ private ClassLoader classLoader;
+
+ private int order = Ordered.LOWEST_PRECEDENCE;
+
+ public AnnotationInjectedBeanPostProcessor() {
+ this.annotationType = resolveGenericType(getClass());
+ }
+
+ private static <T> Collection<T> combine(Collection<? extends T>... elements) {
+ List<T> allElements = new ArrayList<T>();
+ for (Collection<? extends T> e : elements) {
+ allElements.addAll(e);
+ }
+ return allElements;
+ }
+
+ /**
+ * Annotation type
+ *
+ * @return non-null
+ */
+ public final Class<A> getAnnotationType() {
+ return annotationType;
+ }
+
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory,
+ "AnnotationInjectedBeanPostProcessor requires a ConfigurableListableBeanFactory");
+ this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
+ }
+
+ @Override
+ public PropertyValues postProcessPropertyValues(
+ PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
+
+ InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
+ try {
+ metadata.inject(bean, beanName, pvs);
+ } catch (BeanCreationException ex) {
+ throw ex;
+ } catch (Throwable ex) {
+ throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getName()
+ + " dependencies is failed", ex);
+ }
+ return pvs;
+ }
+
+
+ /**
+ * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link A} fields
+ *
+ * @param beanClass The {@link Class} of Bean
+ * @return non-null {@link List}
+ */
+ private List<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> findFieldAnnotationMetadata(final Class<?> beanClass) {
+
+ final List<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> elements = new LinkedList<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement>();
+
+ ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() {
+ @Override
+ public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
+
+ A annotation = getAnnotation(field, getAnnotationType());
+
+ if (annotation != null) {
+
+ if (Modifier.isStatic(field.getModifiers())) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("@" + getAnnotationType().getName() + " is not supported on static fields: " + field);
+ }
+ return;
+ }
+
+ elements.add(new AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement(field, annotation));
+ }
+
+ }
+ });
+
+ return elements;
+
+ }
+
+ /**
+ * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link A @A} methods
+ *
+ * @param beanClass The {@link Class} of Bean
+ * @return non-null {@link List}
+ */
+ private List<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> findAnnotatedMethodMetadata(final Class<?> beanClass) {
+
+ final List<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> elements = new LinkedList<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement>();
+
+ ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
+ @Override
+ public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
+
+ Method bridgedMethod = findBridgedMethod(method);
+
+ if (!isVisibilityBridgeMethodPair(method, bridgedMethod)) {
+ return;
+ }
+
+ A annotation = findAnnotation(bridgedMethod, getAnnotationType());
+
+ if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) {
+ if (Modifier.isStatic(method.getModifiers())) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("@" + getAnnotationType().getSimpleName() + " annotation is not supported on static methods: " + method);
+ }
+ return;
+ }
+ if (method.getParameterTypes().length == 0) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("@" + getAnnotationType().getSimpleName() + " annotation should only be used on methods with parameters: " +
+ method);
+ }
+ }
+ PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass);
+ elements.add(new AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement(method, pd, annotation));
+ }
+ }
+ });
+
+ return elements;
+
+ }
+
+
+ private AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
+ Collection<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
+ Collection<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
+ return new AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
+
+ }
+
+ private InjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
+ // Fall back to class name as cache key, for backwards compatibility with custom callers.
+ String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
+ // Quick check on the concurrent map first, with minimal locking.
+ AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
+ if (InjectionMetadata.needsRefresh(metadata, clazz)) {
+ synchronized (this.injectionMetadataCache) {
+ metadata = this.injectionMetadataCache.get(cacheKey);
+ if (InjectionMetadata.needsRefresh(metadata, clazz)) {
+ if (metadata != null) {
+ metadata.clear(pvs);
+ }
+ try {
+ metadata = buildAnnotatedMetadata(clazz);
+ this.injectionMetadataCache.put(cacheKey, metadata);
+ } catch (NoClassDefFoundError err) {
+ throw new IllegalStateException("Failed to introspect object class [" + clazz.getName() +
+ "] for annotation metadata: could not find class that it depends on", err);
+ }
+ }
+ }
+ }
+ return metadata;
+ }
+
+ @Override
+ public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
+ if (beanType != null) {
+ InjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);
+ metadata.checkConfigMembers(beanDefinition);
+ }
+ }
+
+ @Override
+ public int getOrder() {
+ return order;
+ }
+
+ public void setOrder(int order) {
+ this.order = order;
+ }
+
+ @Override
+ public void destroy() throws Exception {
+
+ for (Object object : injectedObjectsCache.values()) {
+ if (logger.isInfoEnabled()) {
+ logger.info(object + " was destroying!");
+ }
+
+ if (object instanceof DisposableBean) {
+ ((DisposableBean) object).destroy();
+ }
+ }
+
+ injectionMetadataCache.clear();
+ injectedObjectsCache.clear();
+
+ if (logger.isInfoEnabled()) {
+ logger.info(getClass() + " was destroying!");
+ }
+
+ }
+
+ @Override
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ }
+
+ public void setEnvironment(Environment environment) {
+ this.environment = environment;
+ }
+
+ protected Environment getEnvironment() {
+ return environment;
+ }
+
+ protected ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ protected ConfigurableListableBeanFactory getBeanFactory() {
+ return beanFactory;
+ }
+
+ /**
+ * Gets all injected-objects.
+ *
+ * @return non-null {@link Collection}
+ */
+ protected Collection<Object> getInjectedObjects() {
+ return this.injectedObjectsCache.values();
+ }
+
+ /**
+ * Get injected-object from specified {@link A annotation} and Bean Class
+ *
+ * @param annotation {@link A annotation}
+ * @param bean Current bean that will be injected
+ * @param beanName Current bean name that will be injected
+ * @param injectedType the type of injected-object
+ * @param injectedElement {@link InjectionMetadata.InjectedElement}
+ * @return An injected object
+ * @throws Exception If getting is failed
+ */
+ protected Object getInjectedObject(A annotation, Object bean, String beanName, Class<?> injectedType,
+ InjectionMetadata.InjectedElement injectedElement) throws Exception {
+
+ String cacheKey = buildInjectedObjectCacheKey(annotation, bean, beanName, injectedType, injectedElement);
+
+ Object injectedObject = injectedObjectsCache.get(cacheKey);
+
+ if (injectedObject == null) {
+ injectedObject = doGetInjectedBean(annotation, bean, beanName, injectedType, injectedElement);
+ // Customized inject-object if necessary
+ injectedObjectsCache.putIfAbsent(cacheKey, injectedObject);
+ }
+
+ return injectedObject;
+
+ }
+
+ /**
+ * Subclass must implement this method to get injected-object. The context objects could help this method if
+ * necessary :
+ * <ul>
+ * <li>{@link #getBeanFactory() BeanFactory}</li>
+ * <li>{@link #getClassLoader() ClassLoader}</li>
+ * <li>{@link #getEnvironment() Environment}</li>
+ * </ul>
+ *
+ * @param annotation {@link A annotation}
+ * @param bean Current bean that will be injected
+ * @param beanName Current bean name that will be injected
+ * @param injectedType the type of injected-object
+ * @param injectedElement {@link InjectionMetadata.InjectedElement}
+ * @return The injected object
+ * @throws Exception If resolving an injected object is failed.
+ */
+ protected abstract Object doGetInjectedBean(A annotation, Object bean, String beanName, Class<?> injectedType,
+ InjectionMetadata.InjectedElement injectedElement) throws Exception;
+
+ /**
+ * Build a cache key for injected-object. The context objects could help this method if
+ * necessary :
+ * <ul>
+ * <li>{@link #getBeanFactory() BeanFactory}</li>
+ * <li>{@link #getClassLoader() ClassLoader}</li>
+ * <li>{@link #getEnvironment() Environment}</li>
+ * </ul>
+ *
+ * @param annotation {@link A annotation}
+ * @param bean Current bean that will be injected
+ * @param beanName Current bean name that will be injected
+ * @param injectedType the type of injected-object
+ * @param injectedElement {@link InjectionMetadata.InjectedElement}
+ * @return Bean cache key
+ */
+ protected abstract String buildInjectedObjectCacheKey(A annotation, Object bean, String beanName,
+ Class<?> injectedType,
+ InjectionMetadata.InjectedElement injectedElement);
+
+ /**
+ * Get {@link Map} in injected field.
+ *
+ * @return non-null ready-only {@link Map}
+ */
+ protected Map<InjectionMetadata.InjectedElement, Object> getInjectedFieldObjectsMap() {
+
+ Map<InjectionMetadata.InjectedElement, Object> injectedElementBeanMap =
+ new LinkedHashMap<InjectionMetadata.InjectedElement, Object>();
+
+ for (AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata : injectionMetadataCache.values()) {
+
+ Collection<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> fieldElements = metadata.getFieldElements();
+
+ for (AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement fieldElement : fieldElements) {
+
+ injectedElementBeanMap.put(fieldElement, fieldElement.bean);
+
+ }
+
+ }
+
+ return Collections.unmodifiableMap(injectedElementBeanMap);
+
+ }
+
+ /**
+ * Get {@link Map} in injected method.
+ *
+ * @return non-null {@link Map}
+ */
+ protected Map<InjectionMetadata.InjectedElement, Object> getInjectedMethodObjectsMap() {
+
+ Map<InjectionMetadata.InjectedElement, Object> injectedElementBeanMap =
+ new LinkedHashMap<InjectionMetadata.InjectedElement, Object>();
+
+ for (AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata : injectionMetadataCache.values()) {
+
+ Collection<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> methodElements = metadata.getMethodElements();
+
+ for (AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement methodElement : methodElements) {
+
+ injectedElementBeanMap.put(methodElement, methodElement.object);
+
+ }
+
+ }
+
+ return Collections.unmodifiableMap(injectedElementBeanMap);
+
+ }
+
+ /**
+ * {@link A} {@link InjectionMetadata} implementation
+ */
+ private class AnnotatedInjectionMetadata extends InjectionMetadata {
+
+ private final Collection<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> fieldElements;
+
+ private final Collection<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> methodElements;
+
+ public AnnotatedInjectionMetadata(Class<?> targetClass, Collection<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> fieldElements,
+ Collection<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> methodElements) {
+ super(targetClass, combine(fieldElements, methodElements));
+ this.fieldElements = fieldElements;
+ this.methodElements = methodElements;
+ }
+
+ public Collection<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> getFieldElements() {
+ return fieldElements;
+ }
+
+ public Collection<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> getMethodElements() {
+ return methodElements;
+ }
+ }
+
+ /**
+ * {@link A} {@link Method} {@link InjectionMetadata.InjectedElement}
+ */
+ private class AnnotatedMethodElement extends InjectionMetadata.InjectedElement {
+
+ private final Method method;
+
+ private final A annotation;
+
+ private volatile Object object;
+
+ protected AnnotatedMethodElement(Method method, PropertyDescriptor pd, A annotation) {
+ super(method, pd);
+ this.method = method;
+ this.annotation = annotation;
+ }
+
+ @Override
+ protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
+
+ Class<?> injectedType = pd.getPropertyType();
+
+ Object injectedObject = getInjectedObject(annotation, bean, beanName, injectedType, this);
+
+ ReflectionUtils.makeAccessible(method);
+
+ method.invoke(bean, injectedObject);
+
+ }
+
+ }
+
+ /**
+ * {@link A} {@link Field} {@link InjectionMetadata.InjectedElement}
+ */
+ public class AnnotatedFieldElement extends InjectionMetadata.InjectedElement {
+
+ private final Field field;
+
+ private final A annotation;
+
+ private volatile Object bean;
+
+ protected AnnotatedFieldElement(Field field, A annotation) {
+ super(field, null);
+ this.field = field;
+ this.annotation = annotation;
+ }
+
+ @Override
+ protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
+
+ Class<?> injectedType = field.getType();
+
+ Object injectedObject = getInjectedObject(annotation, bean, beanName, injectedType, this);
+
+ ReflectionUtils.makeAccessible(field);
+
+ field.set(bean, injectedObject);
+
+ }
+
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapter.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapter.java
index 29a8acc..aab1883 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapter.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapter.java
@@ -23,7 +23,7 @@ import org.springframework.core.env.PropertyResolver;
import java.lang.annotation.Annotation;
-import static com.alibaba.spring.util.AnnotationUtils.getAttributes;
+import static com.alibaba.dubbo.config.spring.util.AnnotationUtils.getAttributes;
/**
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java
index 46ace14..f87be24 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java
@@ -20,9 +20,9 @@ import com.alibaba.dubbo.common.utils.Assert;
import com.alibaba.dubbo.config.AbstractConfig;
import com.alibaba.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubboConfigBinding;
+import com.alibaba.dubbo.config.spring.context.config.DubboConfigBeanCustomizer;
import com.alibaba.dubbo.config.spring.context.properties.DefaultDubboConfigBinder;
import com.alibaba.dubbo.config.spring.context.properties.DubboConfigBinder;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
@@ -30,8 +30,16 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.env.Environment;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors;
+
/**
* Dubbo Config Binding {@link BeanPostProcessor}
*
@@ -62,6 +70,8 @@ public class DubboConfigBindingBeanPostProcessor implements BeanPostProcessor, A
private boolean ignoreInvalidFields = true;
+ private List<DubboConfigBeanCustomizer> configBeanCustomizers = Collections.emptyList();
+
/**
* @param prefix the prefix of Configuration Properties
* @param beanName the binding Bean Name
@@ -80,18 +90,34 @@ public class DubboConfigBindingBeanPostProcessor implements BeanPostProcessor, A
AbstractConfig dubboConfig = (AbstractConfig) bean;
- dubboConfigBinder.bind(prefix, dubboConfig);
+ bind(prefix, dubboConfig);
+
+ customize(beanName, dubboConfig);
- if (log.isInfoEnabled()) {
- log.info("The properties of bean [name : " + beanName + "] have been binding by prefix of " +
- "configuration properties : " + prefix);
- }
}
return bean;
}
+ private void bind(String prefix, AbstractConfig dubboConfig) {
+
+ dubboConfigBinder.bind(prefix, dubboConfig);
+
+ if (log.isInfoEnabled()) {
+ log.info("The properties of bean [name : " + beanName + "] have been binding by prefix of " +
+ "configuration properties : " + prefix);
+ }
+ }
+
+ private void customize(String beanName, AbstractConfig dubboConfig) {
+
+ for (DubboConfigBeanCustomizer customizer : configBeanCustomizers) {
+ customizer.customize(beanName, dubboConfig);
+ }
+
+ }
+
public boolean isIgnoreUnknownFields() {
return ignoreUnknownFields;
}
@@ -129,6 +155,14 @@ public class DubboConfigBindingBeanPostProcessor implements BeanPostProcessor, A
@Override
public void afterPropertiesSet() throws Exception {
+ initDubboConfigBinder();
+
+ initConfigBeanCustomizers();
+
+ }
+
+ private void initDubboConfigBinder() {
+
if (dubboConfigBinder == null) {
try {
dubboConfigBinder = applicationContext.getBean(DubboConfigBinder.class);
@@ -146,6 +180,16 @@ public class DubboConfigBindingBeanPostProcessor implements BeanPostProcessor, A
}
+ private void initConfigBeanCustomizers() {
+
+ Collection<DubboConfigBeanCustomizer> configBeanCustomizers =
+ beansOfTypeIncludingAncestors(applicationContext, DubboConfigBeanCustomizer.class).values();
+
+ this.configBeanCustomizers = new ArrayList<DubboConfigBeanCustomizer>(configBeanCustomizers);
+
+ AnnotationAwareOrderComparator.sort(this.configBeanCustomizers);
+ }
+
/**
* Create {@link DubboConfigBinder} instance.
*
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
index 517c625..e8be4c0 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
@@ -20,8 +20,7 @@ import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.spring.ReferenceBean;
import com.alibaba.dubbo.config.spring.ServiceBean;
import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
-import com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor;
-import com.alibaba.spring.util.AnnotationUtils;
+import com.alibaba.dubbo.config.spring.util.AnnotationUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.InjectionMetadata;
@@ -33,6 +32,7 @@ import org.springframework.context.event.ContextRefreshedEvent;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
@@ -156,7 +156,18 @@ public class ReferenceAnnotationBeanPostProcessor extends AnnotationInjectedBean
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- return method.invoke(bean, args);
+ Object result = null;
+ try {
+ if (bean == null) { // If the bean is not initialized, invoke init()
+ // issue: https://github.com/apache/incubator-dubbo/issues/3429
+ init();
+ }
+ result = method.invoke(bean, args);
+ } catch (InvocationTargetException e) {
+ // re-throws the actual Exception.
+ throw e.getTargetException();
+ }
+ return result;
}
private void init() {
@@ -170,14 +181,16 @@ public class ReferenceAnnotationBeanPostProcessor extends AnnotationInjectedBean
String key = buildReferencedBeanName(reference, injectedType) +
"#source=" + (injectedElement.getMember()) +
- "#attributes=" + AnnotationUtils.getAttributes(reference,getEnvironment(),true);
+ "#attributes=" + AnnotationUtils.getAttributes(reference, getEnvironment(), true);
return key;
}
private String buildReferencedBeanName(Reference reference, Class<?> injectedType) {
- ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, injectedType, getEnvironment());
+ AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(reference, injectedType);
+
+ builder.environment(getEnvironment());
return getEnvironment().resolvePlaceholders(builder.build());
}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java
index 7b5288d..9b92d21 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java
@@ -31,8 +31,8 @@ import org.springframework.validation.DataBinder;
import java.beans.PropertyEditorSupport;
import java.util.Map;
-import static com.alibaba.spring.util.BeanFactoryUtils.getOptionalBean;
-import static com.alibaba.spring.util.ObjectUtils.of;
+import static com.alibaba.dubbo.config.spring.util.BeanFactoryUtils.getOptionalBean;
+import static com.alibaba.dubbo.config.spring.util.ObjectUtils.of;
import static org.springframework.util.StringUtils.commaDelimitedListToStringArray;
/**
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java
index d34b4a6..0c2fc64 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java
@@ -57,7 +57,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
-import static com.alibaba.spring.util.ObjectUtils.of;
+import static com.alibaba.dubbo.config.spring.util.ObjectUtils.of;
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;
import static org.springframework.context.annotation.AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR;
import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
@@ -262,7 +262,7 @@ public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistr
registry.registerBeanDefinition(beanName, serviceBeanDefinition);
if (logger.isInfoEnabled()) {
- logger.warn("The BeanDefinition[" + serviceBeanDefinition +
+ logger.info("The BeanDefinition[" + serviceBeanDefinition +
"] of ServiceBean has been registered with name : " + beanName);
}
@@ -289,11 +289,11 @@ public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistr
*/
private String generateServiceBeanName(Service service, Class<?> interfaceClass, String annotatedServiceBeanName) {
- ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, interfaceClass, environment);
+ AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(service, interfaceClass);
+ builder.environment(environment);
return builder.build();
-
}
private Class<?> resolveServiceInterfaceClass(Class<?> annotatedServiceBeanClass, Service service) {
@@ -315,8 +315,9 @@ public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistr
}
if (interfaceClass == null) {
-
- Class<?>[] allInterfaces = annotatedServiceBeanClass.getInterfaces();
+ // Find all interfaces from the annotated class
+ // To resolve an issue : https://github.com/apache/incubator-dubbo/issues/3251
+ Class<?>[] allInterfaces = ClassUtils.getAllInterfacesForClass(annotatedServiceBeanClass);
if (allInterfaces.length > 0) {
interfaceClass = allInterfaces[0];
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java
index 06b2dfa..4a97a24 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java
@@ -35,7 +35,9 @@ import static com.alibaba.dubbo.config.spring.util.AnnotationUtils.resolveInterf
* @see ServiceBean
* @see ReferenceBean
* @since 2.6.5
+ * @deprecated {@link AnnotationBeanNameBuilder} as the replacement
*/
+@Deprecated
class ServiceBeanNameBuilder {
private static final String SEPARATOR = ":";
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java
index 8e8cf20..2f55f29 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java
@@ -18,7 +18,7 @@ package com.alibaba.dubbo.config.spring.context.annotation;
import com.alibaba.dubbo.config.AbstractConfig;
import com.alibaba.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor;
-
+import com.alibaba.dubbo.config.spring.context.config.NamePropertyDefaultValueDubboConfigBeanCustomizer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -41,8 +41,9 @@ import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
-import static com.alibaba.spring.util.PropertySourcesUtils.getSubProperties;
-import static com.alibaba.spring.util.PropertySourcesUtils.normalizePrefix;
+import static com.alibaba.dubbo.config.spring.util.BeanRegistrar.registerInfrastructureBean;
+import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties;
+import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.normalizePrefix;
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;
import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerWithGeneratedName;
@@ -107,6 +108,8 @@ public class DubboConfigBindingRegistrar implements ImportBeanDefinitionRegistra
}
+ registerDubboConfigBeanCustomizers(registry);
+
}
private void registerDubboConfigBean(String beanName, Class<? extends AbstractConfig> configClass,
@@ -149,6 +152,11 @@ public class DubboConfigBindingRegistrar implements ImportBeanDefinitionRegistra
}
+ private void registerDubboConfigBeanCustomizers(BeanDefinitionRegistry registry) {
+ registerInfrastructureBean(registry, "namePropertyDefaultValueDubboConfigBeanCustomizer",
+ NamePropertyDefaultValueDubboConfigBeanCustomizer.class);
+ }
+
@Override
public void setEnvironment(Environment environment) {
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java
similarity index 63%
rename from dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java
rename to dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java
index 24f581b..ff20d8d 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java
@@ -18,43 +18,38 @@ package com.alibaba.dubbo.config.spring.context.annotation;
import com.alibaba.dubbo.config.AbstractConfig;
-import org.springframework.context.annotation.ImportSelector;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
+import static com.alibaba.dubbo.config.spring.util.AnnotatedBeanDefinitionRegistryUtils.registerBeans;
+
+
/**
- * Dubbo {@link AbstractConfig Config} Registrar
+ * Dubbo {@link AbstractConfig Config} {@link ImportBeanDefinitionRegistrar register}
*
* @see EnableDubboConfig
* @see DubboConfigConfiguration
+ * @see Ordered
* @since 2.5.8
*/
-public class DubboConfigConfigurationSelector implements ImportSelector, Ordered {
+public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
@Override
- public String[] selectImports(AnnotationMetadata importingClassMetadata) {
+ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
boolean multiple = attributes.getBoolean("multiple");
- if (multiple) {
- return of(DubboConfigConfiguration.Multiple.class.getName());
- } else {
- return of(DubboConfigConfiguration.Single.class.getName());
- }
- }
-
- private static <T> T[] of(T... values) {
- return values;
- }
+ // Single Config Bindings
+ registerBeans(registry, DubboConfigConfiguration.Single.class);
- @Override
- public int getOrder() {
- return HIGHEST_PRECEDENCE;
+ if (multiple) { // Since 2.6.6 https://github.com/apache/incubator-dubbo/issues/3193
+ registerBeans(registry, DubboConfigConfiguration.Multiple.class);
+ }
}
-
-
-}
+}
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubbo.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubbo.java
index 25d8cad..fff2fc4 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubbo.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubbo.java
@@ -76,6 +76,6 @@ public @interface EnableDubbo {
* @see EnableDubboConfig#multiple()
*/
@AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
- boolean multipleConfig() default false;
+ boolean multipleConfig() default true;
}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfig.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfig.java
index fe20770..ad394f7 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfig.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfig.java
@@ -46,7 +46,7 @@ import java.lang.annotation.Target;
* <li>{@link ConsumerConfig} binding to property : "dubbo.consumer"</li>
* </ul>
* <p>
- * In contrast, on multiple bean bindings that requires to set {@link #multiple()} to be <code>true</code> :
+ * On multiple bean bindings that requires to set {@link #multiple()} to be <code>true</code> :
* <ul>
* <li>{@link ApplicationConfig} binding to property : "dubbo.applications"</li>
* <li>{@link ModuleConfig} binding to property : "dubbo.modules"</li>
@@ -59,22 +59,25 @@ import java.lang.annotation.Target;
*
* @see EnableDubboConfigBinding
* @see DubboConfigConfiguration
- * @see DubboConfigConfigurationSelector
+ * @see DubboConfigConfigurationRegistrar
* @since 2.5.8
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
-@Import(DubboConfigConfigurationSelector.class)
+@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {
/**
* It indicates whether binding to multiple Spring Beans.
+ * <p>
+ * Please note that if {@link #multiple()} is <code>true</code> since 2.6.6, the multiple bean bindings will be
+ * enabled, works with single bean bindings, rather than they are mutually exclusive before.
*
- * @return the default value is <code>false</code>
+ * @return the default value is <code>true</code> since 2.6.6, the value is inverse earlier.
* @revised 2.5.9
*/
- boolean multiple() default false;
+ boolean multiple() default true;
}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java
new file mode 100644
index 0000000..42e1f6a
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.spring.context.config;
+
+import com.alibaba.dubbo.config.AbstractConfig;
+import com.alibaba.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor;
+import com.alibaba.dubbo.config.spring.context.properties.DubboConfigBinder;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.Ordered;
+
+/**
+ * The Bean customizer for {@link AbstractConfig Dubbo Config}. Generally, The subclass will be registered as a Spring
+ * Bean that is used to {@link #customize(String, AbstractConfig) customize} {@link AbstractConfig Dubbo Config} bean
+ * after {@link DubboConfigBinder#bind(String, AbstractConfig) its binding}.
+ * <p>
+ * If There are multiple {@link DubboConfigBeanCustomizer} beans in the Spring {@link ApplicationContext context}, they
+ * are executed orderly, thus the subclass should be aware to implement the {@link #getOrder()} method.
+ *
+ * @see DubboConfigBinder#bind(String, AbstractConfig)
+ * @see DubboConfigBindingBeanPostProcessor
+ * @since 2.6.6
+ */
+public interface DubboConfigBeanCustomizer extends Ordered {
+
+ /**
+ * Customize {@link AbstractConfig Dubbo Config Bean}
+ *
+ * @param beanName the name of {@link AbstractConfig Dubbo Config Bean}
+ * @param dubboConfigBean the instance of {@link AbstractConfig Dubbo Config Bean}
+ */
+ void customize(String beanName, AbstractConfig dubboConfigBean);
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.java
new file mode 100644
index 0000000..d938218
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.spring.context.config;
+
+import com.alibaba.dubbo.config.AbstractConfig;
+import org.springframework.util.ReflectionUtils;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import static com.alibaba.dubbo.config.spring.util.ObjectUtils.of;
+import static org.springframework.beans.BeanUtils.getPropertyDescriptor;
+
+/**
+ * {@link DubboConfigBeanCustomizer} for the default value for the "name" property that will be taken bean name
+ * if absent.
+ *
+ * @since 2.6.6
+ */
+public class NamePropertyDefaultValueDubboConfigBeanCustomizer implements DubboConfigBeanCustomizer {
+
+ /**
+ * The name of property that is "name" maybe is absent in target class
+ */
+ private static final String PROPERTY_NAME = "name";
+
+ @Override
+ public void customize(String beanName, AbstractConfig dubboConfigBean) {
+
+ PropertyDescriptor propertyDescriptor = getPropertyDescriptor(dubboConfigBean.getClass(), PROPERTY_NAME);
+
+ if (propertyDescriptor != null) { // "name" property is present
+
+ Method getNameMethod = propertyDescriptor.getReadMethod();
+
+ if (getNameMethod == null) { // if "getName" method is absent
+ return;
+ }
+
+ Object propertyValue = ReflectionUtils.invokeMethod(getNameMethod, dubboConfigBean);
+
+ if (propertyValue != null) { // If The return value of "getName" method is not null
+ return;
+ }
+
+ Method setNameMethod = propertyDescriptor.getWriteMethod();
+ if (setNameMethod != null && getNameMethod != null) { // "setName" and "getName" methods are present
+ if (Arrays.equals(of(String.class), setNameMethod.getParameterTypes())) { // the param type is String
+ // set bean name to the value of the "name" property
+ ReflectionUtils.invokeMethod(setNameMethod, dubboConfigBean, beanName);
+ }
+ }
+ }
+ }
+
+ @Override
+ public int getOrder() {
+ return HIGHEST_PRECEDENCE;
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java
index 045a5ac..cda2a6e 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java
@@ -23,7 +23,7 @@ import org.springframework.validation.DataBinder;
import java.util.Map;
-import static com.alibaba.spring.util.PropertySourcesUtils.getSubProperties;
+import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties;
/**
* Default {@link DubboConfigBinder} implementation based on Spring {@link DataBinder}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/extension/SpringExtensionFactory.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/extension/SpringExtensionFactory.java
index 5cbc06e..c6a07de 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/extension/SpringExtensionFactory.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/extension/SpringExtensionFactory.java
@@ -1,111 +1,111 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.alibaba.dubbo.config.spring.extension;
-
-import com.alibaba.dubbo.common.extension.ExtensionFactory;
-import com.alibaba.dubbo.common.logger.Logger;
-import com.alibaba.dubbo.common.logger.LoggerFactory;
-import com.alibaba.dubbo.common.utils.ConcurrentHashSet;
-
-import com.alibaba.dubbo.config.DubboShutdownHook;
-import com.alibaba.dubbo.config.spring.util.BeanFactoryUtils;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationEvent;
-import org.springframework.context.ApplicationListener;
-import org.springframework.context.event.ContextClosedEvent;
-
-import java.util.Set;
-
-/**
- * SpringExtensionFactory
- */
-public class SpringExtensionFactory implements ExtensionFactory {
- private static final Logger logger = LoggerFactory.getLogger(SpringExtensionFactory.class);
-
- private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();
-
- private static final ApplicationListener shutdownHookListener = new ShutdownHookListener();
-
- public static void addApplicationContext(ApplicationContext context) {
- contexts.add(context);
- BeanFactoryUtils.addApplicationListener(context, shutdownHookListener);
- }
-
- public static void removeApplicationContext(ApplicationContext context) {
- contexts.remove(context);
- }
-
- public static Set<ApplicationContext> getContexts() {
- return contexts;
- }
-
- // currently for test purpose
- public static void clearContexts() {
- contexts.clear();
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public <T> T getExtension(Class<T> type, String name) {
- for (ApplicationContext context : contexts) {
- if (context.containsBean(name)) {
- Object bean = context.getBean(name);
- if (type.isInstance(bean)) {
- return (T) bean;
- }
- }
- }
-
- logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName());
-
- if (Object.class == type) {
- return null;
- }
-
- for (ApplicationContext context : contexts) {
- try {
- return context.getBean(type);
- } catch (NoUniqueBeanDefinitionException multiBeanExe) {
- logger.warn("Find more than 1 spring extensions (beans) of type " + type.getName() + ", will stop auto injection. Please make sure you have specified the concrete parameter type and there's only one extension of that type.");
- } catch (NoSuchBeanDefinitionException noBeanExe) {
- if (logger.isDebugEnabled()) {
- logger.debug("Error when get spring extension(bean) for type:" + type.getName(), noBeanExe);
- }
- }
- }
-
- logger.warn("No spring extension (bean) named:" + name + ", type:" + type.getName() + " found, stop get bean.");
-
- return null;
- }
-
- private static class ShutdownHookListener implements ApplicationListener {
- @Override
- public void onApplicationEvent(ApplicationEvent event) {
- if (event instanceof ContextClosedEvent) {
- // we call it anyway since dubbo shutdown hook make sure its destroyAll() is re-entrant.
- // pls. note we should not remove dubbo shutdown hook when spring framework is present, this is because
- // its shutdown hook may not be installed.
- DubboShutdownHook shutdownHook = DubboShutdownHook.getDubboShutdownHook();
- shutdownHook.destroyAll();
- }
- }
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.spring.extension;
+
+import com.alibaba.dubbo.common.extension.ExtensionFactory;
+import com.alibaba.dubbo.common.logger.Logger;
+import com.alibaba.dubbo.common.logger.LoggerFactory;
+import com.alibaba.dubbo.common.utils.ConcurrentHashSet;
+import com.alibaba.dubbo.config.DubboShutdownHook;
+import com.alibaba.dubbo.config.spring.util.BeanFactoryUtils;
+
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextClosedEvent;
+
+import java.util.Set;
+
+/**
+ * SpringExtensionFactory
+ */
+public class SpringExtensionFactory implements ExtensionFactory {
+ private static final Logger logger = LoggerFactory.getLogger(SpringExtensionFactory.class);
+
+ private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();
+
+ private static final ApplicationListener shutdownHookListener = new ShutdownHookListener();
+
+ public static void addApplicationContext(ApplicationContext context) {
+ contexts.add(context);
+ BeanFactoryUtils.addApplicationListener(context, shutdownHookListener);
+ }
+
+ public static void removeApplicationContext(ApplicationContext context) {
+ contexts.remove(context);
+ }
+
+ public static Set<ApplicationContext> getContexts() {
+ return contexts;
+ }
+
+ // currently for test purpose
+ public static void clearContexts() {
+ contexts.clear();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getExtension(Class<T> type, String name) {
+ for (ApplicationContext context : contexts) {
+ if (context.containsBean(name)) {
+ Object bean = context.getBean(name);
+ if (type.isInstance(bean)) {
+ return (T) bean;
+ }
+ }
+ }
+
+ logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName());
+
+ if (Object.class == type) {
+ return null;
+ }
+
+ for (ApplicationContext context : contexts) {
+ try {
+ return context.getBean(type);
+ } catch (NoUniqueBeanDefinitionException multiBeanExe) {
+ logger.warn("Find more than 1 spring extensions (beans) of type " + type.getName() + ", will stop auto injection. Please make sure you have specified the concrete parameter type and there's only one extension of that type.");
+ } catch (NoSuchBeanDefinitionException noBeanExe) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Error when get spring extension(bean) for type:" + type.getName(), noBeanExe);
+ }
+ }
+ }
+
+ logger.warn("No spring extension (bean) named:" + name + ", type:" + type.getName() + " found, stop get bean.");
+
+ return null;
+ }
+
+ private static class ShutdownHookListener implements ApplicationListener {
+ @Override
+ public void onApplicationEvent(ApplicationEvent event) {
+ if (event instanceof ContextClosedEvent) {
+ // we call it anyway since dubbo shutdown hook make sure its destroyAll() is re-entrant.
+ // pls. note we should not remove dubbo shutdown hook when spring framework is present, this is because
+ // its shutdown hook may not be installed.
+ DubboShutdownHook shutdownHook = DubboShutdownHook.getDubboShutdownHook();
+ shutdownHook.destroyAll();
+ }
+ }
+ }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusChecker.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusChecker.java
index 32baa41..8863d8b 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusChecker.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusChecker.java
@@ -1,96 +1,96 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.alibaba.dubbo.config.spring.status;
-
-import com.alibaba.dubbo.common.extension.Activate;
-import com.alibaba.dubbo.common.logger.Logger;
-import com.alibaba.dubbo.common.logger.LoggerFactory;
-import com.alibaba.dubbo.common.status.Status;
-import com.alibaba.dubbo.common.status.StatusChecker;
-
-import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;
-import org.springframework.context.ApplicationContext;
-
-import javax.sql.DataSource;
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
-import java.util.Map;
-
-/**
- * DataSourceStatusChecker
- */
-@Activate
-public class DataSourceStatusChecker implements StatusChecker {
-
- private static final Logger logger = LoggerFactory.getLogger(DataSourceStatusChecker.class);
-
- @Override
- @SuppressWarnings("unchecked")
- public Status check() {
- ApplicationContext context = null;
- for (ApplicationContext c : SpringExtensionFactory.getContexts()) {
- if (c != null) {
- context = c;
- break;
- }
- }
- if (context == null) {
- return new Status(Status.Level.UNKNOWN);
- }
- Map<String, DataSource> dataSources = context.getBeansOfType(DataSource.class, false, false);
- if (dataSources == null || dataSources.size() == 0) {
- return new Status(Status.Level.UNKNOWN);
- }
- Status.Level level = Status.Level.OK;
- StringBuilder buf = new StringBuilder();
- for (Map.Entry<String, DataSource> entry : dataSources.entrySet()) {
- DataSource dataSource = entry.getValue();
- if (buf.length() > 0) {
- buf.append(", ");
- }
- buf.append(entry.getKey());
- try {
- Connection connection = dataSource.getConnection();
- try {
- DatabaseMetaData metaData = connection.getMetaData();
- ResultSet resultSet = metaData.getTypeInfo();
- try {
- if (!resultSet.next()) {
- level = Status.Level.ERROR;
- }
- } finally {
- resultSet.close();
- }
- buf.append(metaData.getURL());
- buf.append("(");
- buf.append(metaData.getDatabaseProductName());
- buf.append("-");
- buf.append(metaData.getDatabaseProductVersion());
- buf.append(")");
- } finally {
- connection.close();
- }
- } catch (Throwable e) {
- logger.warn(e.getMessage(), e);
- return new Status(level, e.getMessage());
- }
- }
- return new Status(level, buf.toString());
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.spring.status;
+
+import com.alibaba.dubbo.common.extension.Activate;
+import com.alibaba.dubbo.common.logger.Logger;
+import com.alibaba.dubbo.common.logger.LoggerFactory;
+import com.alibaba.dubbo.common.status.Status;
+import com.alibaba.dubbo.common.status.StatusChecker;
+import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;
+
+import org.springframework.context.ApplicationContext;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.util.Map;
+
+/**
+ * DataSourceStatusChecker
+ */
+@Activate
+public class DataSourceStatusChecker implements StatusChecker {
+
+ private static final Logger logger = LoggerFactory.getLogger(DataSourceStatusChecker.class);
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Status check() {
+ ApplicationContext context = null;
+ for (ApplicationContext c : SpringExtensionFactory.getContexts()) {
+ if (c != null) {
+ context = c;
+ break;
+ }
+ }
+ if (context == null) {
+ return new Status(Status.Level.UNKNOWN);
+ }
+ Map<String, DataSource> dataSources = context.getBeansOfType(DataSource.class, false, false);
+ if (dataSources == null || dataSources.size() == 0) {
+ return new Status(Status.Level.UNKNOWN);
+ }
+ Status.Level level = Status.Level.OK;
+ StringBuilder buf = new StringBuilder();
+ for (Map.Entry<String, DataSource> entry : dataSources.entrySet()) {
+ DataSource dataSource = entry.getValue();
+ if (buf.length() > 0) {
+ buf.append(", ");
+ }
+ buf.append(entry.getKey());
+ try {
+ Connection connection = dataSource.getConnection();
+ try {
+ DatabaseMetaData metaData = connection.getMetaData();
+ ResultSet resultSet = metaData.getTypeInfo();
+ try {
+ if (!resultSet.next()) {
+ level = Status.Level.ERROR;
+ }
+ } finally {
+ resultSet.close();
+ }
+ buf.append(metaData.getURL());
+ buf.append("(");
+ buf.append(metaData.getDatabaseProductName());
+ buf.append("-");
+ buf.append(metaData.getDatabaseProductVersion());
+ buf.append(")");
+ } finally {
+ connection.close();
+ }
+ } catch (Throwable e) {
+ logger.warn(e.getMessage(), e);
+ return new Status(level, e.getMessage());
+ }
+ }
+ return new Status(level, buf.toString());
+ }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/SpringStatusChecker.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/SpringStatusChecker.java
index f80b5e6..282f364 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/SpringStatusChecker.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/SpringStatusChecker.java
@@ -1,92 +1,92 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.alibaba.dubbo.config.spring.status;
-
-import com.alibaba.dubbo.common.extension.Activate;
-import com.alibaba.dubbo.common.logger.Logger;
-import com.alibaba.dubbo.common.logger.LoggerFactory;
-import com.alibaba.dubbo.common.status.Status;
-import com.alibaba.dubbo.common.status.StatusChecker;
-
-import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.Lifecycle;
-
-import java.lang.reflect.Method;
-
-/**
- * SpringStatusChecker
- */
-@Activate
-public class SpringStatusChecker implements StatusChecker {
-
- private static final Logger logger = LoggerFactory.getLogger(SpringStatusChecker.class);
-
- @Override
- public Status check() {
- ApplicationContext context = null;
- for (ApplicationContext c : SpringExtensionFactory.getContexts()) {
- if (c != null) {
- context = c;
- break;
- }
- }
- if (context == null) {
- return new Status(Status.Level.UNKNOWN);
- }
- Status.Level level = Status.Level.OK;
- if (context instanceof Lifecycle) {
- if (((Lifecycle) context).isRunning()) {
- level = Status.Level.OK;
- } else {
- level = Status.Level.ERROR;
- }
- } else {
- level = Status.Level.UNKNOWN;
- }
- StringBuilder buf = new StringBuilder();
- try {
- Class<?> cls = context.getClass();
- Method method = null;
- while (cls != null && method == null) {
- try {
- method = cls.getDeclaredMethod("getConfigLocations", new Class<?>[0]);
- } catch (NoSuchMethodException t) {
- cls = cls.getSuperclass();
- }
- }
- if (method != null) {
- if (!method.isAccessible()) {
- method.setAccessible(true);
- }
- String[] configs = (String[]) method.invoke(context, new Object[0]);
- if (configs != null && configs.length > 0) {
- for (String config : configs) {
- if (buf.length() > 0) {
- buf.append(",");
- }
- buf.append(config);
- }
- }
- }
- } catch (Throwable t) {
- logger.warn(t.getMessage(), t);
- }
- return new Status(level, buf.toString());
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.spring.status;
+
+import com.alibaba.dubbo.common.extension.Activate;
+import com.alibaba.dubbo.common.logger.Logger;
+import com.alibaba.dubbo.common.logger.LoggerFactory;
+import com.alibaba.dubbo.common.status.Status;
+import com.alibaba.dubbo.common.status.StatusChecker;
+import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.Lifecycle;
+
+import java.lang.reflect.Method;
+
+/**
+ * SpringStatusChecker
+ */
+@Activate
+public class SpringStatusChecker implements StatusChecker {
+
+ private static final Logger logger = LoggerFactory.getLogger(SpringStatusChecker.class);
+
+ @Override
+ public Status check() {
+ ApplicationContext context = null;
+ for (ApplicationContext c : SpringExtensionFactory.getContexts()) {
+ if (c != null) {
+ context = c;
+ break;
+ }
+ }
+ if (context == null) {
+ return new Status(Status.Level.UNKNOWN);
+ }
+ Status.Level level = Status.Level.OK;
+ if (context instanceof Lifecycle) {
+ if (((Lifecycle) context).isRunning()) {
+ level = Status.Level.OK;
+ } else {
+ level = Status.Level.ERROR;
+ }
+ } else {
+ level = Status.Level.UNKNOWN;
+ }
+ StringBuilder buf = new StringBuilder();
+ try {
+ Class<?> cls = context.getClass();
+ Method method = null;
+ while (cls != null && method == null) {
+ try {
+ method = cls.getDeclaredMethod("getConfigLocations", new Class<?>[0]);
+ } catch (NoSuchMethodException t) {
+ cls = cls.getSuperclass();
+ }
+ }
+ if (method != null) {
+ if (!method.isAccessible()) {
+ method.setAccessible(true);
+ }
+ String[] configs = (String[]) method.invoke(context, new Object[0]);
+ if (configs != null && configs.length > 0) {
+ for (String config : configs) {
+ if (buf.length() > 0) {
+ buf.append(",");
+ }
+ buf.append(config);
+ }
+ }
+ }
+ } catch (Throwable t) {
+ logger.warn(t.getMessage(), t);
+ }
+ return new Status(level, buf.toString());
+ }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtils.java
new file mode 100644
index 0000000..ccc3427
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtils.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.spring.util;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
+import org.springframework.util.ObjectUtils;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+
+/**
+ * Annotated {@link BeanDefinition} Utilities
+ * <p>
+ * The source code is cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/AnnotatedBeanDefinitionRegistryUtils.java
+ * @since 2.6.6
+ */
+public abstract class AnnotatedBeanDefinitionRegistryUtils {
+
+ private static final Log logger = LogFactory.getLog(AnnotatedBeanDefinitionRegistryUtils.class);
+
+ /**
+ * Register Beans
+ *
+ * @param registry {@link BeanDefinitionRegistry}
+ * @param annotatedClasses {@link Annotation annotation} class
+ */
+ public static void registerBeans(BeanDefinitionRegistry registry, Class<?>... annotatedClasses) {
+
+ if (ObjectUtils.isEmpty(annotatedClasses)) {
+ return;
+ }
+
+ boolean debugEnabled = logger.isDebugEnabled();
+
+ AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);
+
+ if (debugEnabled) {
+ logger.debug(registry.getClass().getSimpleName() + " will register annotated classes : " + Arrays.asList(annotatedClasses) + " .");
+ }
+
+ reader.register(annotatedClasses);
+
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotationUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotationUtils.java
index 7e5bb49..703e649 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotationUtils.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotationUtils.java
@@ -19,15 +19,39 @@ package com.alibaba.dubbo.config.spring.util;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
+import org.springframework.core.env.Environment;
+import org.springframework.core.env.PropertyResolver;
import org.springframework.util.StringUtils;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static java.lang.String.valueOf;
+import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
+import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes;
+import static org.springframework.core.annotation.AnnotationUtils.getDefaultValue;
+import static org.springframework.util.CollectionUtils.arrayToList;
+import static org.springframework.util.ObjectUtils.nullSafeEquals;
+import static org.springframework.util.StringUtils.trimWhitespace;
+
/**
* Annotation Utilities Class
*
* @see org.springframework.core.annotation.AnnotationUtils
* @since 2.5.11
*/
-public class AnnotationUtils {
+public abstract class AnnotationUtils {
public static String resolveInterfaceName(Service service, Class<?> defaultInterfaceClass)
throws IllegalStateException {
@@ -69,4 +93,192 @@ public class AnnotationUtils {
}
+
+ // Cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/AnnotationUtils.java
+
+ /**
+ * Is specified {@link Annotation} present on {@link Method}'s declaring class or parameters or itself.
+ *
+ * @param method {@link Method}
+ * @param annotationClass {@link Annotation} type
+ * @param <A> {@link Annotation} type
+ * @return If present , return <code>true</code> , or <code>false</code>
+ * @since 2.6.6
+ */
+ public static <A extends Annotation> boolean isPresent(Method method, Class<A> annotationClass) {
+
+ Map<ElementType, List<A>> annotationsMap = findAnnotations(method, annotationClass);
+
+ return !annotationsMap.isEmpty();
+
+ }
+
+ /**
+ * Find specified {@link Annotation} type maps from {@link Method}
+ *
+ * @param method {@link Method}
+ * @param annotationClass {@link Annotation} type
+ * @param <A> {@link Annotation} type
+ * @return {@link Annotation} type maps , the {@link ElementType} as key ,
+ * the list of {@link Annotation} as value.
+ * If {@link Annotation} was annotated on {@link Method}'s parameters{@link ElementType#PARAMETER} ,
+ * the associated {@link Annotation} list may contain multiple elements.
+ * @since 2.6.6
+ */
+ public static <A extends Annotation> Map<ElementType, List<A>> findAnnotations(Method method,
+ Class<A> annotationClass) {
+
+ Retention retention = annotationClass.getAnnotation(Retention.class);
+
+ RetentionPolicy retentionPolicy = retention.value();
+
+ if (!RetentionPolicy.RUNTIME.equals(retentionPolicy)) {
+ return Collections.emptyMap();
+ }
+
+ Map<ElementType, List<A>> annotationsMap = new LinkedHashMap<ElementType, List<A>>();
+
+ Target target = annotationClass.getAnnotation(Target.class);
+
+ ElementType[] elementTypes = target.value();
+
+
+ for (ElementType elementType : elementTypes) {
+
+ List<A> annotationsList = new LinkedList<A>();
+
+ switch (elementType) {
+
+ case PARAMETER:
+
+ Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+
+ for (Annotation[] annotations : parameterAnnotations) {
+
+ for (Annotation annotation : annotations) {
+
+ if (annotationClass.equals(annotation.annotationType())) {
+
+ annotationsList.add((A) annotation);
+
+ }
+
+ }
+
+ }
+
+ break;
+
+ case METHOD:
+
+ A annotation = findAnnotation(method, annotationClass);
+
+ if (annotation != null) {
+
+ annotationsList.add(annotation);
+
+ }
+
+ break;
+
+ case TYPE:
+
+ Class<?> beanType = method.getDeclaringClass();
+
+ A annotation2 = findAnnotation(beanType, annotationClass);
+
+ if (annotation2 != null) {
+
+ annotationsList.add(annotation2);
+
+ }
+
+ break;
+
+ }
+
+ if (!annotationsList.isEmpty()) {
+
+ annotationsMap.put(elementType, annotationsList);
+
+ }
+
+
+ }
+
+ return Collections.unmodifiableMap(annotationsMap);
+
+ }
+
+ /**
+ * Get the {@link Annotation} attributes
+ *
+ * @param annotation specified {@link Annotation}
+ * @param ignoreDefaultValue whether ignore default value or not
+ * @param ignoreAttributeNames the attribute names of annotation should be ignored
+ * @return non-null
+ * @since 2.6.6
+ */
+ public static Map<String, Object> getAttributes(Annotation annotation, boolean ignoreDefaultValue,
+ String... ignoreAttributeNames) {
+ return getAttributes(annotation, null, ignoreDefaultValue, ignoreAttributeNames);
+ }
+
+ /**
+ * Get the {@link Annotation} attributes
+ *
+ * @param annotation specified {@link Annotation}
+ * @param propertyResolver {@link PropertyResolver} instance, e.g {@link Environment}
+ * @param ignoreDefaultValue whether ignore default value or not
+ * @param ignoreAttributeNames the attribute names of annotation should be ignored
+ * @return non-null
+ * @since 2.6.6
+ */
+ public static Map<String, Object> getAttributes(Annotation annotation, PropertyResolver propertyResolver,
+ boolean ignoreDefaultValue, String... ignoreAttributeNames) {
+
+ Set<String> ignoreAttributeNamesSet = new HashSet<String>(arrayToList(ignoreAttributeNames));
+
+ Map<String, Object> attributes = getAnnotationAttributes(annotation);
+
+ Map<String, Object> actualAttributes = new LinkedHashMap<String, Object>();
+
+ for (Map.Entry<String, Object> entry : attributes.entrySet()) {
+
+ String attributeName = entry.getKey();
+ Object attributeValue = entry.getValue();
+
+ // ignore default attribute value
+ if (ignoreDefaultValue && nullSafeEquals(attributeValue, getDefaultValue(annotation, attributeName))) {
+ continue;
+ }
+
+ // ignore attribute name
+ if (ignoreAttributeNamesSet.contains(attributeName)) {
+ continue;
+ }
+
+ if (attributeValue instanceof String) {
+ attributeValue = resolvePlaceholders(valueOf(attributeValue), propertyResolver);
+ } else if (attributeValue instanceof String[]) {
+ String[] values = (String[]) attributeValue;
+ for (int i = 0; i < values.length; i++) {
+ values[i] = resolvePlaceholders(values[i], propertyResolver);
+ }
+ attributeValue = values;
+ }
+ actualAttributes.put(attributeName, attributeValue);
+ }
+ return actualAttributes;
+ }
+
+ private static String resolvePlaceholders(String attributeValue, PropertyResolver propertyResolver) {
+ String resolvedValue = attributeValue;
+ if (propertyResolver != null) {
+ resolvedValue = propertyResolver.resolvePlaceholders(resolvedValue);
+ resolvedValue = trimWhitespace(resolvedValue);
+ }
+ return resolvedValue;
+ }
+
}
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtils.java
index 13a3011..9018fdd 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtils.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtils.java
@@ -17,12 +17,21 @@
package com.alibaba.dubbo.config.spring.util;
import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.support.AbstractApplicationContext;
import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors;
+import static org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors;
+import static org.springframework.util.ObjectUtils.containsElement;
/**
* {@link BeanFactory} Utilities class
@@ -31,7 +40,8 @@ import java.lang.reflect.Method;
* @see ConfigurableBeanFactory
* @see org.springframework.beans.factory.BeanFactoryUtils
*/
-public class BeanFactoryUtils {
+public abstract class BeanFactoryUtils {
+
public static boolean addApplicationListener(ApplicationContext applicationContext, ApplicationListener listener) {
try {
// backward compatibility to spring 2.0.1
@@ -55,4 +65,55 @@ public class BeanFactoryUtils {
}
return false;
}
+
+ /**
+ * Get optional Bean
+ *
+ * @param beanFactory {@link ListableBeanFactory}
+ * @param beanName the name of Bean
+ * @param beanType the {@link Class type} of Bean
+ * @param <T> the {@link Class type} of Bean
+ * @return A bean if present , or <code>null</code>
+ * @since 2.6.6
+ */
+ public static <T> T getOptionalBean(ListableBeanFactory beanFactory, String beanName, Class<T> beanType) {
+
+ String[] allBeanNames = beanNamesForTypeIncludingAncestors(beanFactory, beanType);
+
+ if (!containsElement(allBeanNames, beanName)) {
+ return null;
+ }
+
+ Map<String, T> beansOfType = beansOfTypeIncludingAncestors(beanFactory, beanType);
+
+ return beansOfType.get(beanName);
+
+ }
+
+
+ /**
+ * Gets name-matched Beans from {@link ListableBeanFactory BeanFactory}
+ *
+ * @param beanFactory {@link ListableBeanFactory BeanFactory}
+ * @param beanNames the names of Bean
+ * @param beanType the {@link Class type} of Bean
+ * @param <T> the {@link Class type} of Bean
+ * @return the read-only and non-null {@link List} of Bean names
+ * @since 2.6.6
+ */
+ public static <T> List<T> getBeans(ListableBeanFactory beanFactory, String[] beanNames, Class<T> beanType) {
+
+ String[] allBeanNames = beanNamesForTypeIncludingAncestors(beanFactory, beanType);
+
+ List<T> beans = new ArrayList<T>(beanNames.length);
+
+ for (String beanName : beanNames) {
+ if (containsElement(allBeanNames, beanName)) {
+ beans.add(beanFactory.getBean(beanName, beanType));
+ }
+ }
+
+ return Collections.unmodifiableList(beans);
+ }
+
}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanRegistrar.java
index 671d63f..08a13ac 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanRegistrar.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanRegistrar.java
@@ -25,7 +25,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
*
* @since 2.5.7
*/
-public class BeanRegistrar {
+public abstract class BeanRegistrar {
/**
* Register Infrastructure Bean
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ClassUtils.java
similarity index 53%
copy from dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
copy to dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ClassUtils.java
index 1feb2bd..6bb1d81 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ClassUtils.java
@@ -14,9 +14,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.alibaba.dubbo.config.spring.util;
-package com.alibaba.dubbo.config.spring.api;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
-public interface HelloService {
- String sayHello(String name);
+/**
+ * {@link Class} Utilities
+ * <p>
+ * The source code is cloned from
+ * https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/ClassUtils.java
+ *
+ * @since 2.6.6
+ */
+public abstract class ClassUtils {
+
+ public static <T> Class<T> resolveGenericType(Class<?> declaredClass) {
+ ParameterizedType parameterizedType = (ParameterizedType) declaredClass.getGenericSuperclass();
+ Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
+ return (Class<T>) actualTypeArguments[0];
+ }
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ObjectUtils.java
similarity index 68%
copy from dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
copy to dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ObjectUtils.java
index 1feb2bd..abb981f 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ObjectUtils.java
@@ -14,9 +14,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.alibaba.dubbo.config.spring.util;
-package com.alibaba.dubbo.config.spring.api;
+/**
+ * Object Utilities
+ *
+ * @since 2.6.6
+ */
+public abstract class ObjectUtils {
+
+ /**
+ * Convert from variable arguments to array
+ *
+ * @param values variable arguments
+ * @param <T> The class
+ * @return array
+ */
+ public static <T> T[] of(T... values) {
+ return values;
+ }
-public interface HelloService {
- String sayHello(String name);
}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java
new file mode 100644
index 0000000..06c7077
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.spring.util;
+
+import org.springframework.core.env.AbstractEnvironment;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.EnumerablePropertySource;
+import org.springframework.core.env.MutablePropertySources;
+import org.springframework.core.env.PropertySource;
+import org.springframework.core.env.PropertySources;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Properties;
+
+
+/**
+ * {@link PropertySources} Utilities
+ * <p>
+ * The source code is cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/PropertySourcesUtils.java
+ *
+ * @since 2.6.6
+ */
+public abstract class PropertySourcesUtils {
+
+ /**
+ * Get Sub {@link Properties}
+ *
+ * @param propertySources {@link PropertySource} Iterable
+ * @param prefix the prefix of property name
+ * @return Map
+ * @see Properties
+ */
+ public static Map<String, Object> getSubProperties(Iterable<PropertySource<?>> propertySources, String prefix) {
+
+ // Non-Extension AbstractEnvironment
+ AbstractEnvironment environment = new AbstractEnvironment() {
+ };
+
+ MutablePropertySources mutablePropertySources = environment.getPropertySources();
+
+ for (PropertySource<?> source : propertySources) {
+ mutablePropertySources.addLast(source);
+ }
+
+ return getSubProperties(environment, prefix);
+
+ }
+
+ /**
+ * Get Sub {@link Properties}
+ *
+ * @param environment {@link ConfigurableEnvironment}
+ * @param prefix the prefix of property name
+ * @return Map
+ * @see Properties
+ */
+ public static Map<String, Object> getSubProperties(ConfigurableEnvironment environment, String prefix) {
+
+ Map<String, Object> subProperties = new LinkedHashMap<String, Object>();
+
+ MutablePropertySources propertySources = environment.getPropertySources();
+
+ String normalizedPrefix = normalizePrefix(prefix);
+
+ for (PropertySource<?> source : propertySources) {
+ if (source instanceof EnumerablePropertySource) {
+ for (String name : ((EnumerablePropertySource<?>) source).getPropertyNames()) {
+ if (!subProperties.containsKey(name) && name.startsWith(normalizedPrefix)) {
+ String subName = name.substring(normalizedPrefix.length());
+ if (!subProperties.containsKey(subName)) { // take first one
+ Object value = source.getProperty(name);
+ if (value instanceof String) {
+ // Resolve placeholder
+ value = environment.resolvePlaceholders((String) value);
+ }
+ subProperties.put(subName, value);
+ }
+ }
+ }
+ }
+ }
+
+ return Collections.unmodifiableMap(subProperties);
+
+ }
+
+ /**
+ * Normalize the prefix
+ *
+ * @param prefix the prefix
+ * @return the prefix
+ */
+ public static String normalizePrefix(String prefix) {
+ return prefix.endsWith(".") ? prefix : prefix + ".";
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
index 1feb2bd..367ad9e 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
@@ -17,6 +17,13 @@
package com.alibaba.dubbo.config.spring.api;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.QueryParam;
+
+@Path("/hello-service")
public interface HelloService {
- String sayHello(String name);
+
+ @GET
+ String sayHello(@QueryParam("name") String name);
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java
similarity index 58%
copy from dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java
copy to dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java
index 84451bc..28c53cc 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java
@@ -21,25 +21,26 @@ import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.dubbo.config.spring.api.DemoService;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.util.ReflectionUtils;
-import static com.alibaba.dubbo.config.spring.beans.factory.annotation.ServiceBeanNameBuilderTest.GROUP;
-import static com.alibaba.dubbo.config.spring.beans.factory.annotation.ServiceBeanNameBuilderTest.VERSION;
+import static com.alibaba.dubbo.config.spring.beans.factory.annotation.AnnotationBeanNameBuilderTest.GROUP;
+import static com.alibaba.dubbo.config.spring.beans.factory.annotation.AnnotationBeanNameBuilderTest.VERSION;
/**
- * {@link ServiceBeanNameBuilder} Test
+ * {@link AnnotationBeanNameBuilder} Test
*
- * @see ServiceBeanNameBuilder
- * @since 2.6.5
+ * @see AnnotationBeanNameBuilder
+ * @since 2.6.6
*/
@Service(interfaceClass = DemoService.class, group = GROUP, version = VERSION,
application = "application", module = "module", registry = {"1", "2", "3"})
-public class ServiceBeanNameBuilderTest {
+public class AnnotationBeanNameBuilderTest {
- @Reference(interfaceClass = DemoService.class, group = "DUBBO", version = "1.0.0",
+ @Reference(interfaceClass = DemoService.class, group = "DUBBO", version = "${dubbo.version}",
application = "application", module = "module", registry = {"1", "2", "3"})
static final Class<?> INTERFACE_CLASS = DemoService.class;
@@ -47,29 +48,35 @@ public class ServiceBeanNameBuilderTest {
static final String VERSION = "1.0.0";
- static final String BEAN_NAME = "ServiceBean:com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO";
+ private MockEnvironment environment;
- private MockEnvironment environment = new MockEnvironment();
-
- @Test
- public void testRequiredAttributes() {
- ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(INTERFACE_CLASS, environment);
- Assert.assertEquals("ServiceBean:com.alibaba.dubbo.config.spring.api.DemoService", builder.build());
+ @Before
+ public void prepare() {
+ environment = new MockEnvironment();
+ environment.setProperty("dubbo.version", "1.0.0");
}
@Test
public void testServiceAnnotation() {
- Service service = AnnotationUtils.getAnnotation(ServiceBeanNameBuilderTest.class, Service.class);
- ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, INTERFACE_CLASS, environment);
- Assert.assertEquals(BEAN_NAME,
+ Service service = AnnotationUtils.getAnnotation(AnnotationBeanNameBuilderTest.class, Service.class);
+ AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(service, INTERFACE_CLASS);
+ Assert.assertEquals("providers:dubbo:com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO",
+ builder.build());
+
+ builder.environment(environment);
+ Assert.assertEquals("providers:dubbo:com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO",
builder.build());
}
@Test
public void testReferenceAnnotation() {
- Reference reference = AnnotationUtils.getAnnotation(ReflectionUtils.findField(ServiceBeanNameBuilderTest.class, "INTERFACE_CLASS"), Reference.class);
- ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, INTERFACE_CLASS, environment);
- Assert.assertEquals(BEAN_NAME,
+ Reference reference = AnnotationUtils.getAnnotation(ReflectionUtils.findField(AnnotationBeanNameBuilderTest.class, "INTERFACE_CLASS"), Reference.class);
+ AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(reference, INTERFACE_CLASS);
+ Assert.assertEquals("consumers:dubbo:com.alibaba.dubbo.config.spring.api.DemoService:${dubbo.version}:DUBBO",
+ builder.build());
+
+ builder.environment(environment);
+ Assert.assertEquals("consumers:dubbo:com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO",
builder.build());
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java
index b98364b..818eade 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java
@@ -17,51 +17,55 @@
package com.alibaba.dubbo.config.spring.beans.factory.annotation;
import com.alibaba.dubbo.config.ApplicationConfig;
+import com.alibaba.dubbo.config.spring.context.config.NamePropertyDefaultValueDubboConfigBeanCustomizer;
import com.alibaba.dubbo.config.spring.context.properties.DefaultDubboConfigBinder;
-import com.alibaba.dubbo.config.spring.context.properties.DubboConfigBinder;
-
import org.junit.Assert;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.PropertySource;
-
-import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
/**
* {@link DubboConfigBindingBeanPostProcessor}
*/
-@PropertySource({"classpath:/META-INF/config.properties"})
-@Configuration
+@RunWith(SpringRunner.class)
+@ContextConfiguration(classes = {
+ DefaultDubboConfigBinder.class,
+ NamePropertyDefaultValueDubboConfigBeanCustomizer.class,
+ DubboConfigBindingBeanPostProcessorTest.class
+})
+@TestPropertySource(properties = {
+ "dubbo.application.id = dubbo-demo-application",
+ "dubbo.application.owner = mercyblitz",
+ "dubbo.application.organization = Apache",
+
+})
public class DubboConfigBindingBeanPostProcessorTest {
- @Bean("applicationBean")
+ @Bean("dubbo-demo-application")
public ApplicationConfig applicationConfig() {
return new ApplicationConfig();
}
@Bean
- public DubboConfigBinder dubboConfigBinder() {
- return new DefaultDubboConfigBinder();
+ public DubboConfigBindingBeanPostProcessor bindingBeanPostProcessor() {
+ return new DubboConfigBindingBeanPostProcessor("dubbo.application", "dubbo-demo-application");
}
+ @Autowired
+ private ApplicationContext applicationContext;
+
@Test
public void test() {
- final AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
-
- applicationContext.register(getClass());
-
- Class<?> processorClass = DubboConfigBindingBeanPostProcessor.class;
-
- applicationContext.registerBeanDefinition("DubboConfigBindingBeanPostProcessor", rootBeanDefinition(processorClass).addConstructorArgValue("dubbo.application").addConstructorArgValue("applicationBean").getBeanDefinition());
-
- applicationContext.refresh();
-
ApplicationConfig applicationConfig = applicationContext.getBean(ApplicationConfig.class);
Assert.assertEquals("dubbo-demo-application", applicationConfig.getName());
-
+ Assert.assertEquals("mercyblitz", applicationConfig.getOwner());
+ Assert.assertEquals("Apache", applicationConfig.getOrganization());
}
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
index a48a85e..dcb4127 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
@@ -124,7 +124,7 @@ public class ReferenceAnnotationBeanPostProcessorTest {
InjectionMetadata.InjectedElement injectedElement = entry.getKey();
- Assert.assertEquals("com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedFieldElement",
+ Assert.assertEquals("com.alibaba.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedFieldElement",
injectedElement.getClass().getName());
ReferenceBean<?> referenceBean = entry.getValue();
@@ -152,7 +152,7 @@ public class ReferenceAnnotationBeanPostProcessorTest {
InjectionMetadata.InjectedElement injectedElement = entry.getKey();
- Assert.assertEquals("com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedMethodElement",
+ Assert.assertEquals("com.alibaba.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedMethodElement",
injectedElement.getClass().getName());
ReferenceBean<?> referenceBean = entry.getValue();
@@ -229,7 +229,7 @@ public class ReferenceAnnotationBeanPostProcessorTest {
return demoService;
}
- @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345")
+ @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", protocol = "dubbo")
public void setDemoService(DemoService demoService) {
this.demoService = demoService;
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java
new file mode 100644
index 0000000..54b1b97
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.spring.beans.factory.annotation;
+
+import com.alibaba.dubbo.config.annotation.Reference;
+import com.alibaba.dubbo.config.spring.ReferenceBean;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
+import static org.springframework.util.ReflectionUtils.findField;
+
+/**
+ * {@link ReferenceBeanBuilder} Test
+ *
+ * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
+ * @see ReferenceBeanBuilder
+ * @see Reference
+ * @since 2.6.4
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = ReferenceBeanBuilderTest.class)
+public class ReferenceBeanBuilderTest {
+
+ @Reference(
+ interfaceClass = CharSequence.class,
+ interfaceName = "java.lang.CharSequence",
+ version = "1.0.0", group = "TEST_GROUP", url = "dubbo://localhost:12345",
+ client = "client", generic = true, injvm = true,
+ check = false, init = false, lazy = true,
+ stubevent = true, reconnect = "reconnect", sticky = true,
+ proxy = "javassist", stub = "java.lang.CharSequence", cluster = "failover",
+ connections = 3, callbacks = 1, onconnect = "onconnect", ondisconnect = "ondisconnect",
+ owner = "owner", layer = "layer", retries = 1,
+ loadbalance = "random", async = true, actives = 3,
+ sent = true, mock = "mock", validation = "validation",
+ timeout = 3, cache = "cache", filter = {"echo", "generic", "accesslog"},
+ listener = {"deprecated"}, parameters = {"n1=v1 ", "n2 = v2 ", " n3 = v3 "},
+ application = "application",
+ module = "module", consumer = "consumer", monitor = "monitor", registry = {"registry"}
+ )
+ private static final Object TEST_FIELD = new Object();
+
+ @Autowired
+ private ApplicationContext context;
+
+ @Test
+ public void testBuild() throws Exception {
+ Reference reference = findAnnotation(findField(getClass(), "TEST_FIELD"), Reference.class);
+ ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder.create(reference, context.getClassLoader(), context);
+ beanBuilder.interfaceClass(CharSequence.class);
+ ReferenceBean referenceBean = beanBuilder.build();
+ Assert.assertEquals(CharSequence.class, referenceBean.getInterfaceClass());
+ Assert.assertEquals("1.0.0", referenceBean.getVersion());
+ Assert.assertEquals("TEST_GROUP", referenceBean.getGroup());
+ Assert.assertEquals("dubbo://localhost:12345", referenceBean.getUrl());
+ Assert.assertEquals("client", referenceBean.getClient());
+ Assert.assertEquals(true, referenceBean.isGeneric());
+ Assert.assertEquals(true, referenceBean.isInjvm());
+ Assert.assertEquals(false, referenceBean.isCheck());
+ Assert.assertEquals(null, referenceBean.isInit());
+ Assert.assertEquals(true, referenceBean.getLazy());
+ Assert.assertEquals(true, referenceBean.getStubevent());
+ Assert.assertEquals("reconnect", referenceBean.getReconnect());
+ Assert.assertEquals(true, referenceBean.getSticky());
+ Assert.assertEquals("javassist", referenceBean.getProxy());
+ Assert.assertEquals("java.lang.CharSequence", referenceBean.getStub());
+ Assert.assertEquals("failover", referenceBean.getCluster());
+ Assert.assertEquals(Integer.valueOf(3), referenceBean.getConnections());
+ Assert.assertEquals(Integer.valueOf(1), referenceBean.getCallbacks());
+ Assert.assertEquals("onconnect", referenceBean.getOnconnect());
+ Assert.assertEquals("ondisconnect", referenceBean.getOndisconnect());
+ Assert.assertEquals("owner", referenceBean.getOwner());
+ Assert.assertEquals("layer", referenceBean.getLayer());
+ Assert.assertEquals(Integer.valueOf(1), referenceBean.getRetries());
+ Assert.assertEquals("random", referenceBean.getLoadbalance());
+ Assert.assertEquals(true, referenceBean.isAsync());
+ Assert.assertEquals(Integer.valueOf(3), referenceBean.getActives());
+ Assert.assertEquals(true, referenceBean.getSent());
+ Assert.assertEquals("mock", referenceBean.getMock());
+ Assert.assertEquals("validation", referenceBean.getValidation());
+ Assert.assertEquals(Integer.valueOf(3), referenceBean.getTimeout());
+ Assert.assertEquals("cache", referenceBean.getCache());
+ Assert.assertEquals("echo,generic,accesslog", referenceBean.getFilter());
+ Assert.assertEquals("deprecated", referenceBean.getListener());
+
+ // parameters
+ Map<String, String> parameters = new HashMap<String, String>();
+ parameters.put("n1", "v1");
+ parameters.put("n2", "v2");
+ parameters.put("n3", "v3");
+ Assert.assertEquals(parameters, referenceBean.getParameters());
+
+ // Asserts Null fields
+ Assert.assertNull(referenceBean.getApplication());
+ Assert.assertNull(referenceBean.getModule());
+ Assert.assertNull(referenceBean.getConsumer());
+ Assert.assertNull(referenceBean.getMonitor());
+ Assert.assertEquals(Collections.emptyList(), referenceBean.getRegistries());
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java
index 84451bc..91b4b70 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java
@@ -37,6 +37,7 @@ import static com.alibaba.dubbo.config.spring.beans.factory.annotation.ServiceBe
*/
@Service(interfaceClass = DemoService.class, group = GROUP, version = VERSION,
application = "application", module = "module", registry = {"1", "2", "3"})
+@Deprecated
public class ServiceBeanNameBuilderTest {
@Reference(interfaceClass = DemoService.class, group = "DUBBO", version = "1.0.0",
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/EmbeddedZooKeeper.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/EmbeddedZooKeeper.java
new file mode 100644
index 0000000..05c08e7
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/EmbeddedZooKeeper.java
@@ -0,0 +1,252 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.spring.beans.factory.annotation.multiple;
+
+
+import org.apache.zookeeper.server.ServerConfig;
+import org.apache.zookeeper.server.ZooKeeperServerMain;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.SmartLifecycle;
+import org.springframework.util.ErrorHandler;
+import org.springframework.util.SocketUtils;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.Properties;
+import java.util.UUID;
+
+/**
+ * from: https://github.com/spring-projects/spring-xd/blob/v1.3.1.RELEASE/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/zookeeper/ZooKeeperUtils.java
+ * <p>
+ * Helper class to start an embedded instance of standalone (non clustered) ZooKeeper.
+ * <p>
+ * NOTE: at least an external standalone server (if not an ensemble) are recommended, even for
+ * org.springframework.xd.dirt.server.singlenode.SingleNodeApplication
+ *
+ * @author Patrick Peralta
+ * @author Mark Fisher
+ * @author David Turanski
+ */
+public class EmbeddedZooKeeper implements SmartLifecycle {
+
+ /**
+ * Logger.
+ */
+ private static final Logger logger = LoggerFactory.getLogger(EmbeddedZooKeeper.class);
+
+ /**
+ * ZooKeeper client port. This will be determined dynamically upon startup.
+ */
+ private final int clientPort;
+
+ /**
+ * Whether to auto-start. Default is true.
+ */
+ private boolean autoStartup = true;
+
+ /**
+ * Lifecycle phase. Default is 0.
+ */
+ private int phase = 0;
+
+ /**
+ * Thread for running the ZooKeeper server.
+ */
+ private volatile Thread zkServerThread;
+
+ /**
+ * ZooKeeper server.
+ */
+ private volatile ZooKeeperServerMain zkServer;
+
+ /**
+ * {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread.
+ */
+ private ErrorHandler errorHandler;
+
+ private boolean daemon = true;
+
+ /**
+ * Construct an EmbeddedZooKeeper with a random port.
+ */
+ public EmbeddedZooKeeper() {
+ clientPort = SocketUtils.findAvailableTcpPort();
+ }
+
+ /**
+ * Construct an EmbeddedZooKeeper with the provided port.
+ *
+ * @param clientPort port for ZooKeeper server to bind to
+ */
+ public EmbeddedZooKeeper(int clientPort, boolean daemon) {
+ this.clientPort = clientPort;
+ this.daemon = daemon;
+ }
+
+ /**
+ * Returns the port that clients should use to connect to this embedded server.
+ *
+ * @return dynamically determined client port
+ */
+ public int getClientPort() {
+ return this.clientPort;
+ }
+
+ /**
+ * Specify whether to start automatically. Default is true.
+ *
+ * @param autoStartup whether to start automatically
+ */
+ public void setAutoStartup(boolean autoStartup) {
+ this.autoStartup = autoStartup;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isAutoStartup() {
+ return this.autoStartup;
+ }
+
+ /**
+ * Specify the lifecycle phase for the embedded server.
+ *
+ * @param phase the lifecycle phase
+ */
+ public void setPhase(int phase) {
+ this.phase = phase;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getPhase() {
+ return this.phase;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isRunning() {
+ return (zkServerThread != null);
+ }
+
+ /**
+ * Start the ZooKeeper server in a background thread.
+ * <p>
+ * Register an error handler via {@link #setErrorHandler} in order to handle
+ * any exceptions thrown during startup or execution.
+ */
+ @Override
+ public synchronized void start() {
+ if (zkServerThread == null) {
+ zkServerThread = new Thread(new ServerRunnable(), "ZooKeeper Server Starter");
+ zkServerThread.setDaemon(daemon);
+ zkServerThread.start();
+ }
+ }
+
+ /**
+ * Shutdown the ZooKeeper server.
+ */
+ @Override
+ public synchronized void stop() {
+ if (zkServerThread != null) {
+ // The shutdown method is protected...thus this hack to invoke it.
+ // This will log an exception on shutdown; see
+ // https://issues.apache.org/jira/browse/ZOOKEEPER-1873 for details.
+ try {
+ Method shutdown = ZooKeeperServerMain.class.getDeclaredMethod("shutdown");
+ shutdown.setAccessible(true);
+ shutdown.invoke(zkServer);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ // It is expected that the thread will exit after
+ // the server is shutdown; this will block until
+ // the shutdown is complete.
+ try {
+ zkServerThread.join(5000);
+ zkServerThread = null;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ logger.warn("Interrupted while waiting for embedded ZooKeeper to exit");
+ // abandoning zk thread
+ zkServerThread = null;
+ }
+ }
+ }
+
+ /**
+ * Stop the server if running and invoke the callback when complete.
+ */
+ @Override
+ public void stop(Runnable callback) {
+ stop();
+ callback.run();
+ }
+
+ /**
+ * Provide an {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread. If none
+ * is provided, only error-level logging will occur.
+ *
+ * @param errorHandler the {@link ErrorHandler} to be invoked
+ */
+ public void setErrorHandler(ErrorHandler errorHandler) {
+ this.errorHandler = errorHandler;
+ }
+
+ /**
+ * Runnable implementation that starts the ZooKeeper server.
+ */
+ private class ServerRunnable implements Runnable {
+
+ @Override
+ public void run() {
+ try {
+ Properties properties = new Properties();
+ File file = new File(System.getProperty("java.io.tmpdir")
+ + File.separator + UUID.randomUUID());
+ file.deleteOnExit();
+ properties.setProperty("dataDir", file.getAbsolutePath());
+ properties.setProperty("clientPort", String.valueOf(clientPort));
+
+ QuorumPeerConfig quorumPeerConfig = new QuorumPeerConfig();
+ quorumPeerConfig.parseProperties(properties);
+
+ zkServer = new ZooKeeperServerMain();
+ ServerConfig configuration = new ServerConfig();
+ configuration.readFrom(quorumPeerConfig);
+
+ zkServer.runFromConfig(configuration);
+ } catch (Exception e) {
+ if (errorHandler != null) {
+ errorHandler.handleError(e);
+ } else {
+ logger.error("Exception running embedded ZooKeeper", e);
+ }
+ }
+ }
+ }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/consumer/MultipleProtocolsServiceConsumer.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/consumer/MultipleProtocolsServiceConsumer.java
new file mode 100644
index 0000000..5166db8
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/consumer/MultipleProtocolsServiceConsumer.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.spring.beans.factory.annotation.multiple.consumer;
+
+import com.alibaba.dubbo.config.annotation.Reference;
+import com.alibaba.dubbo.config.spring.api.HelloService;
+import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
+
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+
+/**
+ * Multiple Protocols Test
+ */
+
+public class MultipleProtocolsServiceConsumer {
+
+ @EnableDubbo
+ @PropertySource({
+ "classpath:/META-INF/multiple-protocols-consumer.properties",
+ "classpath:/META-INF/dubbo-common.properties"
+ })
+ @Configuration
+ static class ConsumerConfiguration {
+
+ @Reference(version = "${hello.service.version}", protocol = "dubbo")
+ private HelloService dubboHelloService;
+
+ @Reference(version = "${hello.service.version}", protocol = "rest")
+ private HelloService restHelloService;
+
+// @Bean
+// public ReferenceBean<HelloService> restReferenceBean(@Value("${hello.service.version}") String version) {
+// ReferenceBean<HelloService> referenceBean = new ReferenceBean<HelloService>();
+// referenceBean.setVersion(version);
+// referenceBean.setProtocol("rest");
+// referenceBean.setInterface(HelloService.class);
+// return referenceBean;
+// }
+
+ }
+
+// @ImportResource("classpath:/META-INF/spring/dubbo-rest-consumer.xml")
+// @Configuration
+// static class ConsumerXMLConfiguration {
+// }
+
+
+ public static void main(String[] args) {
+
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
+ context.register(ConsumerConfiguration.class);
+ context.refresh();
+
+ ConsumerConfiguration configuration = context.getBean(ConsumerConfiguration.class);
+ System.out.println(configuration.dubboHelloService.sayHello("mercyblitz"));
+ System.out.println(configuration.restHelloService.sayHello("mercyblitz"));
+
+ context.close();
+ }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/DefaultHelloService.java
similarity index 60%
copy from dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
copy to dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/DefaultHelloService.java
index 1feb2bd..43a7ced 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/DefaultHelloService.java
@@ -14,9 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.alibaba.dubbo.config.spring.beans.factory.annotation.multiple.provider;
-package com.alibaba.dubbo.config.spring.api;
+import com.alibaba.dubbo.config.annotation.Service;
+import com.alibaba.dubbo.config.spring.api.HelloService;
+import com.alibaba.dubbo.rpc.RpcContext;
-public interface HelloService {
- String sayHello(String name);
+@Service(version = "${hello.service.version}", protocol = {"dubbo", "rest"})
+public class DefaultHelloService implements HelloService {
+
+ @Override
+ public String sayHello(String name) {
+ return String.format("[%s] Hello , %s", RpcContext.getContext().getUrl(), name);
+ }
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/MultipleProtocolsServiceProvider.java
similarity index 51%
copy from dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java
copy to dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/MultipleProtocolsServiceProvider.java
index a73dbf2..e55d70a 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/MultipleProtocolsServiceProvider.java
@@ -14,47 +14,37 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.alibaba.dubbo.config.spring.context.annotation;
+package com.alibaba.dubbo.config.spring.beans.factory.annotation.multiple.provider;
-import com.alibaba.dubbo.config.ApplicationConfig;
+import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
-import org.junit.Assert;
-import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.PropertySource;
+import java.io.IOException;
+
/**
- * {@link DubboConfigBindingsRegistrar} Test
- *
- * @since DubboConfigBindingsRegistrar
+ * Multiple Protocols Service Provider
*/
-public class DubboConfigBindingsRegistrarTest {
+@EnableDubbo
+@PropertySource({
+ "classpath:/META-INF/multiple-protocols-provider.properties",
+ "classpath:/META-INF/dubbo-common.properties"
+})
+public class MultipleProtocolsServiceProvider {
- @Test
- public void test() {
+ public static void main(String[] args) throws IOException {
+// EmbeddedZooKeeper embeddedZooKeeper = new EmbeddedZooKeeper(2181, false);
+// embeddedZooKeeper.start();
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
-
- context.register(TestConfig.class);
-
+ context.register(MultipleProtocolsServiceProvider.class);
context.refresh();
- ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class);
-
- Assert.assertEquals("dubbo-demo-application", applicationConfig.getName());
-
- Assert.assertEquals(2, context.getBeansOfType(ApplicationConfig.class).size());
+ System.out.println("Enter any key to close the application");
+ System.in.read();
+ context.close();
+// embeddedZooKeeper.stop();
}
-
-
- @EnableDubboConfigBindings({
- @EnableDubboConfigBinding(prefix = "${application.prefix}", type = ApplicationConfig.class),
- @EnableDubboConfigBinding(prefix = "dubbo.applications.applicationBean", type = ApplicationConfig.class)
- })
- @PropertySource("META-INF/config.properties")
- private static class TestConfig {
-
- }
-
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java
index 54d6c97..20a1504 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java
@@ -111,5 +111,31 @@ public class DubboComponentScanRegistrarTest {
}
+ @Test(expected = UnsupportedOperationException.class)
+ public void testOnException() {
+
+ AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext();
+
+ providerContext.register(ProviderConfiguration.class);
+
+ providerContext.refresh();
+
+ AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
+
+ consumerContext.register(ConsumerConfiguration.class);
+
+ consumerContext.refresh();
+
+ ConsumerConfiguration.Child child = consumerContext.getBean(ConsumerConfiguration.Child.class);
+
+ // From Child
+ DemoService demoService = child.getDemoServiceFromChild();
+
+ demoService.getBox();
+
+ providerContext.close();
+ consumerContext.close();
+ }
+
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java
index 853df84..30fc54a 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java
@@ -23,6 +23,11 @@ import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.PropertySource;
+import java.util.Set;
+import java.util.TreeSet;
+
+import static java.util.Arrays.asList;
+
/**
* {@link DubboConfigBindingRegistrar}
*
@@ -55,9 +60,14 @@ public class DubboConfigBindingRegistrarTest {
context.refresh();
- ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class);
+ Set<String> expectedBeanNames = new TreeSet<String>(asList("applicationBean1", "applicationBean2", "applicationBean3"));
+ Set<String> actualBeanNames = new TreeSet<String>(asList(context.getBeanNamesForType(ApplicationConfig.class)));
- Assert.assertEquals("dubbo-demo-application", applicationConfig.getName());
+ Assert.assertEquals(expectedBeanNames, actualBeanNames);
+
+ ApplicationConfig applicationConfig = context.getBean("applicationBean1", ApplicationConfig.class);
+
+ Assert.assertEquals("dubbo-demo-application1", applicationConfig.getName());
applicationConfig = context.getBean("applicationBean2", ApplicationConfig.class);
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java
index a73dbf2..b871983 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java
@@ -50,7 +50,7 @@ public class DubboConfigBindingsRegistrarTest {
@EnableDubboConfigBindings({
@EnableDubboConfigBinding(prefix = "${application.prefix}", type = ApplicationConfig.class),
- @EnableDubboConfigBinding(prefix = "dubbo.applications.applicationBean", type = ApplicationConfig.class)
+ @EnableDubboConfigBinding(prefix = "dubbo.applications.applicationBean1", type = ApplicationConfig.class)
})
@PropertySource("META-INF/config.properties")
private static class TestConfig {
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java
index ff21bcd..5a4222e 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java
@@ -84,8 +84,8 @@ public class DubboConfigConfigurationTest {
context.refresh();
// application
- ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class);
- Assert.assertEquals("dubbo-demo-application", applicationConfig.getName());
+ ApplicationConfig applicationConfig = context.getBean("applicationBean1", ApplicationConfig.class);
+ Assert.assertEquals("dubbo-demo-application1", applicationConfig.getName());
ApplicationConfig applicationBean2 = context.getBean("applicationBean2", ApplicationConfig.class);
Assert.assertEquals("dubbo-demo-application2", applicationBean2.getName());
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java
index d5c41b0..15b462e 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java
@@ -23,12 +23,18 @@ import com.alibaba.dubbo.config.MonitorConfig;
import com.alibaba.dubbo.config.ProtocolConfig;
import com.alibaba.dubbo.config.ProviderConfig;
import com.alibaba.dubbo.config.RegistryConfig;
-
+import com.alibaba.dubbo.config.spring.util.ObjectUtils;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.PropertySource;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import static java.util.Arrays.asList;
+
/**
* {@link EnableDubboConfig} Test
*
@@ -47,6 +53,8 @@ public class EnableDubboConfigTest {
ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class);
Assert.assertEquals("dubbo-demo-application", applicationConfig.getName());
+ Assert.assertArrayEquals(ObjectUtils.of("applicationBean"), context.getBeanNamesForType(ApplicationConfig.class));
+
// module
ModuleConfig moduleConfig = context.getBean("moduleBean", ModuleConfig.class);
Assert.assertEquals("dubbo-demo-module", moduleConfig.getName());
@@ -82,25 +90,42 @@ public class EnableDubboConfigTest {
context.register(TestMultipleConfig.class);
context.refresh();
+ Set<String> expectedBeanNames = new TreeSet<String>(asList("applicationBean", "applicationBean1", "applicationBean2", "applicationBean3"));
+ Set<String> actualBeanNames = new TreeSet<String>(asList(context.getBeanNamesForType(ApplicationConfig.class)));
+
+ Assert.assertEquals(expectedBeanNames, actualBeanNames);
+
// application
ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class);
Assert.assertEquals("dubbo-demo-application", applicationConfig.getName());
+ applicationConfig = context.getBean("applicationBean1", ApplicationConfig.class);
+ Assert.assertEquals("dubbo-demo-application1", applicationConfig.getName());
+
ApplicationConfig applicationBean2 = context.getBean("applicationBean2", ApplicationConfig.class);
Assert.assertEquals("dubbo-demo-application2", applicationBean2.getName());
ApplicationConfig applicationBean3 = context.getBean("applicationBean3", ApplicationConfig.class);
Assert.assertEquals("dubbo-demo-application3", applicationBean3.getName());
+
+ Map<String, ProtocolConfig> protocolConfigs = context.getBeansOfType(ProtocolConfig.class);
+
+ for (Map.Entry<String, ProtocolConfig> entry : protocolConfigs.entrySet()) {
+ String beanName = entry.getKey();
+ ProtocolConfig protocol = entry.getValue();
+ Assert.assertEquals(beanName, protocol.getName());
+ }
+
}
- @EnableDubboConfig(multiple = true)
+ @EnableDubboConfig
@PropertySource("META-INF/config.properties")
private static class TestMultipleConfig {
}
- @EnableDubboConfig
+ @EnableDubboConfig(multiple = false)
@PropertySource("META-INF/config.properties")
private static class TestConfig {
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java
index e419632..29d8a3c 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java
@@ -24,12 +24,14 @@ import com.alibaba.dubbo.config.spring.context.annotation.provider.DemoServiceIm
import org.junit.Assert;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.springframework.aop.support.AopUtils;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Primary;
-import org.springframework.context.annotation.PropertySource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.*;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
@@ -44,17 +46,21 @@ import static org.springframework.core.annotation.AnnotationUtils.findAnnotation
*
* @since 2.5.8
*/
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = {EnableDubboTest.class})
+@TestPropertySource(locations = "classpath:/META-INF/dubbb-provider.properties",
+ properties = "demo.service.version = 2.5.7")
+@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.config.spring.context.annotation.provider")
+@ComponentScan(basePackages = "com.alibaba.dubbo.config.spring.context.annotation.provider")
+@EnableTransactionManagement
public class EnableDubboTest {
+ @Autowired
+ private ApplicationContext providerContext;
+
@Test
public void test() {
- AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext();
-
- providerContext.register(TestProviderConfiguration.class);
-
- providerContext.refresh();
-
DemoService demoService = providerContext.getBean(DemoService.class);
String value = demoService.sayName("Mercy");
@@ -69,11 +75,7 @@ public class EnableDubboTest {
// Test @Transactional is present or not
Assert.assertNotNull(findAnnotation(beanClass, Transactional.class));
- AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
-
- consumerContext.register(TestConsumerConfiguration.class);
-
- consumerContext.refresh();
+ AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(TestConsumerConfiguration.class);
TestConsumerConfiguration consumerConfiguration = consumerContext.getBean(TestConsumerConfiguration.class);
@@ -128,10 +130,6 @@ public class EnableDubboTest {
// Test multiple binding
Assert.assertEquals("N/A", registryConfig.getAddress());
- providerContext.close();
- consumerContext.close();
-
-
}
@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.config.spring.context.annotation.provider")
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java
index 2641fae..84c451a 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java
@@ -29,7 +29,7 @@ import org.springframework.transaction.annotation.Transactional;
* @since 2.5.8
*/
@com.alibaba.dubbo.config.annotation.Service(
- version = "2.5.7",
+ version = "${demo.service.version}",
application = "${demo.service.application}",
protocol = "${demo.service.protocol}",
registry = "${demo.service.registry}"
@@ -45,11 +45,6 @@ public class DemoServiceImpl implements DemoService {
@Override
public Box getBox() {
- return new Box() {
- @Override
- public String getName() {
- return "MyBox";
- }
- };
+ throw new UnsupportedOperationException("For Purposes!");
}
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtilsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtilsTest.java
new file mode 100644
index 0000000..c54fa9f
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtilsTest.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.spring.util;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.annotation.AnnotationConfigUtils;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * {@link AnnotatedBeanDefinitionRegistryUtils} Test
+ *
+ * @see AnnotatedBeanDefinitionRegistryUtils
+ * @since 2.6.6
+ */
+public class AnnotatedBeanDefinitionRegistryUtilsTest {
+
+ private DefaultListableBeanFactory registry = null;
+
+ @Before
+ public void init() {
+ registry = new DefaultListableBeanFactory();
+ AnnotationConfigUtils.registerAnnotationConfigProcessors(registry);
+ }
+
+ @Test
+ public void testRegisterBeans() {
+
+ AnnotatedBeanDefinitionRegistryUtils.registerBeans(registry, this.getClass());
+
+ String[] beanNames = registry.getBeanNamesForType(this.getClass());
+
+ Assert.assertEquals(1, beanNames.length);
+
+ beanNames = registry.getBeanNamesForType(AnnotatedBeanDefinitionRegistryUtils.class);
+
+ Assert.assertTrue(ObjectUtils.isEmpty(beanNames));
+
+ AnnotatedBeanDefinitionRegistryUtils.registerBeans(registry);
+
+ }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java
new file mode 100644
index 0000000..4a17ac1
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.spring.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.MutablePropertySources;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * {@link PropertySourcesUtils} Test
+ *
+ * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
+ * @see PropertySourcesUtils
+ * @since 2.6.6
+ */
+public class PropertySourcesUtilsTest {
+
+ @Test
+ public void testGetSubProperties() {
+
+ MutablePropertySources propertySources = new MutablePropertySources();
+
+ Map<String, Object> source = new HashMap<String, Object>();
+ Map<String, Object> source2 = new HashMap<String, Object>();
+
+ MapPropertySource propertySource = new MapPropertySource("propertySource", source);
+ MapPropertySource propertySource2 = new MapPropertySource("propertySource2", source2);
+
+ propertySources.addLast(propertySource);
+ propertySources.addLast(propertySource2);
+
+ Map<String, Object> result = PropertySourcesUtils.getSubProperties(propertySources, "user");
+
+ Assert.assertEquals(Collections.emptyMap(), result);
+
+ source.put("age", "31");
+ source.put("user.name", "Mercy");
+ source.put("user.age", "${age}");
+
+ source2.put("user.name", "mercyblitz");
+ source2.put("user.age", "32");
+
+ Map<String, Object> expected = new HashMap<String, Object>();
+ expected.put("name", "Mercy");
+ expected.put("age", "31");
+
+ result = PropertySourcesUtils.getSubProperties(propertySources, "user");
+
+ Assert.assertEquals(expected, result);
+
+ result = PropertySourcesUtils.getSubProperties(propertySources, "");
+
+ Assert.assertEquals(Collections.emptyMap(), result);
+
+ result = PropertySourcesUtils.getSubProperties(propertySources, "no-exists");
+
+ Assert.assertEquals(Collections.emptyMap(), result);
+
+ }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties
index 6e728cc..1063fe6 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties
@@ -14,9 +14,13 @@ dubbo.module.name = dubbo-demo-module
dubbo.registry.address = zookeeper://192.168.99.100:32770
## protocol
+dubbo.protocol.id = dubbo
dubbo.protocol.name = dubbo
dubbo.protocol.port = 20880
+dubbo.protocols.rest.port=8080
+dubbo.protocols.thrift.port=9090
+
## monitor
dubbo.monitor.address = zookeeper://127.0.0.1:32770
@@ -27,6 +31,6 @@ dubbo.provider.host = 127.0.0.1
dubbo.consumer.client = netty
# multiple Bean definition
-dubbo.applications.applicationBean.name = dubbo-demo-application
+dubbo.applications.applicationBean1.name = dubbo-demo-application1
dubbo.applications.applicationBean2.name = dubbo-demo-application2
dubbo.applications.applicationBean3.name = dubbo-demo-application3
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-common.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-common.properties
new file mode 100644
index 0000000..36146a1
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-common.properties
@@ -0,0 +1,2 @@
+dubbo.registry.address=zookeeper://127.0.0.1:2181
+hello.service.version=1.0.0
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-consumer.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-consumer.properties
new file mode 100644
index 0000000..abbe51c
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-consumer.properties
@@ -0,0 +1 @@
+dubbo.application.id=provider
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-provider.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-provider.properties
new file mode 100644
index 0000000..9879049
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-provider.properties
@@ -0,0 +1,6 @@
+dubbo.application.id=provider
+dubbo.protocols.dubbo.name=dubbo
+dubbo.protocols.dubbo.port=12345
+dubbo.protocols.rest.name=rest
+dubbo.protocols.rest.port=9090
+dubbo.protocols.rest.server=netty
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-rest-consumer.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-rest-consumer.xml
new file mode 100644
index 0000000..c7db5ff
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-rest-consumer.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:dubbo="http://dubbo.apache.org/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-4.3.xsd
+ http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
+
+ <dubbo:application name="dubbo-rest-consumer"/>
+
+ <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
+
+ <dubbo:reference id="restReferenceBean" interface="com.alibaba.dubbo.config.spring.api.HelloService"
+ version="1.0.0"
+ protocol="rest"/>
+
+</beans>
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/DubboRegistration.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/DubboRegistration.java
new file mode 100644
index 0000000..50deb0a
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/DubboRegistration.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.registry.support;
+
+import java.util.Map;
+
+/**
+ * Dubbo Registration
+ *
+ * @since 2.6.6
+ */
+class DubboRegistration implements Registration {
+
+ private String serviceName;
+
+ private String ip;
+
+ private int port;
+
+ private Map<String, String> metadata;
+
+ @Override
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ public void setServiceName(String serviceName) {
+ this.serviceName = serviceName;
+ }
+
+ @Override
+ public String getIp() {
+ return ip;
+ }
+
+ public void setIp(String ip) {
+ this.ip = ip;
+ }
+
+ @Override
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ @Override
+ public Map<String, String> getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(Map<String, String> metadata) {
+ this.metadata = metadata;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ DubboRegistration that = (DubboRegistration) o;
+
+ if (port != that.port) return false;
+ if (serviceName != null ? !serviceName.equals(that.serviceName) : that.serviceName != null) return false;
+ if (ip != null ? !ip.equals(that.ip) : that.ip != null) return false;
+ return metadata != null ? metadata.equals(that.metadata) : that.metadata == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = serviceName != null ? serviceName.hashCode() : 0;
+ result = 31 * result + (ip != null ? ip.hashCode() : 0);
+ result = 31 * result + port;
+ result = 31 * result + (metadata != null ? metadata.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/Registration.java
similarity index 60%
copy from dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
copy to dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/Registration.java
index 1feb2bd..143cc9f 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/Registration.java
@@ -14,9 +14,40 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.alibaba.dubbo.registry.support;
-package com.alibaba.dubbo.config.spring.api;
+import java.util.Map;
-public interface HelloService {
- String sayHello(String name);
+/**
+ * The Registration
+ *
+ * @since 2.6.6
+ */
+public interface Registration {
+
+ /**
+ * @return The service name
+ */
+ String getServiceName();
+
+ /**
+ * @return The IP address
+ */
+ String getIp();
+
+ /**
+ * @return The service port
+ */
+ int getPort();
+
+ /**
+ * @return The read-only metadata
+ */
+ Map<String, String> getMetadata();
+
+ @Override
+ boolean equals(Object o);
+
+ @Override
+ int hashCode();
}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/ServiceInstanceRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/ServiceInstanceRegistry.java
new file mode 100644
index 0000000..d6b1d87
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/ServiceInstanceRegistry.java
@@ -0,0 +1,474 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.registry.support;
+
+import com.alibaba.dubbo.common.Constants;
+import com.alibaba.dubbo.common.URL;
+import com.alibaba.dubbo.common.logger.Logger;
+import com.alibaba.dubbo.common.logger.LoggerFactory;
+import com.alibaba.dubbo.common.utils.StringUtils;
+import com.alibaba.dubbo.common.utils.UrlUtils;
+import com.alibaba.dubbo.registry.NotifyListener;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import static com.alibaba.dubbo.common.Constants.CONFIGURATORS_CATEGORY;
+import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY;
+import static com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY;
+import static com.alibaba.dubbo.common.Constants.ROUTERS_CATEGORY;
+import static java.lang.Long.getLong;
+import static java.lang.System.getProperty;
+
+/**
+ * {@link FailbackRegistry} extension that is used as the Oriented Service Instance registration, for
+ *
+ * @param <S> The actual type of service instance
+ * @since 2.6.6
+ */
+public abstract class ServiceInstanceRegistry<S> extends FailbackRegistry {
+
+ /**
+ * All supported categories
+ */
+ private static final String[] ALL_SUPPORTED_CATEGORIES = of(
+ PROVIDERS_CATEGORY,
+ CONSUMERS_CATEGORY,
+ ROUTERS_CATEGORY,
+ CONFIGURATORS_CATEGORY
+ );
+
+ private static final int CATEGORY_INDEX = 0;
+
+ private static final int SERVICE_INTERFACE_INDEX = CATEGORY_INDEX + 1;
+
+ private static final int SERVICE_VERSION_INDEX = SERVICE_INTERFACE_INDEX + 1;
+
+ private static final int SERVICE_GROUP_INDEX = SERVICE_VERSION_INDEX + 1;
+
+ private static final String WILDCARD = "*";
+
+ /**
+ * The separator for service name
+ */
+ private static final String SERVICE_NAME_SEPARATOR = getProperty("dubbo.service.name.separator", ":");
+
+ /**
+ * The interval in second of lookup service names(only for Dubbo-OPS)
+ */
+ private static final long LOOKUP_INTERVAL = getLong("dubbo.service.names.lookup.interval", 30);
+
+ protected final Logger logger = LoggerFactory.getLogger(getClass());
+
+ /**
+ * {@link ScheduledExecutorService} lookup service names(only for Dubbo-OPS)
+ */
+ private volatile ScheduledExecutorService serviceNamesScheduler;
+
+ public ServiceInstanceRegistry(URL url) {
+ super(url);
+ }
+
+ @Override
+ protected final void doRegister(URL url) {
+ String serviceName = getServiceName(url);
+ Registration registration = createRegistration(serviceName, url);
+ register(serviceName, toServiceInstance(registration), url);
+ }
+
+ @Override
+ protected final void doUnregister(URL url) {
+ String serviceName = getServiceName(url);
+ Registration registration = createRegistration(serviceName, url);
+ deregister(serviceName, toServiceInstance(registration), url);
+ }
+
+ @Override
+ protected final void doSubscribe(URL url, NotifyListener listener) {
+ Set<String> serviceNames = getServiceNames(url, listener);
+ doSubscribe(url, listener, serviceNames);
+ }
+
+ @Override
+ protected void doUnsubscribe(URL url, NotifyListener listener) {
+ if (isAdminProtocol(url)) {
+ shutdownServiceNamesLookup();
+ }
+ }
+
+ /**
+ * Adapts {@link Registration} to an actual service instance
+ *
+ * @param registration {@link Registration}
+ * @return
+ */
+ protected abstract S toServiceInstance(Registration registration);
+
+ /**
+ * Adapts {@link S} to an {@link Registration}
+ *
+ * @param serviceInstance {@link S}
+ * @return an {@link Registration}
+ */
+ protected abstract Registration toRegistration(S serviceInstance);
+
+ /**
+ * Register a {@link S service instance}
+ *
+ * @param serviceName the service name
+ * @param serviceInstance {@link S service instance}
+ * @param url Dubbo's {@link URL}
+ */
+ protected abstract void register(String serviceName, S serviceInstance, URL url);
+
+ /**
+ * Deregister a {@link DubboRegistration Dubbol registration}
+ *
+ * @param serviceName the service name
+ * @param serviceInstance {@link S service instance}
+ * @param url Dubbo's {@link URL}
+ */
+ protected abstract void deregister(String serviceName, S serviceInstance, URL url);
+
+ private void doSubscribe(final URL url, final NotifyListener listener, final Set<String> serviceNames) {
+ Collection<S> serviceInstances = new LinkedList<S>();
+
+ for (String serviceName : serviceNames) {
+ serviceInstances.addAll(findServiceInstances(serviceName));
+ }
+ notifySubscriber(url, listener, serviceInstances);
+ }
+
+ /**
+ * Notify the Healthy {@link DubboRegistration service instance} to subscriber.
+ *
+ * @param url {@link URL}
+ * @param listener {@link NotifyListener}
+ * @param serviceInstances all {@link S registrations}
+ */
+ private void notifySubscriber(URL url, NotifyListener listener, Collection<S> serviceInstances) {
+ Set<S> healthyServiceInstances = new LinkedHashSet<S>(serviceInstances);
+ // Healthy Instances
+ filterHealthyInstances(healthyServiceInstances);
+ List<URL> urls = buildURLs(url, healthyServiceInstances);
+ this.notify(url, listener, urls);
+ }
+
+ private void filterHealthyInstances(Collection<S> serviceInstances) {
+ filter(serviceInstances, new Filter<S>() {
+ @Override
+ public boolean accept(S serviceInstance) {
+ return filterHealthyRegistration(serviceInstance);
+ }
+ });
+ }
+
+ /**
+ * Find the {@link Collection} of {@link S service instances} by the service name
+ *
+ * @param serviceName the service name
+ * @return a {@link Collection} of {@link S service instances}
+ */
+ protected abstract Collection<S> findServiceInstances(String serviceName);
+
+ /**
+ * Filter Healthy the {@link S service instance}
+ *
+ * @param serviceInstance the {@link S service instance}
+ * @return if healthy , return <code>true</code>
+ */
+ protected abstract boolean filterHealthyRegistration(S serviceInstance);
+
+ private void shutdownServiceNamesLookup() {
+ if (serviceNamesScheduler != null) {
+ serviceNamesScheduler.shutdown();
+ }
+ }
+
+ private void scheduleServiceNamesLookup(final URL url,
+ final NotifyListener listener) {
+ if (serviceNamesScheduler == null) {
+ serviceNamesScheduler = Executors.newSingleThreadScheduledExecutor();
+ serviceNamesScheduler.scheduleAtFixedRate(new Runnable() {
+ @Override
+ public void run() {
+ Set<String> serviceNames = findAllServiceNames();
+ filter(serviceNames, new Filter<String>() {
+ @Override
+ public boolean accept(String serviceName) {
+ boolean accepted = false;
+ for (String category : ALL_SUPPORTED_CATEGORIES) {
+ String prefix = category + SERVICE_NAME_SEPARATOR;
+ if (serviceName.startsWith(prefix)) {
+ accepted = true;
+ break;
+ }
+ }
+ return accepted;
+ }
+ });
+ doSubscribe(url, listener, serviceNames);
+ }
+ }, LOOKUP_INTERVAL, LOOKUP_INTERVAL, TimeUnit.SECONDS);
+ }
+ }
+
+ /**
+ * Find all service names
+ *
+ * @return all service names
+ */
+ protected abstract Set<String> findAllServiceNames();
+
+ private List<URL> buildURLs(URL consumerURL, Collection<S> serviceInstances) {
+ if (serviceInstances.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List<URL> urls = new LinkedList<URL>();
+ for (S serviceInstance : serviceInstances) {
+ Registration registration = toRegistration(serviceInstance);
+ URL url = buildURL(registration);
+ if (UrlUtils.isMatch(consumerURL, url)) {
+ urls.add(url);
+ }
+ }
+ return urls;
+ }
+
+ private URL buildURL(Registration registration) {
+ URL url = new URL(registration.getMetadata().get(Constants.PROTOCOL_KEY),
+ registration.getIp(), registration.getPort(),
+ registration.getMetadata());
+ return url;
+ }
+
+ /**
+ * Get the service names for Dubbo OPS
+ *
+ * @param url {@link URL}
+ * @return non-null
+ */
+ private Set<String> getSubscribedServiceNamesForOps(URL url) {
+ Set<String> serviceNames = findAllServiceNames();
+ filterServiceNames(serviceNames, url);
+ return serviceNames;
+ }
+
+ private <T> void filter(Collection<T> collection, Filter<T> filter) {
+ Iterator<T> iterator = collection.iterator();
+ while (iterator.hasNext()) {
+ T data = iterator.next();
+ if (!filter.accept(data)) { // remove if not accept
+ iterator.remove();
+ }
+ }
+ }
+
+ private void filterServiceNames(Set<String> serviceNames, URL url) {
+
+ final String[] categories = getCategories(url);
+
+ final String targetServiceInterface = url.getServiceInterface();
+
+ final String targetVersion = url.getParameter(Constants.VERSION_KEY);
+
+ final String targetGroup = url.getParameter(Constants.GROUP_KEY);
+
+ filter(serviceNames, new Filter<String>() {
+ @Override
+ public boolean accept(String serviceName) {
+ // split service name to segments
+ // (required) segments[0] = category
+ // (required) segments[1] = serviceInterface
+ // (required) segments[2] = version
+ // (optional) segments[3] = group
+ String[] segments = getServiceSegments(serviceName);
+ int length = segments.length;
+ if (length < 4) { // must present 4 segments or more
+ return false;
+ }
+
+ String category = getCategory(segments);
+ if (Arrays.binarySearch(categories, category) > -1) { // no match category
+ return false;
+ }
+
+ String serviceInterface = getServiceInterface(segments);
+ if (!WILDCARD.equals(targetServiceInterface)
+ && !StringUtils.isEquals(targetServiceInterface, serviceInterface)) { // no match interface
+ return false;
+ }
+
+ String version = getServiceVersion(segments);
+ if (!WILDCARD.equals(targetVersion)
+ && !StringUtils.isEquals(targetVersion, version)) { // no match service
+ // version
+ return false;
+ }
+
+ String group = getServiceGroup(segments);
+ if (group != null && !WILDCARD.equals(targetGroup)
+ && !StringUtils.isEquals(targetGroup, group)) { // no match service
+ // group
+ return false;
+ }
+
+ return true;
+ }
+ });
+ }
+
+ protected Registration createRegistration(String serviceName, URL url) {
+ // Append default category if absent
+ String category = url.getParameter(Constants.CATEGORY_KEY,
+ Constants.DEFAULT_CATEGORY);
+ URL newURL = url.addParameter(Constants.CATEGORY_KEY, category);
+ newURL = newURL.addParameter(Constants.PROTOCOL_KEY, url.getProtocol());
+ String ip = url.getHost();
+ int port = url.getPort();
+ DubboRegistration registration = new DubboRegistration();
+ registration.setServiceName(serviceName);
+ registration.setIp(ip);
+ registration.setPort(port);
+ registration.setMetadata(new LinkedHashMap<String, String>(newURL.getParameters()));
+
+ return registration;
+ }
+
+ /**
+ * Get the categories from {@link URL}
+ *
+ * @param url {@link URL}
+ * @return non-null array
+ */
+ private String[] getCategories(URL url) {
+ return Constants.ANY_VALUE.equals(url.getServiceInterface())
+ ? ALL_SUPPORTED_CATEGORIES
+ : of(Constants.DEFAULT_CATEGORY);
+ }
+
+ /**
+ * A filter
+ */
+ private interface Filter<T> {
+
+ /**
+ * Tests whether or not the specified data should be accepted.
+ *
+ * @param data The data to be tested
+ * @return <code>true</code> if and only if <code>data</code> should be accepted
+ */
+ boolean accept(T data);
+
+ }
+
+ /**
+ * Get the subscribed service names from the specified {@link URL url}
+ *
+ * @param url {@link URL}
+ * @param listener {@link NotifyListener}
+ * @return non-null
+ */
+ private Set<String> getServiceNames(URL url, NotifyListener listener) {
+ if (isAdminProtocol(url)) {
+ scheduleServiceNamesLookup(url, listener);
+ return getSubscribedServiceNamesForOps(url);
+ } else {
+ return getServiceNames(url);
+ }
+ }
+
+ private Set<String> getServiceNames(URL url) {
+ String[] categories = getCategories(url);
+ Set<String> serviceNames = new LinkedHashSet<String>(categories.length);
+ for (String category : categories) {
+ final String serviceName = getServiceName(url, category);
+ serviceNames.add(serviceName);
+ }
+ return serviceNames;
+ }
+
+ private boolean isAdminProtocol(URL url) {
+ return Constants.ADMIN_PROTOCOL.equals(url.getProtocol());
+ }
+
+ /**
+ * Get the service name
+ *
+ * @param url {@link URL}
+ * @return non-null
+ */
+ public static String getServiceName(URL url) {
+ String category = url.getParameter(Constants.CATEGORY_KEY,
+ Constants.DEFAULT_CATEGORY);
+ return getServiceName(url, category);
+ }
+
+ private static String getServiceName(URL url, String category) {
+ StringBuilder serviceNameBuilder = new StringBuilder(category);
+ appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY);
+ appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY);
+ appendIfPresent(serviceNameBuilder, url, Constants.GROUP_KEY);
+ return serviceNameBuilder.toString();
+ }
+
+ private static void appendIfPresent(StringBuilder target, URL url,
+ String parameterName) {
+ String parameterValue = url.getParameter(parameterName);
+ appendIfPresent(target, parameterValue);
+ }
+
+ public static String[] getServiceSegments(String serviceName) {
+ return serviceName.split(SERVICE_NAME_SEPARATOR);
+ }
+
+ public static String getCategory(String[] segments) {
+ return segments[CATEGORY_INDEX];
+ }
+
+ public static String getServiceInterface(String[] segments) {
+ return segments[SERVICE_INTERFACE_INDEX];
+ }
+
+ public static String getServiceVersion(String[] segments) {
+ return segments[SERVICE_VERSION_INDEX];
+ }
+
+ public static String getServiceGroup(String[] segments) {
+ return segments.length > 4 ? segments[SERVICE_GROUP_INDEX] : null;
+ }
+
+ private static <T> T[] of(T... values) {
+ return values;
+ }
+
+ private static void appendIfPresent(StringBuilder target, String parameterValue) {
+ if (StringUtils.isNotEmpty(parameterValue)) {
+ target.append(SERVICE_NAME_SEPARATOR).append(parameterValue);
+ }
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-nacos/pom.xml b/dubbo-registry/dubbo-registry-nacos/pom.xml
new file mode 100644
index 0000000..53b7e72
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/pom.xml
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>dubbo-registry</artifactId>
+ <groupId>com.alibaba</groupId>
+ <version>2.6.6-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dubbo-registry-nacos</artifactId>
+
+ <properties>
+ <nacos.version>0.6.2</nacos.version>
+ </properties>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>dubbo-registry-api</artifactId>
+ <version>${project.version}</version>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>dubbo-common</artifactId>
+ <version>${project.version}</version>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>com.alibaba.nacos</groupId>
+ <artifactId>nacos-client</artifactId>
+ <version>${nacos.version}</version>
+ <optional>true</optional>
+ </dependency>
+
+ <!-- Test Libraries -->
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>dubbo-config-api</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>dubbo-serialization-hessian2</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>dubbo-config-spring</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>dubbo-rpc-dubbo</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>dubbo-remoting-netty4</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.3</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- REST support dependencies -->
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>dubbo-rpc-rest</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxrs</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-client</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-netty4</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.validation</groupId>
+ <artifactId>validation-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jackson-provider</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxb-provider</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ </dependencies>
+</project>
diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistry.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistry.java
new file mode 100644
index 0000000..621e7b4
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistry.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.registry.nacos;
+
+import com.alibaba.dubbo.common.URL;
+import com.alibaba.dubbo.registry.Registry;
+import com.alibaba.dubbo.registry.support.Registration;
+import com.alibaba.dubbo.registry.support.ServiceInstanceRegistry;
+import com.alibaba.nacos.api.exception.NacosException;
+import com.alibaba.nacos.api.naming.NamingService;
+import com.alibaba.nacos.api.naming.listener.EventListener;
+import com.alibaba.nacos.api.naming.pojo.Instance;
+import com.alibaba.nacos.api.naming.pojo.ListView;
+
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Nacos {@link Registry}
+ *
+ * @since 2.6.6
+ */
+public class NacosRegistry extends ServiceInstanceRegistry<Instance> {
+
+ /**
+ * The pagination size of query for Nacos service names(only for Dubbo-OPS)
+ */
+ private static final int PAGINATION_SIZE = Integer.getInteger("nacos.service.names.pagination.size", 100);
+
+ private final NamingService namingService;
+
+ private final ConcurrentMap<String, EventListener> nacosListeners;
+
+ public NacosRegistry(URL url, NamingService namingService) {
+ super(url);
+ this.namingService = namingService;
+ this.nacosListeners = new ConcurrentHashMap<String, EventListener>();
+ }
+
+
+ @Override
+ protected Instance toServiceInstance(Registration registration) {
+ Instance instance = new Instance();
+ instance.setServiceName(registration.getServiceName());
+ instance.setIp(registration.getIp());
+ instance.setPort(registration.getPort());
+ instance.setMetadata(registration.getMetadata());
+ return instance;
+ }
+
+ @Override
+ protected Registration toRegistration(final Instance serviceInstance) {
+ return new Registration() {
+
+ @Override
+ public String getServiceName() {
+ return serviceInstance.getServiceName();
+ }
+
+ @Override
+ public String getIp() {
+ return serviceInstance.getIp();
+ }
+
+ @Override
+ public int getPort() {
+ return serviceInstance.getPort();
+ }
+
+ @Override
+ public Map<String, String> getMetadata() {
+ return serviceInstance.getMetadata();
+ }
+ };
+ }
+
+ @Override
+ protected void register(final String serviceName, final Instance serviceInstance, URL url) {
+ execute(new NamingServiceCallback() {
+ @Override
+ public void callback(NamingService namingService) throws NacosException {
+ namingService.registerInstance(serviceName, serviceInstance);
+ }
+ });
+ }
+
+ @Override
+ protected void deregister(final String serviceName, final Instance serviceInstance, URL url) {
+ execute(new NamingServiceCallback() {
+ @Override
+ public void callback(NamingService namingService) throws NacosException {
+ namingService.deregisterInstance(serviceName, serviceInstance.getIp(), serviceInstance.getPort());
+ }
+ });
+ }
+
+ @Override
+ protected Collection<Instance> findServiceInstances(final String serviceName) {
+ final Collection<Instance> instances = new LinkedList<Instance>();
+ execute(new NamingServiceCallback() {
+ @Override
+ public void callback(NamingService namingService) throws NacosException {
+ instances.addAll(namingService.getAllInstances(serviceName));
+ }
+ });
+ return instances;
+ }
+
+ @Override
+ protected boolean filterHealthyRegistration(Instance serviceInstance) {
+ return serviceInstance.isEnabled();
+ }
+
+ @Override
+ protected Set<String> findAllServiceNames() {
+ final Set<String> serviceNames = new LinkedHashSet<String>();
+
+ execute(new NamingServiceCallback() {
+ @Override
+ public void callback(NamingService namingService) throws NacosException {
+
+ int pageIndex = 1;
+ ListView<String> listView = namingService.getServicesOfServer(pageIndex, PAGINATION_SIZE);
+ // First page data
+ List<String> firstPageData = listView.getData();
+ // Append first page into list
+ serviceNames.addAll(firstPageData);
+ // the total count
+ int count = listView.getCount();
+ // the number of pages
+ int pageNumbers = count / PAGINATION_SIZE;
+ int remainder = count % PAGINATION_SIZE;
+ // remain
+ if (remainder > 0) {
+ pageNumbers += 1;
+ }
+ // If more than 1 page
+ while (pageIndex < pageNumbers) {
+ listView = namingService.getServicesOfServer(++pageIndex, PAGINATION_SIZE);
+ serviceNames.addAll(listView.getData());
+ }
+
+ }
+ });
+
+ return serviceNames;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return "UP".equals(namingService.getServerStatus());
+ }
+
+ private void execute(NamingServiceCallback callback) {
+ try {
+ callback.callback(namingService);
+ } catch (NacosException e) {
+ if (logger.isErrorEnabled()) {
+ logger.error(e.getErrMsg(), e);
+ }
+ }
+ }
+
+ /**
+ * {@link NamingService} Callback
+ */
+ interface NamingServiceCallback {
+
+ /**
+ * Callback
+ *
+ * @param namingService {@link NamingService}
+ * @throws NacosException
+ */
+ void callback(NamingService namingService) throws NacosException;
+
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactory.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactory.java
new file mode 100644
index 0000000..56de760
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactory.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.registry.nacos;
+
+import com.alibaba.dubbo.common.URL;
+import com.alibaba.dubbo.registry.Registry;
+import com.alibaba.dubbo.registry.RegistryFactory;
+import com.alibaba.dubbo.registry.support.AbstractRegistryFactory;
+import com.alibaba.nacos.api.NacosFactory;
+import com.alibaba.nacos.api.exception.NacosException;
+import com.alibaba.nacos.api.naming.NamingService;
+import com.alibaba.nacos.client.naming.utils.StringUtils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Properties;
+
+import static com.alibaba.dubbo.common.Constants.BACKUP_KEY;
+import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY;
+import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
+import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT;
+import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
+import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
+import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
+import static com.alibaba.nacos.client.naming.utils.UtilAndComs.NACOS_NAMING_LOG_NAME;
+
+/**
+ * Nacos {@link RegistryFactory}
+ *
+ * @since 2.6.6
+ */
+public class NacosRegistryFactory extends AbstractRegistryFactory {
+
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ protected Registry createRegistry(URL url) {
+ return new NacosRegistry(url, buildNamingService(url));
+ }
+
+ private NamingService buildNamingService(URL url) {
+ Properties nacosProperties = buildNacosProperties(url);
+ NamingService namingService = null;
+ try {
+ namingService = NacosFactory.createNamingService(nacosProperties);
+ } catch (NacosException e) {
+ if (logger.isErrorEnabled()) {
+ logger.error(e.getErrMsg(), e);
+ }
+ throw new IllegalStateException(e);
+ }
+ return namingService;
+ }
+
+ private Properties buildNacosProperties(URL url) {
+ Properties properties = new Properties();
+ setServerAddr(url, properties);
+ setProperties(url, properties);
+ return properties;
+ }
+
+ private void setServerAddr(URL url, Properties properties) {
+ StringBuilder serverAddrBuilder =
+ new StringBuilder(url.getHost()) // Host
+ .append(":")
+ .append(url.getPort()); // Port
+
+ // Append backup parameter as other servers
+ String backup = url.getParameter(BACKUP_KEY);
+ if (backup != null) {
+ serverAddrBuilder.append(",").append(backup);
+ }
+
+ String serverAddr = serverAddrBuilder.toString();
+ properties.put(SERVER_ADDR, serverAddr);
+ }
+
+ private void setProperties(URL url, Properties properties) {
+ putPropertyIfAbsent(url, properties, NAMESPACE);
+ putPropertyIfAbsent(url, properties, NACOS_NAMING_LOG_NAME);
+ putPropertyIfAbsent(url, properties, ENDPOINT);
+ putPropertyIfAbsent(url, properties, NAMESPACE);
+ putPropertyIfAbsent(url, properties, ACCESS_KEY);
+ putPropertyIfAbsent(url, properties, SECRET_KEY);
+ putPropertyIfAbsent(url, properties, CLUSTER_NAME);
+ }
+
+ private void putPropertyIfAbsent(URL url, Properties properties, String propertyName) {
+ String propertyValue = url.getParameter(propertyName);
+ if (StringUtils.isNotEmpty(propertyValue)) {
+ properties.setProperty(propertyName, propertyValue);
+ }
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory b/dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory
new file mode 100644
index 0000000..370cd4a
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory
@@ -0,0 +1 @@
+nacos=com.alibaba.dubbo.registry.nacos.NacosRegistryFactory
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java
new file mode 100644
index 0000000..c61dcb5
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * {@link DemoService} consumer demo
+ */
+@EnableDubbo
+@PropertySource(value = "classpath:/consumer-config.properties")
+public class DemoServiceConsumerBootstrap {
+
+ @Reference(version = "${demo.service.version}")
+ private DemoService demoService;
+
+ @Reference(version = "${demo.service.version}", protocol = "rest")
+ private DemoService restDemoService;
+
+ @PostConstruct
+ public void init() throws InterruptedException {
+ for (int j = 0; j < 10; j++) {
+ System.out.println(demoService.sayName("小马哥(mercyblitz)"));
+ System.out.println(restDemoService.sayName("小马哥(mercyblitz)"));
+ }
+ Thread.sleep(TimeUnit.SECONDS.toMillis(5));
+ }
+
+ public static void main(String[] args) throws IOException {
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
+ context.register(DemoServiceConsumerBootstrap.class);
+ context.refresh();
+ System.in.read();
+ context.close();
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java
new file mode 100644
index 0000000..65b7bef
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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)"));
+ }
+ System.in.read();
+ context.close();
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderBootstrap.java
similarity index 51%
copy from dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java
copy to dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderBootstrap.java
index a73dbf2..f9cd797 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderBootstrap.java
@@ -14,47 +14,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.alibaba.dubbo.config.spring.context.annotation;
+package com.alibaba.dubbo.demo.provider;
-import com.alibaba.dubbo.config.ApplicationConfig;
+import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
+import com.alibaba.dubbo.demo.service.DemoService;
-import org.junit.Assert;
-import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.PropertySource;
+import java.io.IOException;
+
/**
- * {@link DubboConfigBindingsRegistrar} Test
- *
- * @since DubboConfigBindingsRegistrar
+ * {@link DemoService} provider demo
*/
-public class DubboConfigBindingsRegistrarTest {
-
- @Test
- public void test() {
+@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(TestConfig.class);
-
+ context.register(DemoServiceProviderBootstrap.class);
context.refresh();
-
- ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class);
-
- Assert.assertEquals("dubbo-demo-application", applicationConfig.getName());
-
- Assert.assertEquals(2, context.getBeansOfType(ApplicationConfig.class).size());
-
+ System.out.println("DemoService provider is starting...");
+ System.in.read();
}
-
-
- @EnableDubboConfigBindings({
- @EnableDubboConfigBinding(prefix = "${application.prefix}", type = ApplicationConfig.class),
- @EnableDubboConfigBinding(prefix = "dubbo.applications.applicationBean", type = ApplicationConfig.class)
- })
- @PropertySource("META-INF/config.properties")
- private static class TestConfig {
-
- }
-
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java
similarity index 54%
copy from dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
copy to dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java
index 1feb2bd..964adbc 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java
@@ -14,9 +14,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.alibaba.dubbo.demo.provider;
-package com.alibaba.dubbo.config.spring.api;
+import com.alibaba.dubbo.demo.service.DemoService;
-public interface HelloService {
- String sayHello(String name);
+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();
+ }
}
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DefaultService.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DefaultService.java
new file mode 100644
index 0000000..0ff9ada
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DefaultService.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 , protocol: %s , port : %d] %s(\"%s\") : Hello,%s",
+ serviceName,
+ rpcContext.getUrl().getProtocol(),
+ rpcContext.getLocalPort(),
+ rpcContext.getMethodName(),
+ name,
+ name);
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DemoService.java
similarity index 74%
copy from dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
copy to dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DemoService.java
index 1feb2bd..381540e 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DemoService.java
@@ -14,9 +14,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.alibaba.dubbo.demo.service;
-package com.alibaba.dubbo.config.spring.api;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.QueryParam;
-public interface HelloService {
- String sayHello(String name);
-}
+/**
+ * DemoService
+ *
+ * @since 2.6.5
+ */
+@Path("/demo-service")
+public interface DemoService {
+
+ @GET
+ String sayName(@QueryParam("name") String name);
+
+}
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactoryTest.java
similarity index 84%
copy from dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
copy to dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactoryTest.java
index 1feb2bd..8f7a152 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactoryTest.java
@@ -14,9 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.alibaba.dubbo.registry.nacos;
-package com.alibaba.dubbo.config.spring.api;
-
-public interface HelloService {
- String sayHello(String name);
+/**
+ * {@link NacosRegistryFactory} Test
+ *
+ * @since 2.6.5
+ */
+public class NacosRegistryFactoryTest {
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryTest.java
similarity index 68%
copy from dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
copy to dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryTest.java
index 1feb2bd..3ff055b 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryTest.java
@@ -14,9 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.alibaba.dubbo.registry.nacos;
-package com.alibaba.dubbo.config.spring.api;
+/**
+ * {@link NacosRegistry} Test
+ *
+ * @since 2.6.5
+ */
+public class NacosRegistryTest {
+
+ // Test case Dubbo OPS :
+ // URL : admin://30.5.124.12?category=providers,consumers,routers,configurators&check=false&classifier=*&enabled=*&group=*&interface=*&version=*
+ public void testDoSubscribeForDubboOps() {
+
+ }
-public interface HelloService {
- String sayHello(String name);
}
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-consumer-context.xml b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-consumer-context.xml
new file mode 100644
index 0000000..0d47053
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-consumer-context.xml
@@ -0,0 +1,16 @@
+<?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>
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-provider-context.xml b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-provider-context.xml
new file mode 100644
index 0000000..acf08a5
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-provider-context.xml
@@ -0,0 +1,21 @@
+<?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>
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/resources/consumer-config.properties b/dubbo-registry/dubbo-registry-nacos/src/test/resources/consumer-config.properties
new file mode 100644
index 0000000..d32e6e8
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/resources/consumer-config.properties
@@ -0,0 +1,6 @@
+## 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
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/resources/provider-config.properties b/dubbo-registry/dubbo-registry-nacos/src/test/resources/provider-config.properties
new file mode 100644
index 0000000..e2dd335
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/resources/provider-config.properties
@@ -0,0 +1,14 @@
+## Dubbo Application info
+dubbo.application.name=dubbo-provider-demo
+## Nacos registry address
+dubbo.registry.protocol=nacos
+dubbo.registry.address=127.0.0.1:8848
+## Exports multiple protocols
+### Dubbo Protocol using random port
+dubbo.protocols.dubbo.port=-1
+### REST protocol
+dubbo.protocols.rest.port=9090
+dubbo.protocols.rest.server=netty
+# Provider @Service info
+demo.service.version=1.0.0
+demo.service.name=demoService
\ No newline at end of file
diff --git a/dubbo-registry/pom.xml b/dubbo-registry/pom.xml
index b268a88..fe3a7f8 100644
--- a/dubbo-registry/pom.xml
+++ b/dubbo-registry/pom.xml
@@ -34,5 +34,6 @@
<module>dubbo-registry-multicast</module>
<module>dubbo-registry-zookeeper</module>
<module>dubbo-registry-redis</module>
+ <module>dubbo-registry-nacos</module>
</modules>
</project>
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/com/alibaba/dubbo/rpc/protocol/rest/RestProtocol.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/com/alibaba/dubbo/rpc/protocol/rest/RestProtocol.java
index 78b5deb..be4225c 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/com/alibaba/dubbo/rpc/protocol/rest/RestProtocol.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/com/alibaba/dubbo/rpc/protocol/rest/RestProtocol.java
@@ -25,6 +25,7 @@ import com.alibaba.dubbo.remoting.http.servlet.ServletManager;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.StaticContext;
import com.alibaba.dubbo.rpc.protocol.AbstractProxyProtocol;
+
import org.apache.http.HeaderElement;
import org.apache.http.HeaderElementIterator;
import org.apache.http.HttpResponse;
@@ -231,8 +232,13 @@ public class RestProtocol extends AbstractProxyProtocol {
}
protected String getContextPath(URL url) {
- int pos = url.getPath().lastIndexOf("/");
- return pos > 0 ? url.getPath().substring(0, pos) : "";
+ String path = url.getPath();
+ if (path != null) {
+ int pos = url.getPath().lastIndexOf("/");
+ return pos > 0 ? url.getPath().substring(0, pos) : "";
+ } else {
+ return "";
+ }
}
protected class ConnectionMonitor extends Thread {