You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2019/06/17 03:13:05 UTC
[dubbo] branch cloud-native updated: Introduce new Service
Discovery model (#4223)
This is an automated email from the ASF dual-hosted git repository.
liujun pushed a commit to branch cloud-native
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/cloud-native by this push:
new 5fb8dc0 Introduce new Service Discovery model (#4223)
5fb8dc0 is described below
commit 5fb8dc07a85faf7c31bd8d2cf84c2d598784d1e9
Author: Mercy Ma <me...@gmail.com>
AuthorDate: Mon Jun 17 11:12:47 2019 +0800
Introduce new Service Discovery model (#4223)
---
dubbo-all/pom.xml | 34 +
dubbo-bootstrap/pom.xml | 94 +
.../apache/dubbo/bootstrap/AbstractSettings.java | 29 +-
.../dubbo/bootstrap/ApplicationSettings.java | 127 ++
.../org/apache/dubbo/bootstrap/DubboBootstrap.java | 644 ++++++
.../apache/dubbo/bootstrap/ProtocolSettings.java | 215 ++
.../apache/dubbo/bootstrap/ReferenceSettings.java | 334 +++
.../apache/dubbo/bootstrap/RegistrySettings.java | 164 ++
.../apache/dubbo/bootstrap/ServiceSettings.java | 384 ++++
.../java/org/apache/dubbo/bootstrap/Settings.java | 31 +-
.../apache/dubbo/bootstrap/DubboBootstrapTest.java | 96 +
.../bootstrap/DubboServiceConsumerBootstrap.java | 58 +
.../bootstrap/DubboServiceProviderBootstrap.java | 52 +
.../org/apache/dubbo/bootstrap/EchoService.java | 24 +-
.../apache/dubbo/bootstrap/EchoServiceImpl.java | 31 +-
.../src/test/resources/log4j.properties | 7 +
.../cluster/router/condition/ConditionRouter.java | 10 +-
.../dubbo/rpc/cluster/support/ClusterUtils.java | 2 +-
.../rpc/cluster/support/ClusterUtilsTest.java | 2 +-
.../src/main/java/org/apache/dubbo/common/URL.java | 58 +-
.../dubbo/common/constants/RegistryConstants.java | 34 +
.../dubbo/common/function/ThrowableConsumer.java | 66 +
.../dubbo/common/function/ThrowableFunction.java | 71 +
.../org/apache/dubbo/common/utils/DefaultPage.java | 82 +
.../org/apache/dubbo/common/utils/NetUtils.java | 2 +-
.../java/org/apache/dubbo/common/utils/Page.java | 87 +
.../apache/dubbo/common/utils/ReflectUtils.java | 2307 ++++++++++----------
.../org/apache/dubbo/common/utils/UrlUtils.java | 10 +-
.../apache/dubbo/common/utils/DefaultPageTest.java | 30 +-
.../org/apache/dubbo/filter/LegacyInvocation.java | 4 +-
dubbo-config/dubbo-config-api/pom.xml | 48 +-
.../dubbo/config/AbstractInterfaceConfig.java | 20 +-
.../org/apache/dubbo/config/DubboShutdownHook.java | 8 +-
.../org/apache/dubbo/config/ProtocolConfig.java | 4 +-
.../org/apache/dubbo/config/ReferenceConfig.java | 1355 ++++++------
.../org/apache/dubbo/config/RegistryConfig.java | 4 +-
.../org/apache/dubbo/config/ServiceConfig.java | 2135 +++++++++---------
.../dubbo/config/builders/AbstractBuilder.java | 13 +-
.../dubbo/config/builders/ProtocolBuilder.java | 8 +-
.../dubbo/config/builders/ReferenceBuilder.java | 4 +
.../dubbo/config/builders/RegistryBuilder.java | 8 +-
.../dubbo/config/builders/ServiceBuilder.java | 10 +-
.../config/event/DubboServiceDestroyedEvent.java} | 27 +-
.../event/ReferenceConfigDestroyedEvent.java} | 30 +-
.../event/ReferenceConfigInitializedEvent.java} | 45 +-
.../config/event/ServiceConfigExportedEvent.java} | 29 +-
.../event/ServiceConfigUnexportedEvent.java} | 29 +-
.../event/listener/LoggingEventListener.java | 51 +
.../event/listener/ServiceNameMappingListener.java | 55 +
.../ConfigurableMetadataServiceExporter.java | 131 ++
.../metadata/ServiceInstancePortCustomizer.java | 53 +
.../services/org.apache.dubbo.event.EventListener | 2 +
...dubbo.registry.client.ServiceInstanceCustomizer | 1 +
.../dubbo/config/DubboConsumerBootstrap.java | 63 +
.../dubbo/config/DubboProviderBootstrap.java | 84 +
.../apache/dubbo/config/ReferenceConfigTest.java | 48 +-
.../apache/dubbo/config/RegistryConfigTest.java | 2 +-
.../org/apache/dubbo/config/ServiceConfigTest.java | 47 +-
.../org/apache/dubbo/config/api/DemoService.java | 3 +
.../listener/ServiceNameMappingListenerTest.java | 63 +
.../ConfigurableMetadataServiceExporterTest.java | 88 +
.../config/provider/impl/DemoServiceImpl.java | 17 +-
.../config/spring/SimpleRegistryExporter.java | 4 +-
.../dubbo/configcenter/DynamicConfiguration.java | 72 +-
.../support/nop/NopDynamicConfiguration.java | 21 +-
.../support/nop/NopDynamicConfigurationTest.java | 70 +
.../zookeeper/ZookeeperDynamicConfiguration.java | 73 +-
.../ZookeeperDynamicConfigurationTest.java | 39 +
dubbo-dependencies-bom/pom.xml | 13 +-
.../dubbo-dependencies-zookeeper/pom.xml | 2 +-
.../pom.xml | 37 +-
.../dubbo/event/AbstractEventDispatcher.java | 155 ++
.../apache/dubbo/event/DirectEventDispatcher.java | 27 +-
.../main/java/org/apache/dubbo/event/Event.java | 54 +-
.../org/apache/dubbo/event/EventDispatcher.java | 66 +
.../java/org/apache/dubbo/event/EventListener.java | 124 ++
.../java/org/apache/dubbo/event/GenericEvent.java | 29 +-
.../apache/dubbo/event/GenericEventListener.java | 130 ++
.../java/org/apache/dubbo/event/Listenable.java | 131 ++
.../dubbo/event/ParallelEventDispatcher.java | 27 +-
.../org.apache.dubbo.event.EventDispatcher | 2 +
.../apache/dubbo/event/AbstractEventListener.java | 29 +-
.../dubbo/event/DirectEventDispatcherTest.java | 153 ++
.../java/org/apache/dubbo/event/EchoEvent.java | 26 +-
.../org/apache/dubbo/event/EchoEventListener.java | 25 +-
.../org/apache/dubbo/event/EchoEventListener2.java | 61 +
.../apache/dubbo/event/EventDispatcherTest.java | 44 +-
.../org/apache/dubbo/event/EventListenerTest.java | 39 +-
.../dubbo/event/GenericEventListenerTest.java | 77 +
.../org/apache/dubbo/event/GenericEventTest.java | 28 +-
.../dubbo/event/ParallelEventDispatcherTest.java | 59 +
.../services/org.apache.dubbo.event.EventListener | 1 +
.../identifier/MetadataIdentifierTest.java | 1 -
.../metadata/store/redis/RedisMetadataReport.java | 2 +-
.../pom.xml | 40 +-
.../DynamicConfigurationServiceNameMapping.java | 103 +
.../metadata/InMemoryLocalMetadataService.java | 192 ++
.../dubbo/metadata/LocalMetadataService.java | 88 +
.../org/apache/dubbo/metadata/MetadataService.java | 151 ++
.../dubbo/metadata/MetadataServiceExporter.java | 39 +-
.../apache/dubbo/metadata/ServiceNameMapping.java | 64 +
.../org.apache.dubbo.metadata.LocalMetadataService | 1 +
.../org.apache.dubbo.metadata.ServiceNameMapping | 1 +
...DynamicConfigurationServiceNameMappingTest.java | 114 +
.../metadata/InMemoryLocalMetadataServiceTest.java | 140 ++
.../dubbo/metadata/LocalMetadataServiceTest.java | 27 +-
.../dubbo/monitor/support/MonitorFilter.java | 2 +-
.../dubbo/monitor/dubbo/DubboMonitorFactory.java | 2 +-
dubbo-registry/dubbo-registry-api/pom.xml | 15 +-
.../registry/client/DefaultServiceInstance.java | 142 ++
.../client/EventPublishingServiceDiscovery.java | 293 +++
.../EventPublishingServiceDiscoveryFactory.java | 47 +
.../dubbo/registry/client/ServiceDiscovery.java | 201 ++
.../registry/client/ServiceDiscoveryFactory.java | 49 +
.../dubbo/registry/client/ServiceInstance.java | 94 +
.../registry/client/ServiceInstanceCustomizer.java | 49 +-
.../client/ServiceInstanceMetadataCustomizer.java | 73 +
.../client/event/ServiceDiscoveryStartedEvent.java | 49 +
.../event/ServiceDiscoveryStartingEvent.java | 48 +
.../client/event/ServiceDiscoveryStoppedEvent.java | 48 +
.../event/ServiceDiscoveryStoppingEvent.java | 48 +
.../client/event/ServiceInstanceEvent.java | 48 +-
.../event/ServiceInstancePreRegisteredEvent.java | 27 +-
.../event/ServiceInstancePreUnregisteredEvent.java | 27 +-
.../event/ServiceInstanceRegisteredEvent.java | 27 +-
.../event/ServiceInstanceUnregisteredEvent.java | 28 +-
.../client/event/ServiceInstancesChangedEvent.java | 64 +
.../CustomizableServiceInstanceListener.java | 54 +
.../event/listener/LoggingEventListener.java | 85 +
.../listener/ServiceInstancesChangedListener.java | 33 +-
.../DefaultMetadataServiceProxyFactory.java | 31 +-
...ExportedServicesRevisionMetadataCustomizer.java | 69 +
.../client/metadata/MetadataServiceProxy.java | 114 +
.../metadata/MetadataServiceProxyFactory.java | 51 +
.../client/metadata/MetadataServiceURLBuilder.java | 81 +
...MetadataServiceURLParamsMetadataCustomizer.java | 60 +
.../metadata/ServiceInstanceMetadataUtils.java | 172 ++
.../apache/dubbo/registry/client/package-info.java | 24 +-
.../selector/RandomServiceInstanceSelector.java | 48 +-
.../client/selector/ServiceInstanceSelector.java | 43 +
.../registry/integration/RegistryDirectory.java | 10 +-
.../registry/integration/RegistryProtocol.java | 36 +-
.../registry/support/AbstractRegistryFactory.java | 9 +-
.../registry/support/ServiceOrientedRegistry.java | 472 ++++
...e.dubbo.registry.client.ServiceDiscoveryFactory | 1 +
...try.client.metadata.MetadataServiceProxyFactory | 1 +
...egistry.client.selector.ServiceInstanceSelector | 1 +
.../services/org.apache.dubbo.event.EventListener | 2 +
...dubbo.registry.client.ServiceInstanceCustomizer | 2 +
.../client/DefaultServiceInstanceTest.java | 60 +
.../EventPublishingServiceDiscoveryTest.java | 164 ++
.../registry/client/InMemoryServiceDiscovery.java | 110 +
.../client/InMemoryServiceDiscoveryFactory.java | 28 +-
.../client/ServiceDiscoveryFactoryTest.java | 55 +
.../registry/client/ServiceDiscoveryTest.java | 264 +++
.../metadata/ServiceInstanceMetadataUtilsTest.java | 74 +
.../support/ServiceOrientedRegistryTest.java | 173 ++
...e.dubbo.registry.client.ServiceDiscoveryFactory | 1 +
.../dubbo/registry/dubbo/DubboRegistryFactory.java | 10 +-
.../registry/dubbo/RegistryDirectoryTest.java | 14 +-
.../registry/dubbo/SimpleRegistryExporter.java | 4 +-
.../apache/dubbo/registry/nacos/NacosRegistry.java | 2 +-
.../dubbo/registry/nacos/NacosRegistryFactory.java | 70 +-
.../registry/nacos/NacosServiceDiscovery.java | 136 ++
.../nacos/NacosServiceDiscoveryFactory.java | 34 +-
.../NacosNamingServiceUtils.java} | 88 +-
...e.dubbo.registry.client.ServiceDiscoveryFactory | 1 +
dubbo-registry/dubbo-registry-zookeeper/pom.xml | 4 +
.../registry/zookeeper/ZookeeperInstance.java | 77 +
.../zookeeper/ZookeeperServiceDiscovery.java | 159 ++
.../ZookeeperServiceDiscoveryChangeWatcher.java | 68 +
.../ZookeeperServiceDiscoveryFactory.java | 36 +-
.../zookeeper/util/CuratorFrameworkParams.java | 102 +
.../zookeeper/util/CuratorFrameworkUtils.java | 122 ++
...e.dubbo.registry.client.ServiceDiscoveryFactory | 1 +
...e.dubbo.registry.client.ServiceDiscoveryFactory | 1 +
.../registry/zookeeper/ZookeeperRegistryTest.java | 2 +-
.../zookeeper/ZookeeperServiceDiscoveryTest.java | 206 ++
.../support/header/HeaderExchangeClient.java | 4 +-
.../exchange/support/header/HeartBeatTaskTest.java | 1 +
.../remoting/transport/netty4/NettyClient.java | 4 +-
.../transport/netty4/ClientReconnectTest.java | 1 +
.../org/apache/dubbo/rpc/filter/ContextFilter.java | 2 +-
.../org/apache/dubbo/rpc/support/MockInvoker.java | 6 +-
.../apache/dubbo/rpc/filter/GenericFilterTest.java | 6 +-
.../dubbo/rpc/filter/GenericImplFilterTest.java | 5 +-
.../rpc/protocol/dubbo/CallbackServiceCodec.java | 6 +-
.../protocol/dubbo/DecodeableRpcInvocation.java | 2 +-
.../dubbo/rpc/protocol/dubbo/DubboCodec.java | 2 +-
.../dubbo/rpc/protocol/dubbo/DubboProtocol.java | 20 +-
.../dubbo/ReferenceCountExchangeClientTest.java | 2 +-
.../dubbo/rpc/protocol/http/HttpProtocol.java | 2 +-
dubbo-rpc/dubbo-rpc-xml/README.md | 2 +-
.../xml/rpc/protocol/xmlrpc/XmlRpcProtocol.java | 18 +-
pom.xml | 5 +-
195 files changed, 13322 insertions(+), 3767 deletions(-)
diff --git a/dubbo-all/pom.xml b/dubbo-all/pom.xml
index d8c8949..eaf1772 100644
--- a/dubbo-all/pom.xml
+++ b/dubbo-all/pom.xml
@@ -507,6 +507,23 @@
<optional>true</optional>
</dependency>
+ <!-- 2.7.3 new modules -->
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-event</artifactId>
+ <version>${project.version}</version>
+ <scope>compile</scope>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-metadata</artifactId>
+ <version>${project.version}</version>
+ <scope>compile</scope>
+ <optional>true</optional>
+ </dependency>
+
<!-- Transitive dependencies -->
<dependency>
<groupId>org.springframework</groupId>
@@ -639,6 +656,10 @@
<include>org.apache.dubbo:dubbo-metadata-report-nacos</include>
<include>org.apache.dubbo:dubbo-serialization-native-hession</include>
<include>org.apache.dubbo:dubbo-rpc-native-thrift</include>
+
+ <!-- 2.7.3 new modules -->
+ <include>org.apache.dubbo:dubbo-event</include>
+ <include>org.apache.dubbo:dubbo-metadata</include>
</includes>
</artifactSet>
<transformers>
@@ -764,6 +785,19 @@
<resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.store.MetadataReportFactory
</resource>
</transformer>
+ <!-- @since 2.7.3 -->
+ <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+ <resource>META-INF/dubbo/internal/org.apache.dubbo.event.EventDispatcher
+ </resource>
+ </transformer>
+ <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+ <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataServiceExporter
+ </resource>
+ </transformer>
+ <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+ <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.LocalMetadataService
+ </resource>
+ </transformer>
</transformers>
<filters>
<filter>
diff --git a/dubbo-bootstrap/pom.xml b/dubbo-bootstrap/pom.xml
new file mode 100644
index 0000000..ef3cad3
--- /dev/null
+++ b/dubbo-bootstrap/pom.xml
@@ -0,0 +1,94 @@
+<?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">
+ <parent>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-parent</artifactId>
+ <version>${revision}</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dubbo-bootstrap</artifactId>
+ <packaging>jar</packaging>
+
+ <name>dubbo-bootstrap</name>
+ <description>The bootstrap module of Dubbo project</description>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-config-api</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+
+ <!-- Test dependencies -->
+
+ <!-- Zookeeper dependencies for testing -->
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-registry-zookeeper</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-configcenter-zookeeper</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- Nacos dependencies for testing -->
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-registry-nacos</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-configcenter-nacos</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>com.alibaba.nacos</groupId>
+ <artifactId>nacos-client</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-rpc-dubbo</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-remoting-netty4</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-serialization-hessian2</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.curator</groupId>
+ <artifactId>curator-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/AbstractSettings.java
similarity index 67%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/AbstractSettings.java
index c5bc722..6bb9c97 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/AbstractSettings.java
@@ -14,24 +14,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.api;
-
-import java.util.List;
-
+package org.apache.dubbo.bootstrap;
/**
- * DemoService
+ * Abstract {@link Settings}
+ *
+ * @since 2.7.3
*/
-public interface DemoService {
-
- String sayName(String name);
-
- Box getBox();
-
- void throwDemoException() throws DemoException;
+public class AbstractSettings implements Settings {
- List<User> getUsers(List<User> users);
+ private final DubboBootstrap dubboBootstrap;
- int echo(int i);
+ public AbstractSettings(DubboBootstrap dubboBootstrap) {
+ this.dubboBootstrap = dubboBootstrap;
+ }
-}
\ No newline at end of file
+ @Override
+ public DubboBootstrap next() {
+ return dubboBootstrap;
+ }
+}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ApplicationSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ApplicationSettings.java
new file mode 100644
index 0000000..a9bc9c9
--- /dev/null
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ApplicationSettings.java
@@ -0,0 +1,127 @@
+/*
+ * 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 org.apache.dubbo.bootstrap;
+
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.MonitorConfig;
+import org.apache.dubbo.config.builders.ApplicationBuilder;
+
+import java.util.Map;
+
+/**
+ * {@link ApplicationConfig Application} settings
+ *
+ * @since 2.7.3
+ */
+public class ApplicationSettings extends AbstractSettings {
+
+ private final ApplicationBuilder builder;
+
+ public ApplicationSettings(ApplicationBuilder builder, DubboBootstrap dubboBootstrap) {
+ super(dubboBootstrap);
+ this.builder = builder;
+ }
+
+ public ApplicationSettings version(String version) {
+ builder.version(version);
+ return this;
+ }
+
+ public ApplicationSettings owner(String owner) {
+ builder.owner(owner);
+ return this;
+ }
+
+ public ApplicationSettings organization(String organization) {
+ builder.organization(organization);
+ return this;
+ }
+
+ public ApplicationSettings architecture(String architecture) {
+ builder.architecture(architecture);
+ return this;
+ }
+
+ public ApplicationSettings environment(String environment) {
+ builder.environment(environment);
+ return this;
+ }
+
+ public ApplicationSettings compiler(String compiler) {
+ builder.compiler(compiler);
+ return this;
+ }
+
+ public ApplicationSettings logger(String logger) {
+ builder.logger(logger);
+ return this;
+ }
+
+ public ApplicationSettings monitor(MonitorConfig monitor) {
+ builder.monitor(monitor);
+ return this;
+ }
+
+ public ApplicationSettings monitor(String monitor) {
+ builder.monitor(monitor);
+ return this;
+ }
+
+ public ApplicationSettings isDefault(Boolean isDefault) {
+ builder.isDefault(isDefault);
+ return this;
+ }
+
+ public ApplicationSettings dumpDirectory(String dumpDirectory) {
+ builder.dumpDirectory(dumpDirectory);
+ return this;
+ }
+
+ public ApplicationSettings qosEnable(Boolean qosEnable) {
+ builder.qosEnable(qosEnable);
+ return this;
+ }
+
+ public ApplicationSettings qosPort(Integer qosPort) {
+ builder.qosPort(qosPort);
+ return this;
+ }
+
+ public ApplicationSettings qosAcceptForeignIp(Boolean qosAcceptForeignIp) {
+ builder.qosAcceptForeignIp(qosAcceptForeignIp);
+ return this;
+ }
+
+ public ApplicationSettings shutwait(String shutwait) {
+ builder.shutwait(shutwait);
+ return this;
+ }
+
+ public ApplicationSettings appendParameter(String key, String value) {
+ builder.appendParameter(key, value);
+ return this;
+ }
+
+ public ApplicationSettings appendParameters(Map<String, String> appendParameters) {
+ builder.appendParameters(appendParameters);
+ return this;
+ }
+
+ ApplicationConfig build() {
+ return builder.build();
+ }
+}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java
new file mode 100644
index 0000000..c6c2606
--- /dev/null
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java
@@ -0,0 +1,644 @@
+/*
+ * 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 org.apache.dubbo.bootstrap;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.config.AbstractConfig;
+import org.apache.dubbo.config.AbstractInterfaceConfig;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.builders.AbstractBuilder;
+import org.apache.dubbo.config.builders.ApplicationBuilder;
+import org.apache.dubbo.config.builders.ProtocolBuilder;
+import org.apache.dubbo.config.builders.ReferenceBuilder;
+import org.apache.dubbo.config.builders.RegistryBuilder;
+import org.apache.dubbo.config.builders.ServiceBuilder;
+import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.config.metadata.ConfigurableMetadataServiceExporter;
+import org.apache.dubbo.event.EventDispatcher;
+import org.apache.dubbo.event.EventListener;
+import org.apache.dubbo.metadata.MetadataServiceExporter;
+import org.apache.dubbo.registry.client.DefaultServiceInstance;
+import org.apache.dubbo.registry.client.ServiceDiscovery;
+import org.apache.dubbo.registry.client.ServiceInstance;
+import org.apache.dubbo.registry.support.ServiceOrientedRegistry;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+import static java.util.Collections.emptyMap;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
+import static org.apache.dubbo.common.utils.StringUtils.isBlank;
+import static org.apache.dubbo.common.utils.StringUtils.split;
+import static org.apache.dubbo.common.utils.StringUtils.trim;
+import static org.apache.dubbo.registry.support.AbstractRegistryFactory.getRegistries;
+
+/**
+ * The bootstrap class of Dubbo
+ *
+ * @since 2.7.3
+ */
+public class DubboBootstrap {
+
+ public static final String DEFAULT_REGISTRY_ID = "REGISTRY#DEFAULT";
+
+ public static final String DEFAULT_PROTOCOL_ID = "PROTOCOL#DEFAULT";
+
+ public static final String DEFAULT_SERVICE_ID = "SERVICE#DEFAULT";
+
+ public static final String DEFAULT_REFERENCE_ID = "REFERENCE#DEFAULT";
+
+ private static final String NAME = DubboBootstrap.class.getSimpleName();
+
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ private final MetadataServiceExporter metadataServiceExporter = new ConfigurableMetadataServiceExporter();
+
+ private final AtomicBoolean awaited = new AtomicBoolean(false);
+
+ private final Lock lock = new ReentrantLock();
+
+ private final Condition condition = lock.newCondition();
+
+ private final ExecutorService executorService = newSingleThreadExecutor();
+
+ private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension();
+
+ /**
+ * Is provider or not
+ */
+ private boolean isProvider;
+
+ private boolean initialized = false;
+
+ private boolean started = false;
+
+ /**
+ * Only Provider Register
+ */
+ private boolean onlyRegisterProvider = false;
+
+ private ServiceInstance serviceInstance;
+
+ private ApplicationBuilder applicationBuilder;
+
+ private Map<String, RegistryBuilder> registryBuilders = new HashMap<>();
+
+ private Map<String, ProtocolBuilder> protocolBuilders = new HashMap<>();
+
+ private Map<String, ServiceBuilder<?>> serviceBuilders = new HashMap<>();
+
+ private Map<String, ReferenceBuilder<?>> referenceBuilders = new HashMap<>();
+
+ /**
+ * The global {@link ApplicationConfig}
+ */
+ private ApplicationConfig applicationConfig;
+
+ /**
+ * the global {@link RegistryConfig registries}
+ */
+ private Map<String, RegistryConfig> registryConfigs = emptyMap();
+
+ /**
+ * the global {@link RegistryConfig registries}
+ */
+ private Map<String, ProtocolConfig> protocolConfigs = emptyMap();
+
+ /**
+ * the global {@link ServiceConfig services}
+ */
+ private Map<String, ServiceConfig<?>> serviceConfigs = emptyMap();
+
+ /**
+ * the global {@link ReferenceConfig references}
+ */
+ private Map<String, ReferenceConfig<?>> referenceConfigs = new HashMap<>();
+
+ public ApplicationSettings application(String name) {
+ return new ApplicationSettings(initApplicationBuilder(name), this);
+ }
+
+ public RegistrySettings registry() {
+ return registry(DEFAULT_REGISTRY_ID);
+ }
+
+ public RegistrySettings registry(String id) {
+ return new RegistrySettings(initRegistryBuilder(id), this);
+ }
+
+ public ProtocolSettings protocol() {
+ return protocol(DEFAULT_PROTOCOL_ID);
+ }
+
+ public ProtocolSettings protocol(String id) {
+ return new ProtocolSettings(initProtocolBuilder(id), this);
+ }
+
+ public <S> ServiceSettings<S> service(String id) {
+ return new ServiceSettings(initServiceBuilder(id), this);
+ }
+
+ public <S> ReferenceSettings<S> reference(String id) {
+ return new ReferenceSettings<>(initReferenceBuilder(id), this);
+ }
+
+ /**
+ * Set only register provider or not
+ *
+ * @param onlyRegisterProvider if <code>true</code>, only register the provider and reduce the registries' load.
+ * @return {@link DubboBootstrap}
+ */
+ public DubboBootstrap onlyRegisterProvider(boolean onlyRegisterProvider) {
+ this.onlyRegisterProvider = onlyRegisterProvider;
+ return this;
+ }
+
+ public DubboBootstrap application(String name, Consumer<ApplicationBuilder> builder) {
+ initApplicationBuilder(name);
+ builder.accept(applicationBuilder);
+ return this;
+ }
+
+ public DubboBootstrap registry(String id, Consumer<RegistryBuilder> builder) {
+ builder.accept(initRegistryBuilder(id));
+ return this;
+ }
+
+ public DubboBootstrap protocol(String id, Consumer<ProtocolBuilder> builder) {
+ builder.accept(initProtocolBuilder(id));
+ return this;
+ }
+
+ public <S> DubboBootstrap service(String id, Consumer<ServiceBuilder<S>> builder) {
+ builder.accept(initServiceBuilder(id));
+ return this;
+ }
+
+ public <S> DubboBootstrap reference(String id, Consumer<ReferenceBuilder<S>> builder) {
+ builder.accept(initReferenceBuilder(id));
+ return this;
+ }
+
+ /**
+ * Initialize
+ */
+ public void init() {
+
+ if (isInitialized()) {
+ return;
+ }
+
+ initApplicationConfig();
+
+ initRegistryConfigs();
+
+ initProtocolConfigs();
+
+ initServiceConfigs();
+
+ initReferenceConfigs();
+
+ clearBuilders();
+
+ initialized = true;
+
+ if (logger.isInfoEnabled()) {
+ logger.info(NAME + " has been initialized!");
+ }
+ }
+
+ /**
+ * Get the {@link ServiceConfig} by specified id
+ *
+ * @param id The {@link ServiceConfig#getId() id} of {@link ServiceConfig}
+ * @param <S> the type of service interface
+ * @return <code>null</code> if not found
+ */
+ public <S> ServiceConfig<S> serviceConfig(String id) {
+ return (ServiceConfig<S>) serviceConfigs.get(id);
+ }
+
+ /**
+ * Get the {@link ReferenceConfig} by specified id
+ *
+ * @param id The {@link ReferenceConfig#getId() id} of {@link ReferenceConfig}
+ * @param <S> the type of service interface
+ * @return <code>null</code> if not found
+ */
+ public <S> ReferenceConfig<S> referenceConfig(String id) {
+ return (ReferenceConfig<S>) referenceConfigs.get(id);
+ }
+
+ private List<ServiceDiscovery> getServiceDiscoveries() {
+ return getRegistries()
+ .stream()
+ .filter(registry -> ServiceOrientedRegistry.class.isInstance(registry))
+ .map(registry -> ServiceOrientedRegistry.class.cast(registry))
+ .map(ServiceOrientedRegistry::getServiceDiscovery)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Start the bootstrap
+ */
+ public DubboBootstrap start() {
+
+ if (!isStarted()) {
+ if (!isInitialized()) {
+ init();
+ }
+
+ exportServices();
+
+ // Not only provider register and some services are exported
+ if (!onlyRegisterProvider && !serviceConfigs.isEmpty()) {
+ /**
+ * export {@link MetadataService}
+ */
+ List<URL> exportedURLs = exportMetadataService(applicationConfig, registryConfigs, protocolConfigs);
+
+ /**
+ * Register the local {@link ServiceInstance}
+ */
+ registerServiceInstance(exportedURLs);
+ }
+
+ started = true;
+
+ if (logger.isInfoEnabled()) {
+ logger.info(NAME + " is starting...");
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Block current thread to be await.
+ *
+ * @return {@link DubboBootstrap}
+ */
+ public DubboBootstrap await() {
+ // has been waited, return immediately
+ if (!awaited.get()) {
+ if (!executorService.isShutdown()) {
+ executorService.execute(() -> executeMutually(() -> {
+ while (!awaited.get()) {
+ if (logger.isInfoEnabled()) {
+ logger.info(NAME + " is awaiting...");
+ }
+ try {
+ condition.await();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }));
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Stop the bootstrap
+ */
+ public void stop() {
+
+ if (!isInitialized() || !isStarted()) {
+ return;
+ }
+
+ unregisterServiceInstance();
+
+ destroy();
+
+ clear();
+
+ release();
+
+ shutdown();
+ }
+
+ public boolean isInitialized() {
+ return initialized;
+ }
+
+ public boolean isStarted() {
+ return started;
+ }
+
+ private ApplicationBuilder initApplicationBuilder(String name) {
+ applicationBuilder = new ApplicationBuilder().name(name);
+ return applicationBuilder;
+ }
+
+ private RegistryBuilder createRegistryBuilder(String id) {
+ return new RegistryBuilder().id(id);
+ }
+
+ private ProtocolBuilder createProtocolBuilder(String id) {
+ return new ProtocolBuilder().id(id);
+ }
+
+ private ServiceBuilder createServiceBuilder(String id) {
+ return new ServiceBuilder().id(id);
+ }
+
+ private ReferenceBuilder createReferenceBuilder(String id) {
+ return new ReferenceBuilder().id(id);
+ }
+
+ private RegistryBuilder initRegistryBuilder(String id) {
+ return registryBuilders.computeIfAbsent(id, this::createRegistryBuilder);
+ }
+
+ private ProtocolBuilder initProtocolBuilder(String id) {
+ return protocolBuilders.computeIfAbsent(id, this::createProtocolBuilder);
+ }
+
+ private ServiceBuilder initServiceBuilder(String id) {
+ return serviceBuilders.computeIfAbsent(id, this::createServiceBuilder);
+ }
+
+ private ReferenceBuilder initReferenceBuilder(String id) {
+ return referenceBuilders.computeIfAbsent(id, this::createReferenceBuilder);
+ }
+
+ private void initApplicationConfig() {
+ this.applicationConfig = buildApplicationConfig();
+ }
+
+ private void initRegistryConfigs() {
+ this.registryConfigs = buildRegistryConfigs();
+ }
+
+ private void initProtocolConfigs() {
+ this.protocolConfigs = buildProtocolConfigs();
+ }
+
+ private void initReferenceConfigs() {
+ this.referenceConfigs = buildReferenceConfigs();
+ this.referenceConfigs.values().forEach(this::initReferenceConfig);
+ }
+
+ /**
+ * Add an instance of {@link EventListener}
+ *
+ * @param listener {@link EventListener}
+ * @return {@link DubboBootstrap}
+ */
+ public DubboBootstrap addEventListener(EventListener<?> listener) {
+ eventDispatcher.addEventListener(listener);
+ return this;
+ }
+
+ private void initServiceConfigs() {
+ this.serviceConfigs = buildServiceConfigs();
+ this.serviceConfigs.values().forEach(this::initServiceConfig);
+ }
+
+ private List<URL> exportMetadataService(ApplicationConfig applicationConfig,
+ Map<String, RegistryConfig> globalRegistryConfigs,
+ Map<String, ProtocolConfig> globalProtocolConfigs) {
+ ConfigurableMetadataServiceExporter exporter = new ConfigurableMetadataServiceExporter();
+ exporter.setApplicationConfig(applicationConfig);
+ exporter.setRegistries(globalRegistryConfigs.values());
+ exporter.setProtocols(globalProtocolConfigs.values());
+ return exporter.export();
+ }
+
+ private ApplicationConfig buildApplicationConfig() {
+ return applicationBuilder.build();
+ }
+
+ private Map<String, ProtocolConfig> buildProtocolConfigs() {
+ return buildConfigs(protocolBuilders);
+ }
+
+ private Map<String, RegistryConfig> buildRegistryConfigs() {
+ return buildConfigs(registryBuilders);
+ }
+
+ private Map<String, ServiceConfig<?>> buildServiceConfigs() {
+ return buildConfigs(serviceBuilders);
+ }
+
+ private Map<String, ReferenceConfig<?>> buildReferenceConfigs() {
+ return buildConfigs(referenceBuilders);
+ }
+
+ private void exportServices() {
+ serviceConfigs.values().forEach(this::exportServiceConfig);
+ }
+
+ private void initServiceConfig(ServiceConfig<?> serviceConfig) {
+ initConfig(serviceConfig);
+ initProtocols(serviceConfig);
+ }
+
+ private void initReferenceConfig(ReferenceConfig<?> referenceConfig) {
+ initConfig(referenceConfig);
+ }
+
+ private void initConfig(AbstractInterfaceConfig config) {
+ initApplication(config);
+ initRegistries(config);
+ }
+
+ private void initApplication(AbstractInterfaceConfig config) {
+ if (config.getApplication() == null) {
+ config.setApplication(applicationConfig);
+ }
+ }
+
+ private void initRegistries(AbstractInterfaceConfig config) {
+ List<RegistryConfig> registries = config.getRegistries();
+ if (CollectionUtils.isEmpty(registries)) { // If no registry present
+ registries = new LinkedList<>();
+ String registerIds = config.getRegistryIds();
+ if (!isBlank(registerIds)) {
+ for (String id : split(registerIds, ',')) {
+ RegistryConfig registryConfig = registryConfigs.get(trim(id));
+ registries.add(registryConfig);
+ }
+ }
+ if (registries.isEmpty()) { // If empty, add all global registries
+ registries.addAll(registryConfigs.values());
+ }
+
+ config.setRegistries(registries);
+ }
+ }
+
+ private void initProtocols(ServiceConfig<?> serviceConfig) {
+ List<ProtocolConfig> protocols = serviceConfig.getProtocols();
+ if (CollectionUtils.isEmpty(protocols)) { // If no protocols present
+ protocols = new LinkedList<>();
+ String protocolIds = serviceConfig.getProtocolIds();
+ if (!isBlank(protocolIds)) {
+ for (String id : split(protocolIds, ',')) {
+ ProtocolConfig protocol = protocolConfigs.get(trim(id));
+ protocols.add(protocol);
+ }
+ }
+ if (protocols.isEmpty()) { // If empty, add all global protocols
+ protocols.addAll(protocolConfigs.values());
+ }
+ serviceConfig.setProtocols(protocols);
+ }
+ }
+
+ private void exportServiceConfig(ServiceConfig<?> serviceConfig) {
+ serviceConfig.export();
+ }
+
+ private void registerServiceInstance(List<URL> exportedURLs) {
+
+ exportedURLs
+ .stream()
+ .findFirst()
+ .ifPresent(url -> {
+ String serviceName = url.getParameter(APPLICATION_KEY);
+ String host = url.getHost();
+ int port = url.getPort();
+
+ ServiceInstance serviceInstance = initServiceInstance(serviceName, host, port);
+
+ getServiceDiscoveries().forEach(serviceDiscovery -> serviceDiscovery.register(serviceInstance));
+
+ });
+ }
+
+ private void unregisterServiceInstance() {
+
+ if (serviceInstance != null) {
+ getServiceDiscoveries().forEach(serviceDiscovery -> {
+ serviceDiscovery.unregister(serviceInstance);
+ });
+ }
+
+ }
+
+ private ServiceInstance initServiceInstance(String serviceName, String host, int port) {
+ this.serviceInstance = new DefaultServiceInstance(serviceName, host, port);
+ return this.serviceInstance;
+ }
+
+ private void destroy() {
+
+ destroyProtocolConfigs();
+
+ destroyReferenceConfigs();
+
+ }
+
+ private void destroyProtocolConfigs() {
+ protocolConfigs.values().forEach(ProtocolConfig::destroy);
+ if (logger.isDebugEnabled()) {
+ logger.debug(NAME + "'s all ProtocolConfigs have been destroyed.");
+ }
+ }
+
+ private void destroyReferenceConfigs() {
+ referenceConfigs.values().forEach(ReferenceConfig::destroy);
+ if (logger.isDebugEnabled()) {
+ logger.debug(NAME + "'s all ReferenceConfigs have been destroyed.");
+ }
+ }
+
+ private void clear() {
+
+ clearBuilders();
+
+ clearConfigs();
+
+ ConfigManager.getInstance().clear();
+ }
+
+ private void clearConfigs() {
+ this.applicationConfig = null;
+ this.registryConfigs.clear();
+ this.protocolConfigs.clear();
+ this.serviceConfigs.clear();
+ this.referenceConfigs.clear();
+ if (logger.isDebugEnabled()) {
+ logger.debug(NAME + "'s configs have been clear.");
+ }
+ }
+
+ private void clearBuilders() {
+ this.applicationBuilder = null;
+ this.registryBuilders.clear();
+ this.protocolBuilders.clear();
+ this.serviceBuilders.clear();
+ this.referenceBuilders.clear();
+ if (logger.isDebugEnabled()) {
+ logger.debug(NAME + "'s builders have been clear.");
+ }
+ }
+
+ private void release() {
+ executeMutually(() -> {
+ while (awaited.compareAndSet(false, true)) {
+ if (logger.isInfoEnabled()) {
+ logger.info(NAME + " is about to shutdown...");
+ }
+ condition.signalAll();
+ }
+ });
+ }
+
+ private void shutdown() {
+ if (!executorService.isShutdown()) {
+ // Shutdown executorService
+ executorService.shutdown();
+ }
+ }
+
+ private void executeMutually(Runnable runnable) {
+ try {
+ lock.lock();
+ runnable.run();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private static <C extends AbstractConfig, B extends AbstractBuilder> Map<String, C> buildConfigs(Map<String, B> map) {
+ Map<String, C> configs = new HashMap<>();
+ map.entrySet().forEach(entry -> {
+ configs.put(entry.getKey(), (C) entry.getValue().build());
+ });
+ return configs;
+ }
+}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ProtocolSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ProtocolSettings.java
new file mode 100644
index 0000000..dc0169b
--- /dev/null
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ProtocolSettings.java
@@ -0,0 +1,215 @@
+/*
+ * 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 org.apache.dubbo.bootstrap;
+
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.builders.ProtocolBuilder;
+
+import java.util.Map;
+
+/**
+ * The settings of {@link ProtocolConfig protcol}
+ *
+ * @see ProtocolBuilder
+ * @since 2.7.3
+ */
+public class ProtocolSettings extends AbstractSettings {
+
+ private final ProtocolBuilder builder;
+
+ public ProtocolSettings(ProtocolBuilder builder, DubboBootstrap dubboBootstrap) {
+ super(dubboBootstrap);
+ this.builder = builder;
+ }
+
+ public ProtocolSettings name(String name) {
+ builder.name(name);
+ return this;
+ }
+
+ public ProtocolSettings host(String host) {
+ builder.host(host);
+ return this;
+ }
+
+ public ProtocolSettings port(Integer port) {
+ builder.port(port);
+ return this;
+ }
+
+ public ProtocolSettings contextpath(String contextpath) {
+ builder.contextpath(contextpath);
+ return this;
+ }
+
+ @Deprecated
+ public ProtocolSettings path(String path) {
+ builder.path(path);
+ return this;
+ }
+
+ public ProtocolSettings threadpool(String threadpool) {
+ builder.threadpool(threadpool);
+ return this;
+ }
+
+ public ProtocolSettings corethreads(Integer corethreads) {
+ builder.corethreads(corethreads);
+ return this;
+ }
+
+ public ProtocolSettings threads(Integer threads) {
+ builder.threads(threads);
+ return this;
+ }
+
+ public ProtocolSettings iothreads(Integer iothreads) {
+ builder.iothreads(iothreads);
+ return this;
+ }
+
+ public ProtocolSettings queues(Integer queues) {
+ builder.queues(queues);
+ return this;
+ }
+
+ public ProtocolSettings accepts(Integer accepts) {
+ builder.accepts(accepts);
+ return this;
+ }
+
+ public ProtocolSettings codec(String codec) {
+ builder.codec(codec);
+ return this;
+ }
+
+ public ProtocolSettings serialization(String serialization) {
+ builder.serialization(serialization);
+ return this;
+ }
+
+ public ProtocolSettings charset(String charset) {
+ builder.charset(charset);
+ return this;
+ }
+
+ public ProtocolSettings payload(Integer payload) {
+ builder.payload(payload);
+ return this;
+ }
+
+ public ProtocolSettings buffer(Integer buffer) {
+ builder.buffer(buffer);
+ return this;
+ }
+
+ public ProtocolSettings heartbeat(Integer heartbeat) {
+ builder.heartbeat(heartbeat);
+ return this;
+ }
+
+ public ProtocolSettings accesslog(String accesslog) {
+ builder.accesslog(accesslog);
+ return this;
+ }
+
+ public ProtocolSettings transporter(String transporter) {
+ builder.transporter(transporter);
+ return this;
+ }
+
+ public ProtocolSettings exchanger(String exchanger) {
+ builder.exchanger(exchanger);
+ return this;
+ }
+
+ public ProtocolSettings dispatcher(String dispatcher) {
+ builder.dispatcher(dispatcher);
+ return this;
+ }
+
+ @Deprecated
+ public ProtocolSettings dispather(String dispather) {
+ builder.dispather(dispather);
+ return this;
+ }
+
+ public ProtocolSettings networker(String networker) {
+ builder.networker(networker);
+ return this;
+ }
+
+ public ProtocolSettings server(String server) {
+ builder.server(server);
+ return this;
+ }
+
+ public ProtocolSettings client(String client) {
+ builder.client(client);
+ return this;
+ }
+
+ public ProtocolSettings telnet(String telnet) {
+ builder.telnet(telnet);
+ return this;
+ }
+
+ public ProtocolSettings prompt(String prompt) {
+ builder.prompt(prompt);
+ return this;
+ }
+
+ public ProtocolSettings status(String status) {
+ builder.status(status);
+ return this;
+ }
+
+ public ProtocolSettings register(Boolean register) {
+ builder.register(register);
+ return this;
+ }
+
+ public ProtocolSettings keepAlive(Boolean keepAlive) {
+ builder.keepAlive(keepAlive);
+ return this;
+ }
+
+ public ProtocolSettings optimizer(String optimizer) {
+ builder.optimizer(optimizer);
+ return this;
+ }
+
+ public ProtocolSettings extension(String extension) {
+ builder.extension(extension);
+ return this;
+ }
+
+ public ProtocolSettings appendParameter(String key, String value) {
+ builder.appendParameter(key, value);
+ return this;
+ }
+
+ public ProtocolSettings appendParameters(Map<String, String> appendParameters) {
+ builder.appendParameters(appendParameters);
+ return this;
+ }
+
+ public ProtocolSettings isDefault(Boolean isDefault) {
+ builder.isDefault(isDefault);
+ return this;
+ }
+}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ReferenceSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ReferenceSettings.java
new file mode 100644
index 0000000..b38ae05
--- /dev/null
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ReferenceSettings.java
@@ -0,0 +1,334 @@
+/*
+ * 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 org.apache.dubbo.bootstrap;
+
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ConfigCenterConfig;
+import org.apache.dubbo.config.ConsumerConfig;
+import org.apache.dubbo.config.MetadataReportConfig;
+import org.apache.dubbo.config.MethodConfig;
+import org.apache.dubbo.config.ModuleConfig;
+import org.apache.dubbo.config.MonitorConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.builders.ReferenceBuilder;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The settings of {@link ReferenceConfig}
+ *
+ * @since 2.7.3
+ */
+public class ReferenceSettings<S> extends AbstractSettings {
+
+ private final ReferenceBuilder<S> builder;
+
+ public ReferenceSettings(ReferenceBuilder<S> builder, DubboBootstrap dubboBootstrap) {
+ super(dubboBootstrap);
+ this.builder = builder;
+ }
+
+ public ReferenceSettings<S> interfaceName(String interfaceName) {
+ builder.interfaceName(interfaceName);
+ return this;
+ }
+
+ public ReferenceSettings<S> interfaceClass(Class<?> interfaceClass) {
+ builder.interfaceClass(interfaceClass);
+ return this;
+ }
+
+ public ReferenceSettings<S> client(String client) {
+ builder.client(client);
+ return this;
+ }
+
+ public ReferenceSettings<S> url(String url) {
+ builder.url(url);
+ return this;
+ }
+
+ public ReferenceSettings<S> addMethods(List<MethodConfig> methods) {
+ builder.addMethods(methods);
+ return this;
+ }
+
+ public ReferenceSettings<S> addMethod(MethodConfig method) {
+ builder.addMethod(method);
+ return this;
+ }
+
+ public ReferenceSettings<S> consumer(ConsumerConfig consumer) {
+ builder.consumer(consumer);
+ return this;
+ }
+
+ public ReferenceSettings<S> protocol(String protocol) {
+ builder.protocol(protocol);
+ return this;
+ }
+
+ public ReferenceSettings<S> check(Boolean check) {
+ builder.check(check);
+ return this;
+ }
+
+ public ReferenceSettings<S> init(Boolean init) {
+ builder.init(init);
+ return this;
+ }
+
+ public ReferenceSettings<S> generic(String generic) {
+ builder.generic(generic);
+ return this;
+ }
+
+ public ReferenceSettings<S> generic(Boolean generic) {
+ builder.generic(generic);
+ return this;
+ }
+
+ @Deprecated
+ public ReferenceSettings<S> injvm(Boolean injvm) {
+ builder.injvm(injvm);
+ return this;
+ }
+
+ public ReferenceSettings<S> lazy(Boolean lazy) {
+ builder.lazy(lazy);
+ return this;
+ }
+
+ public ReferenceSettings<S> reconnect(String reconnect) {
+ builder.reconnect(reconnect);
+ return this;
+ }
+
+ public ReferenceSettings<S> sticky(Boolean sticky) {
+ builder.sticky(sticky);
+ return this;
+ }
+
+ public ReferenceSettings<S> version(String version) {
+ builder.version(version);
+ return this;
+ }
+
+ public ReferenceSettings<S> group(String group) {
+ builder.group(group);
+ return this;
+ }
+
+ @Deprecated
+ public ReferenceSettings<S> local(String local) {
+ builder.local(local);
+ return this;
+ }
+
+ @Deprecated
+ public ReferenceSettings<S> local(Boolean local) {
+ builder.local(local);
+ return this;
+ }
+
+ public ReferenceSettings<S> stub(String stub) {
+ builder.stub(stub);
+ return this;
+ }
+
+ public ReferenceSettings<S> stub(Boolean stub) {
+ builder.stub(stub);
+ return this;
+ }
+
+ public ReferenceSettings<S> monitor(MonitorConfig monitor) {
+ builder.monitor(monitor);
+ return this;
+ }
+
+ public ReferenceSettings<S> monitor(String monitor) {
+ builder.monitor(monitor);
+ return this;
+ }
+
+ public ReferenceSettings<S> proxy(String proxy) {
+ builder.proxy(proxy);
+ return this;
+ }
+
+ public ReferenceSettings<S> cluster(String cluster) {
+ builder.cluster(cluster);
+ return this;
+ }
+
+ public ReferenceSettings<S> filter(String filter) {
+ builder.filter(filter);
+ return this;
+ }
+
+ public ReferenceSettings<S> listener(String listener) {
+ builder.listener(listener);
+ return this;
+ }
+
+ public ReferenceSettings<S> owner(String owner) {
+ builder.owner(owner);
+ return this;
+ }
+
+ public ReferenceSettings<S> connections(Integer connections) {
+ builder.connections(connections);
+ return this;
+ }
+
+ public ReferenceSettings<S> layer(String layer) {
+ builder.layer(layer);
+ return this;
+ }
+
+ public ReferenceSettings<S> application(ApplicationConfig application) {
+ builder.application(application);
+ return this;
+ }
+
+ public ReferenceSettings<S> module(ModuleConfig module) {
+ builder.module(module);
+ return this;
+ }
+
+ public ReferenceSettings<S> addRegistries(List<RegistryConfig> registries) {
+ builder.addRegistries(registries);
+ return this;
+ }
+
+ public ReferenceSettings<S> addRegistry(RegistryConfig registry) {
+ builder.addRegistry(registry);
+ return this;
+ }
+
+ public ReferenceSettings<S> registryIds(String registryIds) {
+ builder.registryIds(registryIds);
+ return this;
+ }
+
+ public ReferenceSettings<S> onconnect(String onconnect) {
+ builder.onconnect(onconnect);
+ return this;
+ }
+
+ public ReferenceSettings<S> ondisconnect(String ondisconnect) {
+ builder.ondisconnect(ondisconnect);
+ return this;
+ }
+
+ public ReferenceSettings<S> metadataReportConfig(MetadataReportConfig metadataReportConfig) {
+ builder.metadataReportConfig(metadataReportConfig);
+ return this;
+ }
+
+ public ReferenceSettings<S> configCenter(ConfigCenterConfig configCenter) {
+ builder.configCenter(configCenter);
+ return this;
+ }
+
+ public ReferenceSettings<S> callbacks(Integer callbacks) {
+ builder.callbacks(callbacks);
+ return this;
+ }
+
+ public ReferenceSettings<S> scope(String scope) {
+ builder.scope(scope);
+ return this;
+ }
+
+ public ReferenceSettings<S> tag(String tag) {
+ builder.tag(tag);
+ return this;
+ }
+
+ public ReferenceSettings<S> timeout(Integer timeout) {
+ builder.timeout(timeout);
+ return this;
+ }
+
+ public ReferenceSettings<S> retries(Integer retries) {
+ builder.retries(retries);
+ return this;
+ }
+
+ public ReferenceSettings<S> actives(Integer actives) {
+ builder.actives(actives);
+ return this;
+ }
+
+ public ReferenceSettings<S> loadbalance(String loadbalance) {
+ builder.loadbalance(loadbalance);
+ return this;
+ }
+
+ public ReferenceSettings<S> async(Boolean async) {
+ builder.async(async);
+ return this;
+ }
+
+ public ReferenceSettings<S> sent(Boolean sent) {
+ builder.sent(sent);
+ return this;
+ }
+
+ public ReferenceSettings<S> mock(String mock) {
+ builder.mock(mock);
+ return this;
+ }
+
+ public ReferenceSettings<S> mock(Boolean mock) {
+ builder.mock(mock);
+ return this;
+ }
+
+ public ReferenceSettings<S> merger(String merger) {
+ builder.merger(merger);
+ return this;
+ }
+
+ public ReferenceSettings<S> cache(String cache) {
+ builder.cache(cache);
+ return this;
+ }
+
+ public ReferenceSettings<S> validation(String validation) {
+ builder.validation(validation);
+ return this;
+ }
+
+ public ReferenceSettings<S> appendParameters(Map<String, String> appendParameters) {
+ builder.appendParameters(appendParameters);
+ return this;
+ }
+
+ public ReferenceSettings<S> appendParameter(String key, String value) {
+ builder.appendParameter(key, value);
+ return this;
+ }
+
+ public ReferenceSettings<S> forks(Integer forks) {
+ builder.forks(forks);
+ return this;
+ }
+}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/RegistrySettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/RegistrySettings.java
new file mode 100644
index 0000000..40331ae
--- /dev/null
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/RegistrySettings.java
@@ -0,0 +1,164 @@
+/*
+ * 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 org.apache.dubbo.bootstrap;
+
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.builders.RegistryBuilder;
+
+import java.util.Map;
+
+/**
+ * The settings of {@link RegistryConfig}
+ *
+ * @since 2.7.3
+ */
+public class RegistrySettings extends AbstractSettings {
+
+ private final RegistryBuilder builder;
+
+ public RegistrySettings(RegistryBuilder builder, DubboBootstrap dubboBootstrap) {
+ super(dubboBootstrap);
+ this.builder = builder;
+ }
+
+ public RegistrySettings address(String address) {
+ builder.address(address);
+ return this;
+ }
+
+ public RegistrySettings username(String username) {
+ builder.username(username);
+ return this;
+ }
+
+ public RegistrySettings password(String password) {
+ builder.password(password);
+ return this;
+ }
+
+ public RegistrySettings port(Integer port) {
+ builder.port(port);
+ return this;
+ }
+
+ public RegistrySettings protocol(String protocol) {
+ builder.protocol(protocol);
+ return this;
+ }
+
+ public RegistrySettings transporter(String transporter) {
+ builder.transporter(transporter);
+ return this;
+ }
+
+ @Deprecated
+ public RegistrySettings transport(String transport) {
+ builder.transport(transport);
+ return this;
+ }
+
+ public RegistrySettings server(String server) {
+ builder.server(server);
+ return this;
+ }
+
+ public RegistrySettings client(String client) {
+ builder.client(client);
+ return this;
+ }
+
+ public RegistrySettings cluster(String cluster) {
+ builder.cluster(cluster);
+ return this;
+ }
+
+ public RegistrySettings group(String group) {
+ builder.group(group);
+ return this;
+ }
+
+ public RegistrySettings version(String version) {
+ builder.version(version);
+ return this;
+ }
+
+ public RegistrySettings timeout(Integer timeout) {
+ builder.timeout(timeout);
+ return this;
+ }
+
+ public RegistrySettings session(Integer session) {
+ builder.session(session);
+ return this;
+ }
+
+ public RegistrySettings file(String file) {
+ builder.file(file);
+ return this;
+ }
+
+ @Deprecated
+ public RegistrySettings wait(Integer wait) {
+ builder.wait(wait);
+ return this;
+ }
+
+ public RegistrySettings isCheck(Boolean check) {
+ builder.isCheck(check);
+ return this;
+ }
+
+ public RegistrySettings isDynamic(Boolean dynamic) {
+ builder.isDynamic(dynamic);
+ return this;
+ }
+
+ public RegistrySettings register(Boolean register) {
+ builder.register(register);
+ return this;
+ }
+
+ public RegistrySettings subscribe(Boolean subscribe) {
+ builder.subscribe(subscribe);
+ return this;
+ }
+
+ public RegistrySettings appendParameter(String key, String value) {
+ builder.appendParameter(key, value);
+ return this;
+ }
+
+ public RegistrySettings appendParameters(Map<String, String> appendParameters) {
+ builder.appendParameters(appendParameters);
+ return this;
+ }
+
+ public RegistrySettings isDefault(Boolean isDefault) {
+ builder.isDefault(isDefault);
+ return this;
+ }
+
+ public RegistrySettings simplified(Boolean simplified) {
+ builder.simplified(simplified);
+ return this;
+ }
+
+ public RegistrySettings extraKeys(String extraKeys) {
+ builder.extraKeys(extraKeys);
+ return this;
+ }
+}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ServiceSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ServiceSettings.java
new file mode 100644
index 0000000..314482e
--- /dev/null
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ServiceSettings.java
@@ -0,0 +1,384 @@
+/*
+ * 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 org.apache.dubbo.bootstrap;
+
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ConfigCenterConfig;
+import org.apache.dubbo.config.MetadataReportConfig;
+import org.apache.dubbo.config.MethodConfig;
+import org.apache.dubbo.config.ModuleConfig;
+import org.apache.dubbo.config.MonitorConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.ProviderConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.builders.ServiceBuilder;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The settings of {@link ServiceConfig Dubbo service}
+ *
+ * @since 2.7.3
+ */
+public class ServiceSettings<S> extends AbstractSettings {
+
+ private final ServiceBuilder<S> builder;
+
+ public ServiceSettings(ServiceBuilder<S> builder, DubboBootstrap dubboBootstrap) {
+ super(dubboBootstrap);
+ this.builder = builder;
+ }
+
+ public ServiceSettings<S> interfaceName(String interfaceName) {
+ builder.interfaceName(interfaceName);
+ return this;
+ }
+
+ public ServiceSettings<S> interfaceClass(Class<?> interfaceClass) {
+ builder.interfaceClass(interfaceClass);
+ return this;
+ }
+
+ public ServiceSettings<S> ref(S ref) {
+ builder.ref(ref);
+ return this;
+ }
+
+ public ServiceSettings<S> path(String path) {
+ builder.path(path);
+ return this;
+ }
+
+ public ServiceSettings<S> addMethod(MethodConfig method) {
+ builder.addMethod(method);
+ return this;
+ }
+
+ public ServiceSettings<S> addMethods(List<? extends MethodConfig> methods) {
+ builder.addMethods(methods);
+ return this;
+ }
+
+ public ServiceSettings<S> provider(ProviderConfig provider) {
+ builder.provider(provider);
+ return this;
+ }
+
+ public ServiceSettings<S> providerIds(String providerIds) {
+ builder.providerIds(providerIds);
+ return this;
+ }
+
+ public ServiceSettings<S> generic(String generic) {
+ builder.generic(generic);
+ return this;
+ }
+
+ public ServiceSettings<S> mock(String mock) {
+ builder.mock(mock);
+ return this;
+ }
+
+ public ServiceSettings<S> mock(Boolean mock) {
+ builder.mock(mock);
+ return this;
+ }
+
+ public ServiceSettings<S> version(String version) {
+ builder.version(version);
+ return this;
+ }
+
+ public ServiceSettings<S> group(String group) {
+ builder.group(group);
+ return this;
+ }
+
+ public ServiceSettings<S> deprecated(Boolean deprecated) {
+ builder.deprecated(deprecated);
+ return this;
+ }
+
+ public ServiceSettings<S> delay(Integer delay) {
+ builder.delay(delay);
+ return this;
+ }
+
+ public ServiceSettings<S> export(Boolean export) {
+ builder.export(export);
+ return this;
+ }
+
+ public ServiceSettings<S> weight(Integer weight) {
+ builder.weight(weight);
+ return this;
+ }
+
+ public ServiceSettings<S> document(String document) {
+ builder.document(document);
+ return this;
+ }
+
+ public ServiceSettings<S> dynamic(Boolean dynamic) {
+ builder.dynamic(dynamic);
+ return this;
+ }
+
+ public ServiceSettings<S> token(String token) {
+ builder.token(token);
+ return this;
+ }
+
+ public ServiceSettings<S> token(Boolean token) {
+ builder.token(token);
+ return this;
+ }
+
+ public ServiceSettings<S> accesslog(String accesslog) {
+ builder.accesslog(accesslog);
+ return this;
+ }
+
+ public ServiceSettings<S> accesslog(Boolean accesslog) {
+ builder.accesslog(accesslog);
+ return this;
+ }
+
+ public ServiceSettings<S> addProtocols(List<ProtocolConfig> protocols) {
+ builder.addProtocols(protocols);
+ return this;
+ }
+
+ public ServiceSettings<S> addProtocol(ProtocolConfig protocol) {
+ builder.addProtocol(protocol);
+ return this;
+ }
+
+ public ServiceSettings<S> protocolIds(String protocolIds) {
+ builder.protocolIds(protocolIds);
+ return this;
+ }
+
+ public ServiceSettings<S> executes(Integer executes) {
+ builder.executes(executes);
+ return this;
+ }
+
+ public ServiceSettings<S> register(Boolean register) {
+ builder.register(register);
+ return this;
+ }
+
+ public ServiceSettings<S> warmup(Integer warmup) {
+ builder.warmup(warmup);
+ return this;
+ }
+
+ public ServiceSettings<S> serialization(String serialization) {
+ builder.serialization(serialization);
+ return this;
+ }
+
+ @Deprecated
+ public ServiceSettings<S> local(String local) {
+ builder.local(local);
+ return this;
+ }
+
+ @Deprecated
+ public ServiceSettings<S> local(Boolean local) {
+ builder.local(local);
+ return this;
+ }
+
+ public ServiceSettings<S> stub(String stub) {
+ builder.stub(stub);
+ return this;
+ }
+
+ public ServiceSettings<S> stub(Boolean stub) {
+ builder.stub(stub);
+ return this;
+ }
+
+ public ServiceSettings<S> monitor(MonitorConfig monitor) {
+ builder.monitor(monitor);
+ return this;
+ }
+
+ public ServiceSettings<S> monitor(String monitor) {
+ builder.monitor(monitor);
+ return this;
+ }
+
+ public ServiceSettings<S> proxy(String proxy) {
+ builder.proxy(proxy);
+ return this;
+ }
+
+ public ServiceSettings<S> cluster(String cluster) {
+ builder.cluster(cluster);
+ return this;
+ }
+
+ public ServiceSettings<S> filter(String filter) {
+ builder.filter(filter);
+ return this;
+ }
+
+ public ServiceSettings<S> listener(String listener) {
+ builder.listener(listener);
+ return this;
+ }
+
+ public ServiceSettings<S> owner(String owner) {
+ builder.owner(owner);
+ return this;
+ }
+
+ public ServiceSettings<S> connections(Integer connections) {
+ builder.connections(connections);
+ return this;
+ }
+
+ public ServiceSettings<S> layer(String layer) {
+ builder.layer(layer);
+ return this;
+ }
+
+ public ServiceSettings<S> application(ApplicationConfig application) {
+ builder.application(application);
+ return this;
+ }
+
+ public ServiceSettings<S> module(ModuleConfig module) {
+ builder.module(module);
+ return this;
+ }
+
+ public ServiceSettings<S> addRegistries(List<RegistryConfig> registries) {
+ builder.addRegistries(registries);
+ return this;
+ }
+
+ public ServiceSettings<S> addRegistry(RegistryConfig registry) {
+ builder.addRegistry(registry);
+ return this;
+ }
+
+ public ServiceSettings<S> registryIds(String registryIds) {
+ builder.registryIds(registryIds);
+ return this;
+ }
+
+ public ServiceSettings<S> onconnect(String onconnect) {
+ builder.onconnect(onconnect);
+ return this;
+ }
+
+ public ServiceSettings<S> ondisconnect(String ondisconnect) {
+ builder.ondisconnect(ondisconnect);
+ return this;
+ }
+
+ public ServiceSettings<S> metadataReportConfig(MetadataReportConfig metadataReportConfig) {
+ builder.metadataReportConfig(metadataReportConfig);
+ return this;
+ }
+
+ public ServiceSettings<S> configCenter(ConfigCenterConfig configCenter) {
+ builder.configCenter(configCenter);
+ return this;
+ }
+
+ public ServiceSettings<S> callbacks(Integer callbacks) {
+ builder.callbacks(callbacks);
+ return this;
+ }
+
+ public ServiceSettings<S> scope(String scope) {
+ builder.scope(scope);
+ return this;
+ }
+
+ public ServiceSettings<S> tag(String tag) {
+ builder.tag(tag);
+ return this;
+ }
+
+ public ServiceSettings<S> timeout(Integer timeout) {
+ builder.timeout(timeout);
+ return this;
+ }
+
+ public ServiceSettings<S> retries(Integer retries) {
+ builder.retries(retries);
+ return this;
+ }
+
+ public ServiceSettings<S> actives(Integer actives) {
+ builder.actives(actives);
+ return this;
+ }
+
+ public ServiceSettings<S> loadbalance(String loadbalance) {
+ builder.loadbalance(loadbalance);
+ return this;
+ }
+
+ public ServiceSettings<S> async(Boolean async) {
+ builder.async(async);
+ return this;
+ }
+
+ public ServiceSettings<S> sent(Boolean sent) {
+ builder.sent(sent);
+ return this;
+ }
+
+ public ServiceSettings<S> merger(String merger) {
+ builder.merger(merger);
+ return this;
+ }
+
+ public ServiceSettings<S> cache(String cache) {
+ builder.cache(cache);
+ return this;
+ }
+
+ public ServiceSettings<S> validation(String validation) {
+ builder.validation(validation);
+ return this;
+ }
+
+ public ServiceSettings<S> appendParameters(Map<String, String> appendParameters) {
+ builder.appendParameters(appendParameters);
+ return this;
+ }
+
+ public ServiceSettings<S> appendParameter(String key, String value) {
+ builder.appendParameter(key, value);
+ return this;
+ }
+
+ public ServiceSettings<S> forks(Integer forks) {
+ builder.forks(forks);
+ return this;
+ }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/Settings.java
similarity index 74%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/Settings.java
index c5bc722..abf8141 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/Settings.java
@@ -14,24 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.api;
-
-import java.util.List;
-
+package org.apache.dubbo.bootstrap;
/**
- * DemoService
+ * The Dubbo settings
+ *
+ * @since 2.7.3
*/
-public interface DemoService {
-
- String sayName(String name);
-
- Box getBox();
-
- void throwDemoException() throws DemoException;
-
- List<User> getUsers(List<User> users);
-
- int echo(int i);
-
-}
\ No newline at end of file
+public interface Settings {
+
+ /**
+ * Go next settings
+ *
+ * @return {@link DubboBootstrap}
+ */
+ DubboBootstrap next();
+}
diff --git a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboBootstrapTest.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboBootstrapTest.java
new file mode 100644
index 0000000..b9acd29
--- /dev/null
+++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboBootstrapTest.java
@@ -0,0 +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 org.apache.dubbo.bootstrap;
+
+import org.apache.dubbo.common.utils.NetUtils;
+
+import org.apache.curator.test.TestingServer;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+
+/**
+ * {@link DubboBootstrap} Test
+ *
+ * @since 2.7.3
+ */
+public class DubboBootstrapTest {
+
+ private static int zkServerPort = NetUtils.getAvailablePort();
+
+ private static TestingServer zkServer;
+
+
+ @BeforeAll
+ public static void init() throws Exception {
+ zkServer = new TestingServer(zkServerPort, true);
+ }
+
+ @AfterAll
+ public static void destroy() throws IOException {
+ zkServer.stop();
+ zkServer.close();
+ }
+
+ @Test
+ public void testProviderInFluentAPI() {
+
+ new DubboBootstrap()
+ .application("dubbo-provider-demo")
+ .next()
+ .registry()
+ .address("zookeeper://127.0.0.1:" + zkServerPort + "?registry-type=service")
+ .next()
+ .protocol()
+ .name("dubbo")
+ .port(-1)
+ .next()
+ .service("test")
+ .interfaceClass(EchoService.class)
+ .ref(new EchoServiceImpl())
+ .group("DEFAULT")
+ .version("1.0.0")
+ .next()
+ .start()
+ .stop();
+
+ }
+
+ @Test
+ public void testProviderInLambda() {
+ new DubboBootstrap()
+ .application("dubbo-provider-demo", builder -> {
+ })
+ .registry("default", builder ->
+ builder.address("zookeeper://127.0.0.1:" + zkServerPort + "?registry-type=service")
+ )
+ .protocol("defalt", builder ->
+ builder.name("dubbo")
+ .port(-1)
+ )
+ .service("test", builder ->
+ builder.interfaceClass(EchoService.class)
+ .ref(new EchoServiceImpl())
+ .group("DEFAULT")
+ .version("1.0.0")
+ )
+ .start()
+ .stop();
+ }
+}
diff --git a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java
new file mode 100644
index 0000000..800f29d
--- /dev/null
+++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java
@@ -0,0 +1,58 @@
+/*
+ * 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 org.apache.dubbo.bootstrap;
+
+import org.apache.dubbo.config.ReferenceConfig;
+
+import static org.apache.dubbo.bootstrap.EchoService.GROUP;
+import static org.apache.dubbo.bootstrap.EchoService.VERSION;
+
+/**
+ * Dubbo Provider Bootstrap
+ *
+ * @since 2.7.3
+ */
+public class DubboServiceConsumerBootstrap {
+
+ public static void main(String[] args) throws Exception {
+
+ DubboBootstrap bootstrap = new DubboBootstrap()
+ .application("dubbo-consumer-demo")
+ .next()
+ .registry()
+ .address("nacos://127.0.0.1:8848?registry-type=service&subscribed-services=dubbo-provider-demo")
+ .next()
+ .reference("ref")
+ .interfaceClass(EchoService.class)
+ .group(GROUP)
+ .version(VERSION)
+ .next()
+ .onlyRegisterProvider(true)
+ .start()
+ .await();
+
+ ReferenceConfig<EchoService> referenceConfig = bootstrap.referenceConfig("ref");
+
+ EchoService echoService = referenceConfig.get();
+
+ for (int i = 0; i < 500; i++) {
+ Thread.sleep(2000L);
+ System.out.println(echoService.echo("Hello,World"));
+ }
+
+ }
+}
diff --git a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceProviderBootstrap.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceProviderBootstrap.java
new file mode 100644
index 0000000..bb149ad
--- /dev/null
+++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceProviderBootstrap.java
@@ -0,0 +1,52 @@
+/*
+ * 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 org.apache.dubbo.bootstrap;
+
+import java.io.IOException;
+
+import static org.apache.dubbo.bootstrap.EchoService.GROUP;
+import static org.apache.dubbo.bootstrap.EchoService.VERSION;
+
+/**
+ * Dubbo Provider Bootstrap
+ *
+ * @since 2.7.3
+ */
+public class DubboServiceProviderBootstrap {
+
+ public static void main(String[] args) throws IOException {
+
+ new DubboBootstrap()
+ .application("dubbo-provider-demo")
+ .next()
+ .registry()
+ .address("nacos://127.0.0.1:8848?registry-type=service")
+ .next()
+ .protocol()
+ .name("dubbo")
+ .port(-1)
+ .next()
+ .service("test")
+ .interfaceClass(EchoService.class)
+ .ref(new EchoServiceImpl())
+ .group(GROUP)
+ .version(VERSION)
+ .next()
+ .start()
+ .await();
+ }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/EchoService.java
similarity index 74%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/EchoService.java
index c5bc722..7ad8698 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/EchoService.java
@@ -14,24 +14,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.api;
-
-import java.util.List;
-
+package org.apache.dubbo.bootstrap;
/**
- * DemoService
+ * Echo Service
+ *
+ * @since 2.7.3
*/
-public interface DemoService {
-
- String sayName(String name);
-
- Box getBox();
-
- void throwDemoException() throws DemoException;
+public interface EchoService {
- List<User> getUsers(List<User> users);
+ String GROUP = "DEFAULT";
- int echo(int i);
+ String VERSION = "1.0.0";
-}
\ No newline at end of file
+ String echo(String message);
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/EchoServiceImpl.java
similarity index 62%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/EchoServiceImpl.java
index c5bc722..e0218b1 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/EchoServiceImpl.java
@@ -14,24 +14,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.api;
+package org.apache.dubbo.bootstrap;
-import java.util.List;
+import org.apache.dubbo.rpc.RpcContext;
+import static java.lang.String.format;
/**
- * DemoService
+ * The implementation of {@link EchoService}
+ *
+ * @see EchoService
+ * @since 2.7.3
*/
-public interface DemoService {
-
- String sayName(String name);
-
- Box getBox();
-
- void throwDemoException() throws DemoException;
-
- List<User> getUsers(List<User> users);
-
- int echo(int i);
-
-}
\ No newline at end of file
+public class EchoServiceImpl implements EchoService {
+
+ @Override
+ public String echo(String message) {
+ RpcContext rpcContext = RpcContext.getContext();
+ return format("[%s:%s] ECHO - %s", rpcContext.getLocalHost(), rpcContext.getLocalPort(), message);
+ }
+}
diff --git a/dubbo-bootstrap/src/test/resources/log4j.properties b/dubbo-bootstrap/src/test/resources/log4j.properties
new file mode 100644
index 0000000..15a0900
--- /dev/null
+++ b/dubbo-bootstrap/src/test/resources/log4j.properties
@@ -0,0 +1,7 @@
+###set log levels###
+log4j.rootLogger=info, stdout
+###output to the console###
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java
index 87e9b25..3ac978d 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java
@@ -38,16 +38,16 @@ import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
+import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.ADDRESS_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
-import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
/**
* ConditionRouter
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
index 7a2894b..8eca3c1 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
@@ -23,7 +23,6 @@ import org.apache.dubbo.remoting.Constants;
import java.util.HashMap;
import java.util.Map;
-import static org.apache.dubbo.rpc.cluster.Constants.TAG_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;
@@ -41,6 +40,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
import static org.apache.dubbo.rpc.Constants.INVOKER_LISTENER_KEY;
import static org.apache.dubbo.rpc.Constants.REFERENCE_FILTER_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.TAG_KEY;
/**
* ClusterUtils
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java
index 871e075..1a67587 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java
@@ -25,6 +25,7 @@ import org.junit.jupiter.api.Test;
import static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;
@@ -32,7 +33,6 @@ import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
public class ClusterUtilsTest {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
index 106bebc..82627f2 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
@@ -40,20 +40,20 @@ import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
-import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
/**
* URL - Uniform Resource Locator (Immutable, ThreadSafe)
@@ -339,6 +339,30 @@ class URL implements Serializable {
}
}
+ static String appendDefaultPort(String address, int defaultPort) {
+ if (address != null && address.length() > 0 && defaultPort > 0) {
+ int i = address.indexOf(':');
+ if (i < 0) {
+ return address + ":" + defaultPort;
+ } else if (Integer.parseInt(address.substring(i + 1)) == 0) {
+ return address.substring(0, i + 1) + defaultPort;
+ }
+ }
+ return address;
+ }
+
+ public static String buildKey(String path, String group, String version) {
+ StringBuilder buf = new StringBuilder();
+ if (group != null && group.length() > 0) {
+ buf.append(group).append("/");
+ }
+ buf.append(path);
+ if (version != null && version.length() > 0) {
+ buf.append(":").append(version);
+ }
+ return buf.toString();
+ }
+
public String getProtocol() {
return protocol;
}
@@ -452,18 +476,6 @@ class URL implements Serializable {
return urls;
}
- static String appendDefaultPort(String address, int defaultPort) {
- if (address != null && address.length() > 0 && defaultPort > 0) {
- int i = address.indexOf(':');
- if (i < 0) {
- return address + ":" + defaultPort;
- } else if (Integer.parseInt(address.substring(i + 1)) == 0) {
- return address.substring(0, i + 1) + defaultPort;
- }
- }
- return address;
- }
-
public String getPath() {
return path;
}
@@ -1325,6 +1337,7 @@ class URL implements Serializable {
/**
* The format of return value is '{group}/{interfaceName}:{version}'
+ *
* @return
*/
public String getServiceKey() {
@@ -1337,6 +1350,7 @@ class URL implements Serializable {
/**
* The format of return value is '{group}/{path/interfaceName}:{version}'
+ *
* @return
*/
public String getPathKey() {
@@ -1347,18 +1361,6 @@ class URL implements Serializable {
return buildKey(inf, getParameter(GROUP_KEY), getParameter(VERSION_KEY));
}
- public static String buildKey(String path, String group, String version) {
- StringBuilder buf = new StringBuilder();
- if (group != null && group.length() > 0) {
- buf.append(group).append("/");
- }
- buf.append(path);
- if (version != null && version.length() > 0) {
- buf.append(":").append(version);
- }
- return buf.toString();
- }
-
public String toServiceStringWithoutResolving() {
return buildString(true, false, false, true);
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java
index 647ac81..b28fe39 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java
@@ -52,4 +52,38 @@ public interface RegistryConstants {
String OVERRIDE_PROTOCOL = "override";
String COMPATIBLE_CONFIG_KEY = "compatible_config";
+
+ /**
+ * The parameter key of Dubbo Registry type
+ *
+ * @since 2.7.3
+ */
+ String REGISTRY_TYPE_KEY = "registry-type";
+
+ /**
+ * The parameter value of Service-Oriented Registry type
+ *
+ * @since 2.7.3
+ */
+ String SERVICE_REGISTRY_TYPE = "service";
+
+ /**
+ * The parameter key of the subscribed service names for Service-Oriented Registry
+ *
+ * @since 2.7.3
+ */
+ String SUBSCRIBED_SERVICE_NAMES_KEY = "subscribed-services";
+
+
+ /**
+ * The request size of service instances
+ *
+ * @since 2.7.3
+ */
+ String INSTANCES_REQUEST_SIZE_KEY = "instances-request-size";
+
+ /**
+ * The default request size of service instances
+ */
+ int DEFAULT_INSTANCES_REQUEST_SIZE = 100;
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/function/ThrowableConsumer.java b/dubbo-common/src/main/java/org/apache/dubbo/common/function/ThrowableConsumer.java
new file mode 100644
index 0000000..28561bb
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/function/ThrowableConsumer.java
@@ -0,0 +1,66 @@
+/*
+ * 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 org.apache.dubbo.common.function;
+
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * {@link Consumer} with {@link Throwable}
+ *
+ * @param <T> the source type
+ * @see Function
+ * @see Throwable
+ * @since 2.7.3
+ */
+@FunctionalInterface
+public interface ThrowableConsumer<T> {
+
+ /**
+ * Applies this function to the given argument.
+ *
+ * @param t the function argument
+ * @throws Throwable if met with any error
+ */
+ void accept(T t) throws Throwable;
+
+ /**
+ * Executes {@link ThrowableConsumer}
+ *
+ * @param t the function argument
+ * @throws RuntimeException wrappers {@link Throwable}
+ */
+ default void execute(T t) throws RuntimeException {
+ try {
+ accept(t);
+ } catch (Throwable e) {
+ throw new RuntimeException(e.getMessage(), e.getCause());
+ }
+ }
+
+ /**
+ * Executes {@link ThrowableConsumer}
+ *
+ * @param t the function argument
+ * @param consumer {@link ThrowableConsumer}
+ * @param <T> the source type
+ * @return the result after execution
+ */
+ static <T> void execute(T t, ThrowableConsumer<T> consumer) {
+ consumer.execute(t);
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/function/ThrowableFunction.java b/dubbo-common/src/main/java/org/apache/dubbo/common/function/ThrowableFunction.java
new file mode 100644
index 0000000..eb7171d
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/function/ThrowableFunction.java
@@ -0,0 +1,71 @@
+/*
+ * 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 org.apache.dubbo.common.function;
+
+import java.util.function.Function;
+
+/**
+ * {@link Function} with {@link Throwable}
+ *
+ * @param <T> the source type
+ * @param <R> the return type
+ * @see Function
+ * @see Throwable
+ * @since 2.7.3
+ */
+@FunctionalInterface
+public interface ThrowableFunction<T, R> {
+
+ /**
+ * Applies this function to the given argument.
+ *
+ * @param t the function argument
+ * @return the function result
+ * @throws Throwable if met with any error
+ */
+ R apply(T t) throws Throwable;
+
+ /**
+ * Executes {@link ThrowableFunction}
+ *
+ * @param t the function argument
+ * @return the function result
+ * @throws RuntimeException wrappers {@link Throwable}
+ */
+ default R execute(T t) throws RuntimeException {
+ R result = null;
+ try {
+ result = apply(t);
+ } catch (Throwable e) {
+ throw new RuntimeException(e.getCause());
+ }
+ return result;
+ }
+
+ /**
+ * Executes {@link ThrowableFunction}
+ *
+ * @param t the function argument
+ * @param function {@link ThrowableFunction}
+ * @param <T> the source type
+ * @param <R> the return type
+ * @return the result after execution
+ */
+ static <T, R> R execute(T t, ThrowableFunction<T, R> function) {
+ return function.execute(t);
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultPage.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultPage.java
new file mode 100644
index 0000000..fd408b5
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultPage.java
@@ -0,0 +1,82 @@
+/*
+ * 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 org.apache.dubbo.common.utils;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * The default implementation of {@link Page}
+ *
+ * @since 2.7.3
+ */
+public class DefaultPage<T> implements Page<T>, Serializable {
+
+ private static final long serialVersionUID = 1099331838954070419L;
+
+ private final int requestOffset;
+
+ private final int pageSize;
+
+ private final int totalSize;
+
+ private final List<T> data;
+
+ private final int totalPages;
+
+ private final boolean hasNext;
+
+ public DefaultPage(int requestOffset, int pageSize, List<T> data, int totalSize) {
+ this.requestOffset = requestOffset;
+ this.pageSize = pageSize;
+ this.data = data;
+ this.totalSize = totalSize;
+ int remain = totalSize % pageSize;
+ this.totalPages = remain > 0 ? (totalSize / pageSize) + 1 : totalSize / pageSize;
+ this.hasNext = totalSize - requestOffset - pageSize > 0;
+ }
+
+ @Override
+ public int getOffset() {
+ return requestOffset;
+ }
+
+ @Override
+ public int getPageSize() {
+ return pageSize;
+ }
+
+ @Override
+ public int getTotalSize() {
+ return totalSize;
+ }
+
+ @Override
+ public int getTotalPages() {
+ return totalPages;
+ }
+
+ @Override
+ public List<T> getData() {
+ return data;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return hasNext;
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java
index 6fd1a4e..c2fea8b 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java
@@ -37,9 +37,9 @@ import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Pattern;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND;
import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND;
/**
* IP and Port Helper for RPC
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/Page.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/Page.java
new file mode 100644
index 0000000..c15cfb8
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/Page.java
@@ -0,0 +1,87 @@
+/*
+ * 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 org.apache.dubbo.common.utils;
+
+import java.util.List;
+
+/**
+ * The model class of pagination
+ *
+ * @since 2.7.3
+ */
+public interface Page<T> {
+
+ /**
+ * Gets the offset of request
+ *
+ * @return positive integer
+ */
+ int getOffset();
+
+ /**
+ * Gets the size of request for pagination query
+ *
+ * @return positive integer
+ */
+ int getPageSize();
+
+ /**
+ * Gets the total amount of elements.
+ *
+ * @return the total amount of elements
+ */
+ int getTotalSize();
+
+ /**
+ * Get the number of total pages.
+ *
+ * @return the number of total pages.
+ */
+ int getTotalPages();
+
+ /**
+ * The data of current page
+ *
+ * @return non-null {@link List}
+ */
+ List<T> getData();
+
+ /**
+ * The size of {@link #getData() data}
+ *
+ * @return positive integer
+ */
+ default int getDataSize() {
+ return getData().size();
+ }
+
+ /**
+ * It indicates has next page or not
+ *
+ * @return if has , return <code>true</code>, or <code>false</code>
+ */
+ boolean hasNext();
+
+ /**
+ * Returns whether the page has data at all.
+ *
+ * @return
+ */
+ default boolean hasData() {
+ return getDataSize() > 0;
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java
index 0c1a13d..437f131 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java
@@ -1,1122 +1,1187 @@
-/*
- * 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 org.apache.dubbo.common.utils;
-
-import javassist.CtClass;
-import javassist.CtConstructor;
-import javassist.CtMethod;
-import javassist.NotFoundException;
-
-import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.net.URL;
-import java.security.CodeSource;
-import java.security.ProtectionDomain;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Future;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * ReflectUtils
- */
-public final class ReflectUtils {
-
- /**
- * void(V).
- */
- public static final char JVM_VOID = 'V';
-
- /**
- * boolean(Z).
- */
- public static final char JVM_BOOLEAN = 'Z';
-
- /**
- * byte(B).
- */
- public static final char JVM_BYTE = 'B';
-
- /**
- * char(C).
- */
- public static final char JVM_CHAR = 'C';
-
- /**
- * double(D).
- */
- public static final char JVM_DOUBLE = 'D';
-
- /**
- * float(F).
- */
- public static final char JVM_FLOAT = 'F';
-
- /**
- * int(I).
- */
- public static final char JVM_INT = 'I';
-
- /**
- * long(J).
- */
- public static final char JVM_LONG = 'J';
-
- /**
- * short(S).
- */
- public static final char JVM_SHORT = 'S';
-
- public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
-
- public static final String JAVA_IDENT_REGEX = "(?:[_$a-zA-Z][_$a-zA-Z0-9]*)";
-
- public static final String JAVA_NAME_REGEX = "(?:" + JAVA_IDENT_REGEX + "(?:\\." + JAVA_IDENT_REGEX + ")*)";
-
- public static final String CLASS_DESC = "(?:L" + JAVA_IDENT_REGEX + "(?:\\/" + JAVA_IDENT_REGEX + ")*;)";
-
- public static final String ARRAY_DESC = "(?:\\[+(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "))";
-
- public static final String DESC_REGEX = "(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "|" + ARRAY_DESC + ")";
-
- public static final Pattern DESC_PATTERN = Pattern.compile(DESC_REGEX);
-
- public static final String METHOD_DESC_REGEX = "(?:(" + JAVA_IDENT_REGEX + ")?\\((" + DESC_REGEX + "*)\\)(" + DESC_REGEX + ")?)";
-
- public static final Pattern METHOD_DESC_PATTERN = Pattern.compile(METHOD_DESC_REGEX);
-
- public static final Pattern GETTER_METHOD_DESC_PATTERN = Pattern.compile("get([A-Z][_a-zA-Z0-9]*)\\(\\)(" + DESC_REGEX + ")");
-
- public static final Pattern SETTER_METHOD_DESC_PATTERN = Pattern.compile("set([A-Z][_a-zA-Z0-9]*)\\((" + DESC_REGEX + ")\\)V");
-
- public static final Pattern IS_HAS_CAN_METHOD_DESC_PATTERN = Pattern.compile("(?:is|has|can)([A-Z][_a-zA-Z0-9]*)\\(\\)Z");
-
- private static final ConcurrentMap<String, Class<?>> DESC_CLASS_CACHE = new ConcurrentHashMap<String, Class<?>>();
-
- private static final ConcurrentMap<String, Class<?>> NAME_CLASS_CACHE = new ConcurrentHashMap<String, Class<?>>();
-
- private static final ConcurrentMap<String, Method> Signature_METHODS_CACHE = new ConcurrentHashMap<String, Method>();
-
- private ReflectUtils() {
- }
-
- public static boolean isPrimitives(Class<?> cls) {
- if (cls.isArray()) {
- return isPrimitive(cls.getComponentType());
- }
- return isPrimitive(cls);
- }
-
- public static boolean isPrimitive(Class<?> cls) {
- return cls.isPrimitive() || cls == String.class || cls == Boolean.class || cls == Character.class
- || Number.class.isAssignableFrom(cls) || Date.class.isAssignableFrom(cls);
- }
-
- public static Class<?> getBoxedClass(Class<?> c) {
- if (c == int.class) {
- c = Integer.class;
- } else if (c == boolean.class) {
- c = Boolean.class;
- } else if (c == long.class) {
- c = Long.class;
- } else if (c == float.class) {
- c = Float.class;
- } else if (c == double.class) {
- c = Double.class;
- } else if (c == char.class) {
- c = Character.class;
- } else if (c == byte.class) {
- c = Byte.class;
- } else if (c == short.class) {
- c = Short.class;
- }
- return c;
- }
-
- /**
- * is compatible.
- *
- * @param c class.
- * @param o instance.
- * @return compatible or not.
- */
- public static boolean isCompatible(Class<?> c, Object o) {
- boolean pt = c.isPrimitive();
- if (o == null) {
- return !pt;
- }
-
- if (pt) {
- c = getBoxedClass(c);
- }
-
- return c == o.getClass() || c.isInstance(o);
- }
-
- /**
- * is compatible.
- *
- * @param cs class array.
- * @param os object array.
- * @return compatible or not.
- */
- public static boolean isCompatible(Class<?>[] cs, Object[] os) {
- int len = cs.length;
- if (len != os.length) {
- return false;
- }
- if (len == 0) {
- return true;
- }
- for (int i = 0; i < len; i++) {
- if (!isCompatible(cs[i], os[i])) {
- return false;
- }
- }
- return true;
- }
-
- public static String getCodeBase(Class<?> cls) {
- if (cls == null) {
- return null;
- }
- ProtectionDomain domain = cls.getProtectionDomain();
- if (domain == null) {
- return null;
- }
- CodeSource source = domain.getCodeSource();
- if (source == null) {
- return null;
- }
- URL location = source.getLocation();
- if (location == null) {
- return null;
- }
- return location.getFile();
- }
-
- /**
- * get name.
- * java.lang.Object[][].class => "java.lang.Object[][]"
- *
- * @param c class.
- * @return name.
- */
- public static String getName(Class<?> c) {
- if (c.isArray()) {
- StringBuilder sb = new StringBuilder();
- do {
- sb.append("[]");
- c = c.getComponentType();
- }
- while (c.isArray());
-
- return c.getName() + sb.toString();
- }
- return c.getName();
- }
-
- public static Class<?> getGenericClass(Class<?> cls) {
- return getGenericClass(cls, 0);
- }
-
- public static Class<?> getGenericClass(Class<?> cls, int i) {
- try {
- ParameterizedType parameterizedType = ((ParameterizedType) cls.getGenericInterfaces()[0]);
- Object genericClass = parameterizedType.getActualTypeArguments()[i];
- if (genericClass instanceof ParameterizedType) { // handle nested generic type
- return (Class<?>) ((ParameterizedType) genericClass).getRawType();
- } else if (genericClass instanceof GenericArrayType) { // handle array generic type
- return (Class<?>) ((GenericArrayType) genericClass).getGenericComponentType();
- } else if (((Class) genericClass).isArray()) {
- // Requires JDK 7 or higher, Foo<int[]> is no longer GenericArrayType
- return ((Class) genericClass).getComponentType();
- } else {
- return (Class<?>) genericClass;
- }
- } catch (Throwable e) {
- throw new IllegalArgumentException(cls.getName()
- + " generic type undefined!", e);
- }
- }
-
- /**
- * get method name.
- * "void do(int)", "void do()", "int do(java.lang.String,boolean)"
- *
- * @param m method.
- * @return name.
- */
- public static String getName(final Method m) {
- StringBuilder ret = new StringBuilder();
- ret.append(getName(m.getReturnType())).append(' ');
- ret.append(m.getName()).append('(');
- Class<?>[] parameterTypes = m.getParameterTypes();
- for (int i = 0; i < parameterTypes.length; i++) {
- if (i > 0) {
- ret.append(',');
- }
- ret.append(getName(parameterTypes[i]));
- }
- ret.append(')');
- return ret.toString();
- }
-
- public static String getSignature(String methodName, Class<?>[] parameterTypes) {
- StringBuilder sb = new StringBuilder(methodName);
- sb.append("(");
- if (parameterTypes != null && parameterTypes.length > 0) {
- boolean first = true;
- for (Class<?> type : parameterTypes) {
- if (first) {
- first = false;
- } else {
- sb.append(",");
- }
- sb.append(type.getName());
- }
- }
- sb.append(")");
- return sb.toString();
- }
-
- /**
- * get constructor name.
- * "()", "(java.lang.String,int)"
- *
- * @param c constructor.
- * @return name.
- */
- public static String getName(final Constructor<?> c) {
- StringBuilder ret = new StringBuilder("(");
- Class<?>[] parameterTypes = c.getParameterTypes();
- for (int i = 0; i < parameterTypes.length; i++) {
- if (i > 0) {
- ret.append(',');
- }
- ret.append(getName(parameterTypes[i]));
- }
- ret.append(')');
- return ret.toString();
- }
-
- /**
- * get class desc.
- * boolean[].class => "[Z"
- * Object.class => "Ljava/lang/Object;"
- *
- * @param c class.
- * @return desc.
- * @throws NotFoundException
- */
- public static String getDesc(Class<?> c) {
- StringBuilder ret = new StringBuilder();
-
- while (c.isArray()) {
- ret.append('[');
- c = c.getComponentType();
- }
-
- if (c.isPrimitive()) {
- String t = c.getName();
- if ("void".equals(t)) {
- ret.append(JVM_VOID);
- } else if ("boolean".equals(t)) {
- ret.append(JVM_BOOLEAN);
- } else if ("byte".equals(t)) {
- ret.append(JVM_BYTE);
- } else if ("char".equals(t)) {
- ret.append(JVM_CHAR);
- } else if ("double".equals(t)) {
- ret.append(JVM_DOUBLE);
- } else if ("float".equals(t)) {
- ret.append(JVM_FLOAT);
- } else if ("int".equals(t)) {
- ret.append(JVM_INT);
- } else if ("long".equals(t)) {
- ret.append(JVM_LONG);
- } else if ("short".equals(t)) {
- ret.append(JVM_SHORT);
- }
- } else {
- ret.append('L');
- ret.append(c.getName().replace('.', '/'));
- ret.append(';');
- }
- return ret.toString();
- }
-
- /**
- * get class array desc.
- * [int.class, boolean[].class, Object.class] => "I[ZLjava/lang/Object;"
- *
- * @param cs class array.
- * @return desc.
- * @throws NotFoundException
- */
- public static String getDesc(final Class<?>[] cs) {
- if (cs.length == 0) {
- return "";
- }
-
- StringBuilder sb = new StringBuilder(64);
- for (Class<?> c : cs) {
- sb.append(getDesc(c));
- }
- return sb.toString();
- }
-
- /**
- * get method desc.
- * int do(int arg1) => "do(I)I"
- * void do(String arg1,boolean arg2) => "do(Ljava/lang/String;Z)V"
- *
- * @param m method.
- * @return desc.
- */
- public static String getDesc(final Method m) {
- StringBuilder ret = new StringBuilder(m.getName()).append('(');
- Class<?>[] parameterTypes = m.getParameterTypes();
- for (int i = 0; i < parameterTypes.length; i++) {
- ret.append(getDesc(parameterTypes[i]));
- }
- ret.append(')').append(getDesc(m.getReturnType()));
- return ret.toString();
- }
-
- /**
- * get constructor desc.
- * "()V", "(Ljava/lang/String;I)V"
- *
- * @param c constructor.
- * @return desc
- */
- public static String getDesc(final Constructor<?> c) {
- StringBuilder ret = new StringBuilder("(");
- Class<?>[] parameterTypes = c.getParameterTypes();
- for (int i = 0; i < parameterTypes.length; i++) {
- ret.append(getDesc(parameterTypes[i]));
- }
- ret.append(')').append('V');
- return ret.toString();
- }
-
- /**
- * get method desc.
- * "(I)I", "()V", "(Ljava/lang/String;Z)V"
- *
- * @param m method.
- * @return desc.
- */
- public static String getDescWithoutMethodName(Method m) {
- StringBuilder ret = new StringBuilder();
- ret.append('(');
- Class<?>[] parameterTypes = m.getParameterTypes();
- for (int i = 0; i < parameterTypes.length; i++) {
- ret.append(getDesc(parameterTypes[i]));
- }
- ret.append(')').append(getDesc(m.getReturnType()));
- return ret.toString();
- }
-
- /**
- * get class desc.
- * Object.class => "Ljava/lang/Object;"
- * boolean[].class => "[Z"
- *
- * @param c class.
- * @return desc.
- * @throws NotFoundException
- */
- public static String getDesc(final CtClass c) throws NotFoundException {
- StringBuilder ret = new StringBuilder();
- if (c.isArray()) {
- ret.append('[');
- ret.append(getDesc(c.getComponentType()));
- } else if (c.isPrimitive()) {
- String t = c.getName();
- if ("void".equals(t)) {
- ret.append(JVM_VOID);
- } else if ("boolean".equals(t)) {
- ret.append(JVM_BOOLEAN);
- } else if ("byte".equals(t)) {
- ret.append(JVM_BYTE);
- } else if ("char".equals(t)) {
- ret.append(JVM_CHAR);
- } else if ("double".equals(t)) {
- ret.append(JVM_DOUBLE);
- } else if ("float".equals(t)) {
- ret.append(JVM_FLOAT);
- } else if ("int".equals(t)) {
- ret.append(JVM_INT);
- } else if ("long".equals(t)) {
- ret.append(JVM_LONG);
- } else if ("short".equals(t)) {
- ret.append(JVM_SHORT);
- }
- } else {
- ret.append('L');
- ret.append(c.getName().replace('.', '/'));
- ret.append(';');
- }
- return ret.toString();
- }
-
- /**
- * get method desc.
- * "do(I)I", "do()V", "do(Ljava/lang/String;Z)V"
- *
- * @param m method.
- * @return desc.
- */
- public static String getDesc(final CtMethod m) throws NotFoundException {
- StringBuilder ret = new StringBuilder(m.getName()).append('(');
- CtClass[] parameterTypes = m.getParameterTypes();
- for (int i = 0; i < parameterTypes.length; i++) {
- ret.append(getDesc(parameterTypes[i]));
- }
- ret.append(')').append(getDesc(m.getReturnType()));
- return ret.toString();
- }
-
- /**
- * get constructor desc.
- * "()V", "(Ljava/lang/String;I)V"
- *
- * @param c constructor.
- * @return desc
- */
- public static String getDesc(final CtConstructor c) throws NotFoundException {
- StringBuilder ret = new StringBuilder("(");
- CtClass[] parameterTypes = c.getParameterTypes();
- for (int i = 0; i < parameterTypes.length; i++) {
- ret.append(getDesc(parameterTypes[i]));
- }
- ret.append(')').append('V');
- return ret.toString();
- }
-
- /**
- * get method desc.
- * "(I)I", "()V", "(Ljava/lang/String;Z)V".
- *
- * @param m method.
- * @return desc.
- */
- public static String getDescWithoutMethodName(final CtMethod m) throws NotFoundException {
- StringBuilder ret = new StringBuilder();
- ret.append('(');
- CtClass[] parameterTypes = m.getParameterTypes();
- for (int i = 0; i < parameterTypes.length; i++) {
- ret.append(getDesc(parameterTypes[i]));
- }
- ret.append(')').append(getDesc(m.getReturnType()));
- return ret.toString();
- }
-
- /**
- * name to desc.
- * java.util.Map[][] => "[[Ljava/util/Map;"
- *
- * @param name name.
- * @return desc.
- */
- public static String name2desc(String name) {
- StringBuilder sb = new StringBuilder();
- int c = 0, index = name.indexOf('[');
- if (index > 0) {
- c = (name.length() - index) / 2;
- name = name.substring(0, index);
- }
- while (c-- > 0) {
- sb.append("[");
- }
- if ("void".equals(name)) {
- sb.append(JVM_VOID);
- } else if ("boolean".equals(name)) {
- sb.append(JVM_BOOLEAN);
- } else if ("byte".equals(name)) {
- sb.append(JVM_BYTE);
- } else if ("char".equals(name)) {
- sb.append(JVM_CHAR);
- } else if ("double".equals(name)) {
- sb.append(JVM_DOUBLE);
- } else if ("float".equals(name)) {
- sb.append(JVM_FLOAT);
- } else if ("int".equals(name)) {
- sb.append(JVM_INT);
- } else if ("long".equals(name)) {
- sb.append(JVM_LONG);
- } else if ("short".equals(name)) {
- sb.append(JVM_SHORT);
- } else {
- sb.append('L').append(name.replace('.', '/')).append(';');
- }
- return sb.toString();
- }
-
- /**
- * desc to name.
- * "[[I" => "int[][]"
- *
- * @param desc desc.
- * @return name.
- */
- public static String desc2name(String desc) {
- StringBuilder sb = new StringBuilder();
- int c = desc.lastIndexOf('[') + 1;
- if (desc.length() == c + 1) {
- switch (desc.charAt(c)) {
- case JVM_VOID: {
- sb.append("void");
- break;
- }
- case JVM_BOOLEAN: {
- sb.append("boolean");
- break;
- }
- case JVM_BYTE: {
- sb.append("byte");
- break;
- }
- case JVM_CHAR: {
- sb.append("char");
- break;
- }
- case JVM_DOUBLE: {
- sb.append("double");
- break;
- }
- case JVM_FLOAT: {
- sb.append("float");
- break;
- }
- case JVM_INT: {
- sb.append("int");
- break;
- }
- case JVM_LONG: {
- sb.append("long");
- break;
- }
- case JVM_SHORT: {
- sb.append("short");
- break;
- }
- default:
- throw new RuntimeException();
- }
- } else {
- sb.append(desc.substring(c + 1, desc.length() - 1).replace('/', '.'));
- }
- while (c-- > 0) {
- sb.append("[]");
- }
- return sb.toString();
- }
-
- public static Class<?> forName(String name) {
- try {
- return name2class(name);
- } catch (ClassNotFoundException e) {
- throw new IllegalStateException("Not found class " + name + ", cause: " + e.getMessage(), e);
- }
- }
-
- public static Class<?> forName(ClassLoader cl, String name) {
- try {
- return name2class(cl, name);
- } catch (ClassNotFoundException e) {
- throw new IllegalStateException("Not found class " + name + ", cause: " + e.getMessage(), e);
- }
- }
-
- /**
- * name to class.
- * "boolean" => boolean.class
- * "java.util.Map[][]" => java.util.Map[][].class
- *
- * @param name name.
- * @return Class instance.
- */
- public static Class<?> name2class(String name) throws ClassNotFoundException {
- return name2class(ClassUtils.getClassLoader(), name);
- }
-
- /**
- * name to class.
- * "boolean" => boolean.class
- * "java.util.Map[][]" => java.util.Map[][].class
- *
- * @param cl ClassLoader instance.
- * @param name name.
- * @return Class instance.
- */
- private static Class<?> name2class(ClassLoader cl, String name) throws ClassNotFoundException {
- int c = 0, index = name.indexOf('[');
- if (index > 0) {
- c = (name.length() - index) / 2;
- name = name.substring(0, index);
- }
- if (c > 0) {
- StringBuilder sb = new StringBuilder();
- while (c-- > 0) {
- sb.append("[");
- }
-
- if ("void".equals(name)) {
- sb.append(JVM_VOID);
- } else if ("boolean".equals(name)) {
- sb.append(JVM_BOOLEAN);
- } else if ("byte".equals(name)) {
- sb.append(JVM_BYTE);
- } else if ("char".equals(name)) {
- sb.append(JVM_CHAR);
- } else if ("double".equals(name)) {
- sb.append(JVM_DOUBLE);
- } else if ("float".equals(name)) {
- sb.append(JVM_FLOAT);
- } else if ("int".equals(name)) {
- sb.append(JVM_INT);
- } else if ("long".equals(name)) {
- sb.append(JVM_LONG);
- } else if ("short".equals(name)) {
- sb.append(JVM_SHORT);
- } else {
- sb.append('L').append(name).append(';'); // "java.lang.Object" ==> "Ljava.lang.Object;"
- }
- name = sb.toString();
- } else {
- if ("void".equals(name)) {
- return void.class;
- } else if ("boolean".equals(name)) {
- return boolean.class;
- } else if ("byte".equals(name)) {
- return byte.class;
- } else if ("char".equals(name)) {
- return char.class;
- } else if ("double".equals(name)) {
- return double.class;
- } else if ("float".equals(name)) {
- return float.class;
- } else if ("int".equals(name)) {
- return int.class;
- } else if ("long".equals(name)) {
- return long.class;
- } else if ("short".equals(name)) {
- return short.class;
- }
- }
-
- if (cl == null) {
- cl = ClassUtils.getClassLoader();
- }
- Class<?> clazz = NAME_CLASS_CACHE.get(name);
- if (clazz == null) {
- clazz = Class.forName(name, true, cl);
- NAME_CLASS_CACHE.put(name, clazz);
- }
- return clazz;
- }
-
- /**
- * desc to class.
- * "[Z" => boolean[].class
- * "[[Ljava/util/Map;" => java.util.Map[][].class
- *
- * @param desc desc.
- * @return Class instance.
- * @throws ClassNotFoundException
- */
- public static Class<?> desc2class(String desc) throws ClassNotFoundException {
- return desc2class(ClassUtils.getClassLoader(), desc);
- }
-
- /**
- * desc to class.
- * "[Z" => boolean[].class
- * "[[Ljava/util/Map;" => java.util.Map[][].class
- *
- * @param cl ClassLoader instance.
- * @param desc desc.
- * @return Class instance.
- * @throws ClassNotFoundException
- */
- private static Class<?> desc2class(ClassLoader cl, String desc) throws ClassNotFoundException {
- switch (desc.charAt(0)) {
- case JVM_VOID:
- return void.class;
- case JVM_BOOLEAN:
- return boolean.class;
- case JVM_BYTE:
- return byte.class;
- case JVM_CHAR:
- return char.class;
- case JVM_DOUBLE:
- return double.class;
- case JVM_FLOAT:
- return float.class;
- case JVM_INT:
- return int.class;
- case JVM_LONG:
- return long.class;
- case JVM_SHORT:
- return short.class;
- case 'L':
- desc = desc.substring(1, desc.length() - 1).replace('/', '.'); // "Ljava/lang/Object;" ==> "java.lang.Object"
- break;
- case '[':
- desc = desc.replace('/', '.'); // "[[Ljava/lang/Object;" ==> "[[Ljava.lang.Object;"
- break;
- default:
- throw new ClassNotFoundException("Class not found: " + desc);
- }
-
- if (cl == null) {
- cl = ClassUtils.getClassLoader();
- }
- Class<?> clazz = DESC_CLASS_CACHE.get(desc);
- if (clazz == null) {
- clazz = Class.forName(desc, true, cl);
- DESC_CLASS_CACHE.put(desc, clazz);
- }
- return clazz;
- }
-
- /**
- * get class array instance.
- *
- * @param desc desc.
- * @return Class class array.
- * @throws ClassNotFoundException
- */
- public static Class<?>[] desc2classArray(String desc) throws ClassNotFoundException {
- Class<?>[] ret = desc2classArray(ClassUtils.getClassLoader(), desc);
- return ret;
- }
-
- /**
- * get class array instance.
- *
- * @param cl ClassLoader instance.
- * @param desc desc.
- * @return Class[] class array.
- * @throws ClassNotFoundException
- */
- private static Class<?>[] desc2classArray(ClassLoader cl, String desc) throws ClassNotFoundException {
- if (desc.length() == 0) {
- return EMPTY_CLASS_ARRAY;
- }
-
- List<Class<?>> cs = new ArrayList<Class<?>>();
- Matcher m = DESC_PATTERN.matcher(desc);
- while (m.find()) {
- cs.add(desc2class(cl, m.group()));
- }
- return cs.toArray(EMPTY_CLASS_ARRAY);
- }
-
- /**
- * Find method from method signature
- *
- * @param clazz Target class to find method
- * @param methodName Method signature, e.g.: method1(int, String). It is allowed to provide method name only, e.g.: method2
- * @return target method
- * @throws NoSuchMethodException
- * @throws ClassNotFoundException
- * @throws IllegalStateException when multiple methods are found (overridden method when parameter info is not provided)
- */
- public static Method findMethodByMethodSignature(Class<?> clazz, String methodName, String[] parameterTypes)
- throws NoSuchMethodException, ClassNotFoundException {
- String signature = clazz.getName() + "." + methodName;
- if (parameterTypes != null && parameterTypes.length > 0) {
- signature += StringUtils.join(parameterTypes);
- }
- Method method = Signature_METHODS_CACHE.get(signature);
- if (method != null) {
- return method;
- }
- if (parameterTypes == null) {
- List<Method> finded = new ArrayList<Method>();
- for (Method m : clazz.getMethods()) {
- if (m.getName().equals(methodName)) {
- finded.add(m);
- }
- }
- if (finded.isEmpty()) {
- throw new NoSuchMethodException("No such method " + methodName + " in class " + clazz);
- }
- if (finded.size() > 1) {
- String msg = String.format("Not unique method for method name(%s) in class(%s), find %d methods.",
- methodName, clazz.getName(), finded.size());
- throw new IllegalStateException(msg);
- }
- method = finded.get(0);
- } else {
- Class<?>[] types = new Class<?>[parameterTypes.length];
- for (int i = 0; i < parameterTypes.length; i++) {
- types[i] = ReflectUtils.name2class(parameterTypes[i]);
- }
- method = clazz.getMethod(methodName, types);
-
- }
- Signature_METHODS_CACHE.put(signature, method);
- return method;
- }
-
- public static Method findMethodByMethodName(Class<?> clazz, String methodName)
- throws NoSuchMethodException, ClassNotFoundException {
- return findMethodByMethodSignature(clazz, methodName, null);
- }
-
- public static Constructor<?> findConstructor(Class<?> clazz, Class<?> paramType) throws NoSuchMethodException {
- Constructor<?> targetConstructor;
- try {
- targetConstructor = clazz.getConstructor(new Class<?>[]{paramType});
- } catch (NoSuchMethodException e) {
- targetConstructor = null;
- Constructor<?>[] constructors = clazz.getConstructors();
- for (Constructor<?> constructor : constructors) {
- if (Modifier.isPublic(constructor.getModifiers())
- && constructor.getParameterTypes().length == 1
- && constructor.getParameterTypes()[0].isAssignableFrom(paramType)) {
- targetConstructor = constructor;
- break;
- }
- }
- if (targetConstructor == null) {
- throw e;
- }
- }
- return targetConstructor;
- }
-
- /**
- * Check if one object is the implementation for a given interface.
- * <p>
- * This method will not trigger classloading for the given interface, therefore it will not lead to error when
- * the given interface is not visible by the classloader
- *
- * @param obj Object to examine
- * @param interfaceClazzName The given interface
- * @return true if the object implements the given interface, otherwise return false
- */
- public static boolean isInstance(Object obj, String interfaceClazzName) {
- for (Class<?> clazz = obj.getClass();
- clazz != null && !clazz.equals(Object.class);
- clazz = clazz.getSuperclass()) {
- Class<?>[] interfaces = clazz.getInterfaces();
- for (Class<?> itf : interfaces) {
- if (itf.getName().equals(interfaceClazzName)) {
- return true;
- }
- }
- }
- return false;
- }
-
- public static Object getEmptyObject(Class<?> returnType) {
- return getEmptyObject(returnType, new HashMap<Class<?>, Object>(), 0);
- }
-
- private static Object getEmptyObject(Class<?> returnType, Map<Class<?>, Object> emptyInstances, int level) {
- if (level > 2) {
- return null;
- }
- if (returnType == null) {
- return null;
- } else if (returnType == boolean.class || returnType == Boolean.class) {
- return false;
- } else if (returnType == char.class || returnType == Character.class) {
- return '\0';
- } else if (returnType == byte.class || returnType == Byte.class) {
- return (byte) 0;
- } else if (returnType == short.class || returnType == Short.class) {
- return (short) 0;
- } else if (returnType == int.class || returnType == Integer.class) {
- return 0;
- } else if (returnType == long.class || returnType == Long.class) {
- return 0L;
- } else if (returnType == float.class || returnType == Float.class) {
- return 0F;
- } else if (returnType == double.class || returnType == Double.class) {
- return 0D;
- } else if (returnType.isArray()) {
- return Array.newInstance(returnType.getComponentType(), 0);
- } else if (returnType.isAssignableFrom(ArrayList.class)) {
- return new ArrayList<Object>(0);
- } else if (returnType.isAssignableFrom(HashSet.class)) {
- return new HashSet<Object>(0);
- } else if (returnType.isAssignableFrom(HashMap.class)) {
- return new HashMap<Object, Object>(0);
- } else if (String.class.equals(returnType)) {
- return "";
- } else if (!returnType.isInterface()) {
- try {
- Object value = emptyInstances.get(returnType);
- if (value == null) {
- value = returnType.newInstance();
- emptyInstances.put(returnType, value);
- }
- Class<?> cls = value.getClass();
- while (cls != null && cls != Object.class) {
- Field[] fields = cls.getDeclaredFields();
- for (Field field : fields) {
- if (field.isSynthetic()) {
- continue;
- }
- Object property = getEmptyObject(field.getType(), emptyInstances, level + 1);
- if (property != null) {
- try {
- if (!field.isAccessible()) {
- field.setAccessible(true);
- }
- field.set(value, property);
- } catch (Throwable e) {
- }
- }
- }
- cls = cls.getSuperclass();
- }
- return value;
- } catch (Throwable e) {
- return null;
- }
- } else {
- return null;
- }
- }
-
- public static boolean isBeanPropertyReadMethod(Method method) {
- return method != null
- && Modifier.isPublic(method.getModifiers())
- && !Modifier.isStatic(method.getModifiers())
- && method.getReturnType() != void.class
- && method.getDeclaringClass() != Object.class
- && method.getParameterTypes().length == 0
- && ((method.getName().startsWith("get") && method.getName().length() > 3)
- || (method.getName().startsWith("is") && method.getName().length() > 2));
- }
-
- public static String getPropertyNameFromBeanReadMethod(Method method) {
- if (isBeanPropertyReadMethod(method)) {
- if (method.getName().startsWith("get")) {
- return method.getName().substring(3, 4).toLowerCase()
- + method.getName().substring(4);
- }
- if (method.getName().startsWith("is")) {
- return method.getName().substring(2, 3).toLowerCase()
- + method.getName().substring(3);
- }
- }
- return null;
- }
-
- public static boolean isBeanPropertyWriteMethod(Method method) {
- return method != null
- && Modifier.isPublic(method.getModifiers())
- && !Modifier.isStatic(method.getModifiers())
- && method.getDeclaringClass() != Object.class
- && method.getParameterTypes().length == 1
- && method.getName().startsWith("set")
- && method.getName().length() > 3;
- }
-
- public static String getPropertyNameFromBeanWriteMethod(Method method) {
- if (isBeanPropertyWriteMethod(method)) {
- return method.getName().substring(3, 4).toLowerCase()
- + method.getName().substring(4);
- }
- return null;
- }
-
- public static boolean isPublicInstanceField(Field field) {
- return Modifier.isPublic(field.getModifiers())
- && !Modifier.isStatic(field.getModifiers())
- && !Modifier.isFinal(field.getModifiers())
- && !field.isSynthetic();
- }
-
- public static Map<String, Field> getBeanPropertyFields(Class cl) {
- Map<String, Field> properties = new HashMap<String, Field>();
- for (; cl != null; cl = cl.getSuperclass()) {
- Field[] fields = cl.getDeclaredFields();
- for (Field field : fields) {
- if (Modifier.isTransient(field.getModifiers())
- || Modifier.isStatic(field.getModifiers())) {
- continue;
- }
-
- field.setAccessible(true);
-
- properties.put(field.getName(), field);
- }
- }
-
- return properties;
- }
-
- public static Map<String, Method> getBeanPropertyReadMethods(Class cl) {
- Map<String, Method> properties = new HashMap<String, Method>();
- for (; cl != null; cl = cl.getSuperclass()) {
- Method[] methods = cl.getDeclaredMethods();
- for (Method method : methods) {
- if (isBeanPropertyReadMethod(method)) {
- method.setAccessible(true);
- String property = getPropertyNameFromBeanReadMethod(method);
- properties.put(property, method);
- }
- }
- }
-
- return properties;
- }
-
- public static Type[] getReturnTypes(Method method) {
- Class<?> returnType = method.getReturnType();
- Type genericReturnType = method.getGenericReturnType();
- if (Future.class.isAssignableFrom(returnType)) {
- if (genericReturnType instanceof ParameterizedType) {
- Type actualArgType = ((ParameterizedType) genericReturnType).getActualTypeArguments()[0];
- if (actualArgType instanceof ParameterizedType) {
- returnType = (Class<?>) ((ParameterizedType) actualArgType).getRawType();
- genericReturnType = actualArgType;
- } else {
- returnType = (Class<?>) actualArgType;
- genericReturnType = returnType;
- }
- } else {
- returnType = null;
- genericReturnType = null;
- }
- }
- return new Type[]{returnType, genericReturnType};
- }
+/*
+ * 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 org.apache.dubbo.common.utils;
+
+import javassist.CtClass;
+import javassist.CtConstructor;
+import javassist.CtMethod;
+import javassist.NotFoundException;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.net.URL;
+import java.security.CodeSource;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+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;
+import java.util.concurrent.Future;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.unmodifiableSet;
+
+/**
+ * ReflectUtils
+ */
+public final class ReflectUtils {
+
+ /**
+ * void(V).
+ */
+ public static final char JVM_VOID = 'V';
+
+ /**
+ * boolean(Z).
+ */
+ public static final char JVM_BOOLEAN = 'Z';
+
+ /**
+ * byte(B).
+ */
+ public static final char JVM_BYTE = 'B';
+
+ /**
+ * char(C).
+ */
+ public static final char JVM_CHAR = 'C';
+
+ /**
+ * double(D).
+ */
+ public static final char JVM_DOUBLE = 'D';
+
+ /**
+ * float(F).
+ */
+ public static final char JVM_FLOAT = 'F';
+
+ /**
+ * int(I).
+ */
+ public static final char JVM_INT = 'I';
+
+ /**
+ * long(J).
+ */
+ public static final char JVM_LONG = 'J';
+
+ /**
+ * short(S).
+ */
+ public static final char JVM_SHORT = 'S';
+
+ public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
+
+ public static final String JAVA_IDENT_REGEX = "(?:[_$a-zA-Z][_$a-zA-Z0-9]*)";
+
+ public static final String JAVA_NAME_REGEX = "(?:" + JAVA_IDENT_REGEX + "(?:\\." + JAVA_IDENT_REGEX + ")*)";
+
+ public static final String CLASS_DESC = "(?:L" + JAVA_IDENT_REGEX + "(?:\\/" + JAVA_IDENT_REGEX + ")*;)";
+
+ public static final String ARRAY_DESC = "(?:\\[+(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "))";
+
+ public static final String DESC_REGEX = "(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "|" + ARRAY_DESC + ")";
+
+ public static final Pattern DESC_PATTERN = Pattern.compile(DESC_REGEX);
+
+ public static final String METHOD_DESC_REGEX = "(?:(" + JAVA_IDENT_REGEX + ")?\\((" + DESC_REGEX + "*)\\)(" + DESC_REGEX + ")?)";
+
+ public static final Pattern METHOD_DESC_PATTERN = Pattern.compile(METHOD_DESC_REGEX);
+
+ public static final Pattern GETTER_METHOD_DESC_PATTERN = Pattern.compile("get([A-Z][_a-zA-Z0-9]*)\\(\\)(" + DESC_REGEX + ")");
+
+ public static final Pattern SETTER_METHOD_DESC_PATTERN = Pattern.compile("set([A-Z][_a-zA-Z0-9]*)\\((" + DESC_REGEX + ")\\)V");
+
+ public static final Pattern IS_HAS_CAN_METHOD_DESC_PATTERN = Pattern.compile("(?:is|has|can)([A-Z][_a-zA-Z0-9]*)\\(\\)Z");
+
+ private static final ConcurrentMap<String, Class<?>> DESC_CLASS_CACHE = new ConcurrentHashMap<String, Class<?>>();
+
+ private static final ConcurrentMap<String, Class<?>> NAME_CLASS_CACHE = new ConcurrentHashMap<String, Class<?>>();
+
+ private static final ConcurrentMap<String, Method> Signature_METHODS_CACHE = new ConcurrentHashMap<String, Method>();
+
+ private ReflectUtils() {
+ }
+
+ public static boolean isPrimitives(Class<?> cls) {
+ if (cls.isArray()) {
+ return isPrimitive(cls.getComponentType());
+ }
+ return isPrimitive(cls);
+ }
+
+ public static boolean isPrimitive(Class<?> cls) {
+ return cls.isPrimitive() || cls == String.class || cls == Boolean.class || cls == Character.class
+ || Number.class.isAssignableFrom(cls) || Date.class.isAssignableFrom(cls);
+ }
+
+ public static Class<?> getBoxedClass(Class<?> c) {
+ if (c == int.class) {
+ c = Integer.class;
+ } else if (c == boolean.class) {
+ c = Boolean.class;
+ } else if (c == long.class) {
+ c = Long.class;
+ } else if (c == float.class) {
+ c = Float.class;
+ } else if (c == double.class) {
+ c = Double.class;
+ } else if (c == char.class) {
+ c = Character.class;
+ } else if (c == byte.class) {
+ c = Byte.class;
+ } else if (c == short.class) {
+ c = Short.class;
+ }
+ return c;
+ }
+
+ /**
+ * is compatible.
+ *
+ * @param c class.
+ * @param o instance.
+ * @return compatible or not.
+ */
+ public static boolean isCompatible(Class<?> c, Object o) {
+ boolean pt = c.isPrimitive();
+ if (o == null) {
+ return !pt;
+ }
+
+ if (pt) {
+ c = getBoxedClass(c);
+ }
+
+ return c == o.getClass() || c.isInstance(o);
+ }
+
+ /**
+ * is compatible.
+ *
+ * @param cs class array.
+ * @param os object array.
+ * @return compatible or not.
+ */
+ public static boolean isCompatible(Class<?>[] cs, Object[] os) {
+ int len = cs.length;
+ if (len != os.length) {
+ return false;
+ }
+ if (len == 0) {
+ return true;
+ }
+ for (int i = 0; i < len; i++) {
+ if (!isCompatible(cs[i], os[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static String getCodeBase(Class<?> cls) {
+ if (cls == null) {
+ return null;
+ }
+ ProtectionDomain domain = cls.getProtectionDomain();
+ if (domain == null) {
+ return null;
+ }
+ CodeSource source = domain.getCodeSource();
+ if (source == null) {
+ return null;
+ }
+ URL location = source.getLocation();
+ if (location == null) {
+ return null;
+ }
+ return location.getFile();
+ }
+
+ /**
+ * get name.
+ * java.lang.Object[][].class => "java.lang.Object[][]"
+ *
+ * @param c class.
+ * @return name.
+ */
+ public static String getName(Class<?> c) {
+ if (c.isArray()) {
+ StringBuilder sb = new StringBuilder();
+ do {
+ sb.append("[]");
+ c = c.getComponentType();
+ }
+ while (c.isArray());
+
+ return c.getName() + sb.toString();
+ }
+ return c.getName();
+ }
+
+ public static Class<?> getGenericClass(Class<?> cls) {
+ return getGenericClass(cls, 0);
+ }
+
+ public static Class<?> getGenericClass(Class<?> cls, int i) {
+ try {
+ ParameterizedType parameterizedType = ((ParameterizedType) cls.getGenericInterfaces()[0]);
+ Object genericClass = parameterizedType.getActualTypeArguments()[i];
+ if (genericClass instanceof ParameterizedType) { // handle nested generic type
+ return (Class<?>) ((ParameterizedType) genericClass).getRawType();
+ } else if (genericClass instanceof GenericArrayType) { // handle array generic type
+ return (Class<?>) ((GenericArrayType) genericClass).getGenericComponentType();
+ } else if (((Class) genericClass).isArray()) {
+ // Requires JDK 7 or higher, Foo<int[]> is no longer GenericArrayType
+ return ((Class) genericClass).getComponentType();
+ } else {
+ return (Class<?>) genericClass;
+ }
+ } catch (Throwable e) {
+ throw new IllegalArgumentException(cls.getName()
+ + " generic type undefined!", e);
+ }
+ }
+
+ /**
+ * get method name.
+ * "void do(int)", "void do()", "int do(java.lang.String,boolean)"
+ *
+ * @param m method.
+ * @return name.
+ */
+ public static String getName(final Method m) {
+ StringBuilder ret = new StringBuilder();
+ ret.append(getName(m.getReturnType())).append(' ');
+ ret.append(m.getName()).append('(');
+ Class<?>[] parameterTypes = m.getParameterTypes();
+ for (int i = 0; i < parameterTypes.length; i++) {
+ if (i > 0) {
+ ret.append(',');
+ }
+ ret.append(getName(parameterTypes[i]));
+ }
+ ret.append(')');
+ return ret.toString();
+ }
+
+ public static String getSignature(String methodName, Class<?>[] parameterTypes) {
+ StringBuilder sb = new StringBuilder(methodName);
+ sb.append("(");
+ if (parameterTypes != null && parameterTypes.length > 0) {
+ boolean first = true;
+ for (Class<?> type : parameterTypes) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(",");
+ }
+ sb.append(type.getName());
+ }
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
+ /**
+ * get constructor name.
+ * "()", "(java.lang.String,int)"
+ *
+ * @param c constructor.
+ * @return name.
+ */
+ public static String getName(final Constructor<?> c) {
+ StringBuilder ret = new StringBuilder("(");
+ Class<?>[] parameterTypes = c.getParameterTypes();
+ for (int i = 0; i < parameterTypes.length; i++) {
+ if (i > 0) {
+ ret.append(',');
+ }
+ ret.append(getName(parameterTypes[i]));
+ }
+ ret.append(')');
+ return ret.toString();
+ }
+
+ /**
+ * get class desc.
+ * boolean[].class => "[Z"
+ * Object.class => "Ljava/lang/Object;"
+ *
+ * @param c class.
+ * @return desc.
+ * @throws NotFoundException
+ */
+ public static String getDesc(Class<?> c) {
+ StringBuilder ret = new StringBuilder();
+
+ while (c.isArray()) {
+ ret.append('[');
+ c = c.getComponentType();
+ }
+
+ if (c.isPrimitive()) {
+ String t = c.getName();
+ if ("void".equals(t)) {
+ ret.append(JVM_VOID);
+ } else if ("boolean".equals(t)) {
+ ret.append(JVM_BOOLEAN);
+ } else if ("byte".equals(t)) {
+ ret.append(JVM_BYTE);
+ } else if ("char".equals(t)) {
+ ret.append(JVM_CHAR);
+ } else if ("double".equals(t)) {
+ ret.append(JVM_DOUBLE);
+ } else if ("float".equals(t)) {
+ ret.append(JVM_FLOAT);
+ } else if ("int".equals(t)) {
+ ret.append(JVM_INT);
+ } else if ("long".equals(t)) {
+ ret.append(JVM_LONG);
+ } else if ("short".equals(t)) {
+ ret.append(JVM_SHORT);
+ }
+ } else {
+ ret.append('L');
+ ret.append(c.getName().replace('.', '/'));
+ ret.append(';');
+ }
+ return ret.toString();
+ }
+
+ /**
+ * get class array desc.
+ * [int.class, boolean[].class, Object.class] => "I[ZLjava/lang/Object;"
+ *
+ * @param cs class array.
+ * @return desc.
+ * @throws NotFoundException
+ */
+ public static String getDesc(final Class<?>[] cs) {
+ if (cs.length == 0) {
+ return "";
+ }
+
+ StringBuilder sb = new StringBuilder(64);
+ for (Class<?> c : cs) {
+ sb.append(getDesc(c));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * get method desc.
+ * int do(int arg1) => "do(I)I"
+ * void do(String arg1,boolean arg2) => "do(Ljava/lang/String;Z)V"
+ *
+ * @param m method.
+ * @return desc.
+ */
+ public static String getDesc(final Method m) {
+ StringBuilder ret = new StringBuilder(m.getName()).append('(');
+ Class<?>[] parameterTypes = m.getParameterTypes();
+ for (int i = 0; i < parameterTypes.length; i++) {
+ ret.append(getDesc(parameterTypes[i]));
+ }
+ ret.append(')').append(getDesc(m.getReturnType()));
+ return ret.toString();
+ }
+
+ /**
+ * get constructor desc.
+ * "()V", "(Ljava/lang/String;I)V"
+ *
+ * @param c constructor.
+ * @return desc
+ */
+ public static String getDesc(final Constructor<?> c) {
+ StringBuilder ret = new StringBuilder("(");
+ Class<?>[] parameterTypes = c.getParameterTypes();
+ for (int i = 0; i < parameterTypes.length; i++) {
+ ret.append(getDesc(parameterTypes[i]));
+ }
+ ret.append(')').append('V');
+ return ret.toString();
+ }
+
+ /**
+ * get method desc.
+ * "(I)I", "()V", "(Ljava/lang/String;Z)V"
+ *
+ * @param m method.
+ * @return desc.
+ */
+ public static String getDescWithoutMethodName(Method m) {
+ StringBuilder ret = new StringBuilder();
+ ret.append('(');
+ Class<?>[] parameterTypes = m.getParameterTypes();
+ for (int i = 0; i < parameterTypes.length; i++) {
+ ret.append(getDesc(parameterTypes[i]));
+ }
+ ret.append(')').append(getDesc(m.getReturnType()));
+ return ret.toString();
+ }
+
+ /**
+ * get class desc.
+ * Object.class => "Ljava/lang/Object;"
+ * boolean[].class => "[Z"
+ *
+ * @param c class.
+ * @return desc.
+ * @throws NotFoundException
+ */
+ public static String getDesc(final CtClass c) throws NotFoundException {
+ StringBuilder ret = new StringBuilder();
+ if (c.isArray()) {
+ ret.append('[');
+ ret.append(getDesc(c.getComponentType()));
+ } else if (c.isPrimitive()) {
+ String t = c.getName();
+ if ("void".equals(t)) {
+ ret.append(JVM_VOID);
+ } else if ("boolean".equals(t)) {
+ ret.append(JVM_BOOLEAN);
+ } else if ("byte".equals(t)) {
+ ret.append(JVM_BYTE);
+ } else if ("char".equals(t)) {
+ ret.append(JVM_CHAR);
+ } else if ("double".equals(t)) {
+ ret.append(JVM_DOUBLE);
+ } else if ("float".equals(t)) {
+ ret.append(JVM_FLOAT);
+ } else if ("int".equals(t)) {
+ ret.append(JVM_INT);
+ } else if ("long".equals(t)) {
+ ret.append(JVM_LONG);
+ } else if ("short".equals(t)) {
+ ret.append(JVM_SHORT);
+ }
+ } else {
+ ret.append('L');
+ ret.append(c.getName().replace('.', '/'));
+ ret.append(';');
+ }
+ return ret.toString();
+ }
+
+ /**
+ * get method desc.
+ * "do(I)I", "do()V", "do(Ljava/lang/String;Z)V"
+ *
+ * @param m method.
+ * @return desc.
+ */
+ public static String getDesc(final CtMethod m) throws NotFoundException {
+ StringBuilder ret = new StringBuilder(m.getName()).append('(');
+ CtClass[] parameterTypes = m.getParameterTypes();
+ for (int i = 0; i < parameterTypes.length; i++) {
+ ret.append(getDesc(parameterTypes[i]));
+ }
+ ret.append(')').append(getDesc(m.getReturnType()));
+ return ret.toString();
+ }
+
+ /**
+ * get constructor desc.
+ * "()V", "(Ljava/lang/String;I)V"
+ *
+ * @param c constructor.
+ * @return desc
+ */
+ public static String getDesc(final CtConstructor c) throws NotFoundException {
+ StringBuilder ret = new StringBuilder("(");
+ CtClass[] parameterTypes = c.getParameterTypes();
+ for (int i = 0; i < parameterTypes.length; i++) {
+ ret.append(getDesc(parameterTypes[i]));
+ }
+ ret.append(')').append('V');
+ return ret.toString();
+ }
+
+ /**
+ * get method desc.
+ * "(I)I", "()V", "(Ljava/lang/String;Z)V".
+ *
+ * @param m method.
+ * @return desc.
+ */
+ public static String getDescWithoutMethodName(final CtMethod m) throws NotFoundException {
+ StringBuilder ret = new StringBuilder();
+ ret.append('(');
+ CtClass[] parameterTypes = m.getParameterTypes();
+ for (int i = 0; i < parameterTypes.length; i++) {
+ ret.append(getDesc(parameterTypes[i]));
+ }
+ ret.append(')').append(getDesc(m.getReturnType()));
+ return ret.toString();
+ }
+
+ /**
+ * name to desc.
+ * java.util.Map[][] => "[[Ljava/util/Map;"
+ *
+ * @param name name.
+ * @return desc.
+ */
+ public static String name2desc(String name) {
+ StringBuilder sb = new StringBuilder();
+ int c = 0, index = name.indexOf('[');
+ if (index > 0) {
+ c = (name.length() - index) / 2;
+ name = name.substring(0, index);
+ }
+ while (c-- > 0) {
+ sb.append("[");
+ }
+ if ("void".equals(name)) {
+ sb.append(JVM_VOID);
+ } else if ("boolean".equals(name)) {
+ sb.append(JVM_BOOLEAN);
+ } else if ("byte".equals(name)) {
+ sb.append(JVM_BYTE);
+ } else if ("char".equals(name)) {
+ sb.append(JVM_CHAR);
+ } else if ("double".equals(name)) {
+ sb.append(JVM_DOUBLE);
+ } else if ("float".equals(name)) {
+ sb.append(JVM_FLOAT);
+ } else if ("int".equals(name)) {
+ sb.append(JVM_INT);
+ } else if ("long".equals(name)) {
+ sb.append(JVM_LONG);
+ } else if ("short".equals(name)) {
+ sb.append(JVM_SHORT);
+ } else {
+ sb.append('L').append(name.replace('.', '/')).append(';');
+ }
+ return sb.toString();
+ }
+
+ /**
+ * desc to name.
+ * "[[I" => "int[][]"
+ *
+ * @param desc desc.
+ * @return name.
+ */
+ public static String desc2name(String desc) {
+ StringBuilder sb = new StringBuilder();
+ int c = desc.lastIndexOf('[') + 1;
+ if (desc.length() == c + 1) {
+ switch (desc.charAt(c)) {
+ case JVM_VOID: {
+ sb.append("void");
+ break;
+ }
+ case JVM_BOOLEAN: {
+ sb.append("boolean");
+ break;
+ }
+ case JVM_BYTE: {
+ sb.append("byte");
+ break;
+ }
+ case JVM_CHAR: {
+ sb.append("char");
+ break;
+ }
+ case JVM_DOUBLE: {
+ sb.append("double");
+ break;
+ }
+ case JVM_FLOAT: {
+ sb.append("float");
+ break;
+ }
+ case JVM_INT: {
+ sb.append("int");
+ break;
+ }
+ case JVM_LONG: {
+ sb.append("long");
+ break;
+ }
+ case JVM_SHORT: {
+ sb.append("short");
+ break;
+ }
+ default:
+ throw new RuntimeException();
+ }
+ } else {
+ sb.append(desc.substring(c + 1, desc.length() - 1).replace('/', '.'));
+ }
+ while (c-- > 0) {
+ sb.append("[]");
+ }
+ return sb.toString();
+ }
+
+ public static Class<?> forName(String name) {
+ try {
+ return name2class(name);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException("Not found class " + name + ", cause: " + e.getMessage(), e);
+ }
+ }
+
+ public static Class<?> forName(ClassLoader cl, String name) {
+ try {
+ return name2class(cl, name);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException("Not found class " + name + ", cause: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * name to class.
+ * "boolean" => boolean.class
+ * "java.util.Map[][]" => java.util.Map[][].class
+ *
+ * @param name name.
+ * @return Class instance.
+ */
+ public static Class<?> name2class(String name) throws ClassNotFoundException {
+ return name2class(ClassUtils.getClassLoader(), name);
+ }
+
+ /**
+ * name to class.
+ * "boolean" => boolean.class
+ * "java.util.Map[][]" => java.util.Map[][].class
+ *
+ * @param cl ClassLoader instance.
+ * @param name name.
+ * @return Class instance.
+ */
+ private static Class<?> name2class(ClassLoader cl, String name) throws ClassNotFoundException {
+ int c = 0, index = name.indexOf('[');
+ if (index > 0) {
+ c = (name.length() - index) / 2;
+ name = name.substring(0, index);
+ }
+ if (c > 0) {
+ StringBuilder sb = new StringBuilder();
+ while (c-- > 0) {
+ sb.append("[");
+ }
+
+ if ("void".equals(name)) {
+ sb.append(JVM_VOID);
+ } else if ("boolean".equals(name)) {
+ sb.append(JVM_BOOLEAN);
+ } else if ("byte".equals(name)) {
+ sb.append(JVM_BYTE);
+ } else if ("char".equals(name)) {
+ sb.append(JVM_CHAR);
+ } else if ("double".equals(name)) {
+ sb.append(JVM_DOUBLE);
+ } else if ("float".equals(name)) {
+ sb.append(JVM_FLOAT);
+ } else if ("int".equals(name)) {
+ sb.append(JVM_INT);
+ } else if ("long".equals(name)) {
+ sb.append(JVM_LONG);
+ } else if ("short".equals(name)) {
+ sb.append(JVM_SHORT);
+ } else {
+ sb.append('L').append(name).append(';'); // "java.lang.Object" ==> "Ljava.lang.Object;"
+ }
+ name = sb.toString();
+ } else {
+ if ("void".equals(name)) {
+ return void.class;
+ } else if ("boolean".equals(name)) {
+ return boolean.class;
+ } else if ("byte".equals(name)) {
+ return byte.class;
+ } else if ("char".equals(name)) {
+ return char.class;
+ } else if ("double".equals(name)) {
+ return double.class;
+ } else if ("float".equals(name)) {
+ return float.class;
+ } else if ("int".equals(name)) {
+ return int.class;
+ } else if ("long".equals(name)) {
+ return long.class;
+ } else if ("short".equals(name)) {
+ return short.class;
+ }
+ }
+
+ if (cl == null) {
+ cl = ClassUtils.getClassLoader();
+ }
+ Class<?> clazz = NAME_CLASS_CACHE.get(name);
+ if (clazz == null) {
+ clazz = Class.forName(name, true, cl);
+ NAME_CLASS_CACHE.put(name, clazz);
+ }
+ return clazz;
+ }
+
+ /**
+ * desc to class.
+ * "[Z" => boolean[].class
+ * "[[Ljava/util/Map;" => java.util.Map[][].class
+ *
+ * @param desc desc.
+ * @return Class instance.
+ * @throws ClassNotFoundException
+ */
+ public static Class<?> desc2class(String desc) throws ClassNotFoundException {
+ return desc2class(ClassUtils.getClassLoader(), desc);
+ }
+
+ /**
+ * desc to class.
+ * "[Z" => boolean[].class
+ * "[[Ljava/util/Map;" => java.util.Map[][].class
+ *
+ * @param cl ClassLoader instance.
+ * @param desc desc.
+ * @return Class instance.
+ * @throws ClassNotFoundException
+ */
+ private static Class<?> desc2class(ClassLoader cl, String desc) throws ClassNotFoundException {
+ switch (desc.charAt(0)) {
+ case JVM_VOID:
+ return void.class;
+ case JVM_BOOLEAN:
+ return boolean.class;
+ case JVM_BYTE:
+ return byte.class;
+ case JVM_CHAR:
+ return char.class;
+ case JVM_DOUBLE:
+ return double.class;
+ case JVM_FLOAT:
+ return float.class;
+ case JVM_INT:
+ return int.class;
+ case JVM_LONG:
+ return long.class;
+ case JVM_SHORT:
+ return short.class;
+ case 'L':
+ desc = desc.substring(1, desc.length() - 1).replace('/', '.'); // "Ljava/lang/Object;" ==> "java.lang.Object"
+ break;
+ case '[':
+ desc = desc.replace('/', '.'); // "[[Ljava/lang/Object;" ==> "[[Ljava.lang.Object;"
+ break;
+ default:
+ throw new ClassNotFoundException("Class not found: " + desc);
+ }
+
+ if (cl == null) {
+ cl = ClassUtils.getClassLoader();
+ }
+ Class<?> clazz = DESC_CLASS_CACHE.get(desc);
+ if (clazz == null) {
+ clazz = Class.forName(desc, true, cl);
+ DESC_CLASS_CACHE.put(desc, clazz);
+ }
+ return clazz;
+ }
+
+ /**
+ * get class array instance.
+ *
+ * @param desc desc.
+ * @return Class class array.
+ * @throws ClassNotFoundException
+ */
+ public static Class<?>[] desc2classArray(String desc) throws ClassNotFoundException {
+ Class<?>[] ret = desc2classArray(ClassUtils.getClassLoader(), desc);
+ return ret;
+ }
+
+ /**
+ * get class array instance.
+ *
+ * @param cl ClassLoader instance.
+ * @param desc desc.
+ * @return Class[] class array.
+ * @throws ClassNotFoundException
+ */
+ private static Class<?>[] desc2classArray(ClassLoader cl, String desc) throws ClassNotFoundException {
+ if (desc.length() == 0) {
+ return EMPTY_CLASS_ARRAY;
+ }
+
+ List<Class<?>> cs = new ArrayList<Class<?>>();
+ Matcher m = DESC_PATTERN.matcher(desc);
+ while (m.find()) {
+ cs.add(desc2class(cl, m.group()));
+ }
+ return cs.toArray(EMPTY_CLASS_ARRAY);
+ }
+
+ /**
+ * Find method from method signature
+ *
+ * @param clazz Target class to find method
+ * @param methodName Method signature, e.g.: method1(int, String). It is allowed to provide method name only, e.g.: method2
+ * @return target method
+ * @throws NoSuchMethodException
+ * @throws ClassNotFoundException
+ * @throws IllegalStateException when multiple methods are found (overridden method when parameter info is not provided)
+ */
+ public static Method findMethodByMethodSignature(Class<?> clazz, String methodName, String[] parameterTypes)
+ throws NoSuchMethodException, ClassNotFoundException {
+ String signature = clazz.getName() + "." + methodName;
+ if (parameterTypes != null && parameterTypes.length > 0) {
+ signature += StringUtils.join(parameterTypes);
+ }
+ Method method = Signature_METHODS_CACHE.get(signature);
+ if (method != null) {
+ return method;
+ }
+ if (parameterTypes == null) {
+ List<Method> finded = new ArrayList<Method>();
+ for (Method m : clazz.getMethods()) {
+ if (m.getName().equals(methodName)) {
+ finded.add(m);
+ }
+ }
+ if (finded.isEmpty()) {
+ throw new NoSuchMethodException("No such method " + methodName + " in class " + clazz);
+ }
+ if (finded.size() > 1) {
+ String msg = String.format("Not unique method for method name(%s) in class(%s), find %d methods.",
+ methodName, clazz.getName(), finded.size());
+ throw new IllegalStateException(msg);
+ }
+ method = finded.get(0);
+ } else {
+ Class<?>[] types = new Class<?>[parameterTypes.length];
+ for (int i = 0; i < parameterTypes.length; i++) {
+ types[i] = ReflectUtils.name2class(parameterTypes[i]);
+ }
+ method = clazz.getMethod(methodName, types);
+
+ }
+ Signature_METHODS_CACHE.put(signature, method);
+ return method;
+ }
+
+ public static Method findMethodByMethodName(Class<?> clazz, String methodName)
+ throws NoSuchMethodException, ClassNotFoundException {
+ return findMethodByMethodSignature(clazz, methodName, null);
+ }
+
+ public static Constructor<?> findConstructor(Class<?> clazz, Class<?> paramType) throws NoSuchMethodException {
+ Constructor<?> targetConstructor;
+ try {
+ targetConstructor = clazz.getConstructor(new Class<?>[]{paramType});
+ } catch (NoSuchMethodException e) {
+ targetConstructor = null;
+ Constructor<?>[] constructors = clazz.getConstructors();
+ for (Constructor<?> constructor : constructors) {
+ if (Modifier.isPublic(constructor.getModifiers())
+ && constructor.getParameterTypes().length == 1
+ && constructor.getParameterTypes()[0].isAssignableFrom(paramType)) {
+ targetConstructor = constructor;
+ break;
+ }
+ }
+ if (targetConstructor == null) {
+ throw e;
+ }
+ }
+ return targetConstructor;
+ }
+
+ /**
+ * Check if one object is the implementation for a given interface.
+ * <p>
+ * This method will not trigger classloading for the given interface, therefore it will not lead to error when
+ * the given interface is not visible by the classloader
+ *
+ * @param obj Object to examine
+ * @param interfaceClazzName The given interface
+ * @return true if the object implements the given interface, otherwise return false
+ */
+ public static boolean isInstance(Object obj, String interfaceClazzName) {
+ for (Class<?> clazz = obj.getClass();
+ clazz != null && !clazz.equals(Object.class);
+ clazz = clazz.getSuperclass()) {
+ Class<?>[] interfaces = clazz.getInterfaces();
+ for (Class<?> itf : interfaces) {
+ if (itf.getName().equals(interfaceClazzName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public static Object getEmptyObject(Class<?> returnType) {
+ return getEmptyObject(returnType, new HashMap<Class<?>, Object>(), 0);
+ }
+
+ private static Object getEmptyObject(Class<?> returnType, Map<Class<?>, Object> emptyInstances, int level) {
+ if (level > 2) {
+ return null;
+ }
+ if (returnType == null) {
+ return null;
+ } else if (returnType == boolean.class || returnType == Boolean.class) {
+ return false;
+ } else if (returnType == char.class || returnType == Character.class) {
+ return '\0';
+ } else if (returnType == byte.class || returnType == Byte.class) {
+ return (byte) 0;
+ } else if (returnType == short.class || returnType == Short.class) {
+ return (short) 0;
+ } else if (returnType == int.class || returnType == Integer.class) {
+ return 0;
+ } else if (returnType == long.class || returnType == Long.class) {
+ return 0L;
+ } else if (returnType == float.class || returnType == Float.class) {
+ return 0F;
+ } else if (returnType == double.class || returnType == Double.class) {
+ return 0D;
+ } else if (returnType.isArray()) {
+ return Array.newInstance(returnType.getComponentType(), 0);
+ } else if (returnType.isAssignableFrom(ArrayList.class)) {
+ return new ArrayList<Object>(0);
+ } else if (returnType.isAssignableFrom(HashSet.class)) {
+ return new HashSet<Object>(0);
+ } else if (returnType.isAssignableFrom(HashMap.class)) {
+ return new HashMap<Object, Object>(0);
+ } else if (String.class.equals(returnType)) {
+ return "";
+ } else if (!returnType.isInterface()) {
+ try {
+ Object value = emptyInstances.get(returnType);
+ if (value == null) {
+ value = returnType.newInstance();
+ emptyInstances.put(returnType, value);
+ }
+ Class<?> cls = value.getClass();
+ while (cls != null && cls != Object.class) {
+ Field[] fields = cls.getDeclaredFields();
+ for (Field field : fields) {
+ if (field.isSynthetic()) {
+ continue;
+ }
+ Object property = getEmptyObject(field.getType(), emptyInstances, level + 1);
+ if (property != null) {
+ try {
+ if (!field.isAccessible()) {
+ field.setAccessible(true);
+ }
+ field.set(value, property);
+ } catch (Throwable e) {
+ }
+ }
+ }
+ cls = cls.getSuperclass();
+ }
+ return value;
+ } catch (Throwable e) {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ public static boolean isBeanPropertyReadMethod(Method method) {
+ return method != null
+ && Modifier.isPublic(method.getModifiers())
+ && !Modifier.isStatic(method.getModifiers())
+ && method.getReturnType() != void.class
+ && method.getDeclaringClass() != Object.class
+ && method.getParameterTypes().length == 0
+ && ((method.getName().startsWith("get") && method.getName().length() > 3)
+ || (method.getName().startsWith("is") && method.getName().length() > 2));
+ }
+
+ public static String getPropertyNameFromBeanReadMethod(Method method) {
+ if (isBeanPropertyReadMethod(method)) {
+ if (method.getName().startsWith("get")) {
+ return method.getName().substring(3, 4).toLowerCase()
+ + method.getName().substring(4);
+ }
+ if (method.getName().startsWith("is")) {
+ return method.getName().substring(2, 3).toLowerCase()
+ + method.getName().substring(3);
+ }
+ }
+ return null;
+ }
+
+ public static boolean isBeanPropertyWriteMethod(Method method) {
+ return method != null
+ && Modifier.isPublic(method.getModifiers())
+ && !Modifier.isStatic(method.getModifiers())
+ && method.getDeclaringClass() != Object.class
+ && method.getParameterTypes().length == 1
+ && method.getName().startsWith("set")
+ && method.getName().length() > 3;
+ }
+
+ public static String getPropertyNameFromBeanWriteMethod(Method method) {
+ if (isBeanPropertyWriteMethod(method)) {
+ return method.getName().substring(3, 4).toLowerCase()
+ + method.getName().substring(4);
+ }
+ return null;
+ }
+
+ public static boolean isPublicInstanceField(Field field) {
+ return Modifier.isPublic(field.getModifiers())
+ && !Modifier.isStatic(field.getModifiers())
+ && !Modifier.isFinal(field.getModifiers())
+ && !field.isSynthetic();
+ }
+
+ public static Map<String, Field> getBeanPropertyFields(Class cl) {
+ Map<String, Field> properties = new HashMap<String, Field>();
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Field[] fields = cl.getDeclaredFields();
+ for (Field field : fields) {
+ if (Modifier.isTransient(field.getModifiers())
+ || Modifier.isStatic(field.getModifiers())) {
+ continue;
+ }
+
+ field.setAccessible(true);
+
+ properties.put(field.getName(), field);
+ }
+ }
+
+ return properties;
+ }
+
+ public static Map<String, Method> getBeanPropertyReadMethods(Class cl) {
+ Map<String, Method> properties = new HashMap<String, Method>();
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Method[] methods = cl.getDeclaredMethods();
+ for (Method method : methods) {
+ if (isBeanPropertyReadMethod(method)) {
+ method.setAccessible(true);
+ String property = getPropertyNameFromBeanReadMethod(method);
+ properties.put(property, method);
+ }
+ }
+ }
+
+ return properties;
+ }
+
+ public static Type[] getReturnTypes(Method method) {
+ Class<?> returnType = method.getReturnType();
+ Type genericReturnType = method.getGenericReturnType();
+ if (Future.class.isAssignableFrom(returnType)) {
+ if (genericReturnType instanceof ParameterizedType) {
+ Type actualArgType = ((ParameterizedType) genericReturnType).getActualTypeArguments()[0];
+ if (actualArgType instanceof ParameterizedType) {
+ returnType = (Class<?>) ((ParameterizedType) actualArgType).getRawType();
+ genericReturnType = actualArgType;
+ } else {
+ returnType = (Class<?>) actualArgType;
+ genericReturnType = returnType;
+ }
+ } else {
+ returnType = null;
+ genericReturnType = null;
+ }
+ }
+ return new Type[]{returnType, genericReturnType};
+ }
+
+ /**
+ * Find the {@link Set} of {@link ParameterizedType}
+ *
+ * @param sourceClass the source {@link Class class}
+ * @return non-null read-only {@link Set}
+ * @since 2.7.3
+ */
+ public static Set<ParameterizedType> findParameterizedTypes(Class<?> sourceClass) {
+ // Add Generic Interfaces
+ List<Type> genericTypes = new LinkedList<>(asList(sourceClass.getGenericInterfaces()));
+ // Add Generic Super Class
+ genericTypes.add(sourceClass.getGenericSuperclass());
+
+ Set<ParameterizedType> parameterizedTypes = genericTypes.stream()
+ .filter(type -> type instanceof ParameterizedType)// filter ParameterizedType
+ .map(type -> ParameterizedType.class.cast(type)) // cast to ParameterizedType
+ .collect(Collectors.toSet());
+
+ if (parameterizedTypes.isEmpty()) { // If not found, try to search super types recursively
+ genericTypes.stream()
+ .filter(type -> type instanceof Class)
+ .map(type -> Class.class.cast(type))
+ .forEach(superClass -> {
+ parameterizedTypes.addAll(findParameterizedTypes(superClass));
+ });
+ }
+
+ return unmodifiableSet(parameterizedTypes); // build as a Set
+
+ }
+
+ /**
+ * Find the hierarchical types form the source {@link Class class} by specified {@link Class type}.
+ *
+ * @param sourceClass the source {@link Class class}
+ * @param matchType the type to match
+ * @param <T> the type to match
+ * @return non-null read-only {@link Set}
+ * @since 2.7.3
+ */
+ public static <T> Set<Class<T>> findHierarchicalTypes(Class<?> sourceClass, Class<T> matchType) {
+ if (sourceClass == null) {
+ return Collections.emptySet();
+ }
+
+ Set<Class<T>> hierarchicalTypes = new LinkedHashSet<>();
+
+ if (matchType.isAssignableFrom(sourceClass)) {
+ hierarchicalTypes.add((Class<T>) sourceClass);
+ }
+
+ // Find all super classes
+ hierarchicalTypes.addAll(findHierarchicalTypes(sourceClass.getSuperclass(), matchType));
+
+ return unmodifiableSet(hierarchicalTypes);
+ }
}
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java
index 56e73cb..548c48f 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java
@@ -30,19 +30,19 @@ import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.CLASSIFIER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_SPLIT_PATTERN;
import static org.apache.dubbo.common.constants.CommonConstants.REMOVE_VALUE_PREFIX;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
-import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java
similarity index 69%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java
index c5bc722..3e6296b 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java
@@ -14,24 +14,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.api;
+package org.apache.dubbo.common.utils;
+
+import org.junit.jupiter.api.Test;
import java.util.List;
+import static java.util.Arrays.asList;
/**
- * DemoService
+ * {@link DefaultPage}
+ *
+ * @since 2.7.3
*/
-public interface DemoService {
-
- String sayName(String name);
-
- Box getBox();
-
- void throwDemoException() throws DemoException;
-
- List<User> getUsers(List<User> users);
-
- int echo(int i);
-
-}
\ No newline at end of file
+public class DefaultPageTest {
+
+ @Test
+ public void test() {
+ List<Integer> data = asList(1, 2, 3, 4, 5);
+ DefaultPage page = new DefaultPage(0, 1, data.subList(0, 1), data.size());
+ }
+}
diff --git a/dubbo-compatible/src/test/java/org/apache/dubbo/filter/LegacyInvocation.java b/dubbo-compatible/src/test/java/org/apache/dubbo/filter/LegacyInvocation.java
index a98f22e..cd1cc17 100644
--- a/dubbo-compatible/src/test/java/org/apache/dubbo/filter/LegacyInvocation.java
+++ b/dubbo-compatible/src/test/java/org/apache/dubbo/filter/LegacyInvocation.java
@@ -23,11 +23,11 @@ import com.alibaba.dubbo.rpc.Invoker;
import java.util.HashMap;
import java.util.Map;
-import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
+import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
/**
diff --git a/dubbo-config/dubbo-config-api/pom.xml b/dubbo-config/dubbo-config-api/pom.xml
index 3a4584d..b8f5938 100644
--- a/dubbo-config/dubbo-config-api/pom.xml
+++ b/dubbo-config/dubbo-config-api/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>org.apache.dubbo</groupId>
@@ -64,6 +65,13 @@
<artifactId>dubbo-filter-cache</artifactId>
<version>${project.parent.version}</version>
</dependency>
+
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-metadata</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+
<!-- FIXME, we shouldn't rely on these modules, even in test scope -->
<dependency>
<groupId>org.apache.dubbo</groupId>
@@ -71,17 +79,55 @@
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-remoting-netty4</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-rpc-dubbo</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-multicast</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
+
+ <!-- Zookeeper Registry -->
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-registry-zookeeper</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- Zookeeper configcenter -->
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-configcenter-zookeeper</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-serialization-hessian2</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.curator</groupId>
+ <artifactId>curator-test</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
index b725608..8130a5f 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
@@ -53,31 +53,30 @@ import java.util.Map;
import java.util.Set;
import static org.apache.dubbo.common.config.ConfigurationUtils.parseProperties;
-import static org.apache.dubbo.rpc.cluster.Constants.TAG_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
+import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_SECONDS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;
+import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.config.Constants.LAYER_KEY;
import static org.apache.dubbo.config.Constants.LISTENER_KEY;
-import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
-import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;
import static org.apache.dubbo.config.Constants.REGISTRIES_SUFFIX;
-import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_SECONDS_KEY;
import static org.apache.dubbo.monitor.Constants.LOGSTAT_PROTOCOL;
+import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;
import static org.apache.dubbo.registry.Constants.REGISTER_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;
import static org.apache.dubbo.registry.Constants.SUBSCRIBE_KEY;
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
import static org.apache.dubbo.rpc.Constants.INVOKER_LISTENER_KEY;
@@ -86,7 +85,8 @@ import static org.apache.dubbo.rpc.Constants.PROXY_KEY;
import static org.apache.dubbo.rpc.Constants.REFERENCE_FILTER_KEY;
import static org.apache.dubbo.rpc.Constants.RETURN_PREFIX;
import static org.apache.dubbo.rpc.Constants.THROW_PREFIX;
-import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
+import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.TAG_KEY;
/**
* AbstractDefaultConfig
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java
index 47c035e..309f907 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java
@@ -19,6 +19,8 @@ package org.apache.dubbo.config;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.config.event.DubboServiceDestroyedEvent;
+import org.apache.dubbo.event.EventDispatcher;
import org.apache.dubbo.registry.support.AbstractRegistryFactory;
import org.apache.dubbo.rpc.Protocol;
@@ -42,7 +44,9 @@ public class DubboShutdownHook extends Thread {
/**
* Has it already been destroyed or not?
*/
- private final AtomicBoolean destroyed= new AtomicBoolean(false);
+ private final AtomicBoolean destroyed = new AtomicBoolean(false);
+
+ private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension();
private DubboShutdownHook(String name) {
super(name);
@@ -89,6 +93,8 @@ public class DubboShutdownHook extends Thread {
AbstractRegistryFactory.destroyAll();
// destroy all the protocols
destroyProtocols();
+ // dispatch the DubboDestroyedEvent @since 2.7.3
+ eventDispatcher.dispatch(new DubboServiceDestroyedEvent(this));
}
/**
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java
index c3dcf0c..18c4d17 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java
@@ -32,12 +32,12 @@ import org.apache.dubbo.rpc.Protocol;
import java.util.Map;
-import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
import static org.apache.dubbo.config.Constants.PROTOCOLS_SUFFIX;
-import static org.apache.dubbo.remoting.Constants.TELNET;
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
+import static org.apache.dubbo.remoting.Constants.TELNET;
/**
* ProtocolConfig
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
index a3c020c..ee2e9b6 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
@@ -1,664 +1,691 @@
-/*
- * 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 org.apache.dubbo.config;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.Version;
-import org.apache.dubbo.common.bytecode.Wrapper;
-import org.apache.dubbo.common.extension.ExtensionLoader;
-import org.apache.dubbo.common.utils.ClassUtils;
-import org.apache.dubbo.common.utils.CollectionUtils;
-import org.apache.dubbo.common.utils.ConfigUtils;
-import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.config.annotation.Reference;
-import org.apache.dubbo.config.context.ConfigManager;
-import org.apache.dubbo.config.support.Parameter;
-import org.apache.dubbo.metadata.integration.MetadataReportService;
-import org.apache.dubbo.remoting.Constants;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Protocol;
-import org.apache.dubbo.rpc.ProxyFactory;
-import org.apache.dubbo.rpc.cluster.Cluster;
-import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
-import org.apache.dubbo.rpc.cluster.support.ClusterUtils;
-import org.apache.dubbo.rpc.cluster.support.RegistryAwareCluster;
-import org.apache.dubbo.rpc.model.ApplicationModel;
-import org.apache.dubbo.rpc.model.ConsumerModel;
-import org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol;
-import org.apache.dubbo.rpc.service.GenericService;
-import org.apache.dubbo.rpc.support.ProtocolUtils;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
-import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;
-import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
-import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
-import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.SEMICOLON_SPLIT_PATTERN;
-import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
-import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY;
-import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
-import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;
-import static org.apache.dubbo.registry.Constants.CONSUMER_PROTOCOL;
-import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;
-import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
-import static org.apache.dubbo.common.utils.NetUtils.isInvalidLocalHost;
-
-/**
- * ReferenceConfig
- *
- * @export
- */
-public class ReferenceConfig<T> extends AbstractReferenceConfig {
-
- private static final long serialVersionUID = -5864351140409987595L;
-
- /**
- * The {@link Protocol} implementation with adaptive functionality,it will be different in different scenarios.
- * A particular {@link Protocol} implementation is determined by the protocol attribute in the {@link URL}.
- * For example:
- *
- * <li>when the url is registry://224.5.6.7:1234/org.apache.dubbo.registry.RegistryService?application=dubbo-sample,
- * then the protocol is <b>RegistryProtocol</b></li>
- *
- * <li>when the url is dubbo://224.5.6.7:1234/org.apache.dubbo.config.api.DemoService?application=dubbo-sample, then
- * the protocol is <b>DubboProtocol</b></li>
- * <p>
- * Actually,when the {@link ExtensionLoader} init the {@link Protocol} instants,it will automatically wraps two
- * layers, and eventually will get a <b>ProtocolFilterWrapper</b> or <b>ProtocolListenerWrapper</b>
- */
- private static final Protocol REF_PROTOCOL = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
-
- /**
- * The {@link Cluster}'s implementation with adaptive functionality, and actually it will get a {@link Cluster}'s
- * specific implementation who is wrapped with <b>MockClusterInvoker</b>
- */
- private static final Cluster CLUSTER = ExtensionLoader.getExtensionLoader(Cluster.class).getAdaptiveExtension();
-
- /**
- * A {@link ProxyFactory} implementation that will generate a reference service's proxy,the JavassistProxyFactory is
- * its default implementation
- */
- private static final ProxyFactory PROXY_FACTORY = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
-
- /**
- * The url of the reference service
- */
- private final List<URL> urls = new ArrayList<URL>();
-
- /**
- * The interface name of the reference service
- */
- private String interfaceName;
-
- /**
- * The interface class of the reference service
- */
- private Class<?> interfaceClass;
-
- /**
- * client type
- */
- private String client;
-
- /**
- * The url for peer-to-peer invocation
- */
- private String url;
-
- /**
- * The method configs
- */
- private List<MethodConfig> methods;
-
- /**
- * The consumer config (default)
- */
- private ConsumerConfig consumer;
-
- /**
- * Only the service provider of the specified protocol is invoked, and other protocols are ignored.
- */
- private String protocol;
-
- /**
- * The interface proxy reference
- */
- private transient volatile T ref;
-
- /**
- * The invoker of the reference service
- */
- private transient volatile Invoker<?> invoker;
-
- /**
- * The flag whether the ReferenceConfig has been initialized
- */
- private transient volatile boolean initialized;
-
- /**
- * whether this ReferenceConfig has been destroyed
- */
- private transient volatile boolean destroyed;
-
- @SuppressWarnings("unused")
- private final Object finalizerGuardian = new Object() {
- @Override
- protected void finalize() throws Throwable {
- super.finalize();
-
- if (!ReferenceConfig.this.destroyed) {
- logger.warn("ReferenceConfig(" + url + ") is not DESTROYED when FINALIZE");
-
- /* don't destroy for now
- try {
- ReferenceConfig.this.destroy();
- } catch (Throwable t) {
- logger.warn("Unexpected err when destroy invoker of ReferenceConfig(" + url + ") in finalize method!", t);
- }
- */
- }
- }
- };
-
- public ReferenceConfig() {
- }
-
- public ReferenceConfig(Reference reference) {
- appendAnnotation(Reference.class, reference);
- setMethods(MethodConfig.constructMethodConfig(reference.methods()));
- }
-
- public URL toUrl() {
- return urls.isEmpty() ? null : urls.iterator().next();
- }
-
- public List<URL> toUrls() {
- return urls;
- }
-
- /**
- * This method should be called right after the creation of this class's instance, before any property in other config modules is used.
- * Check each config modules are created properly and override their properties if necessary.
- */
- public void checkAndUpdateSubConfigs() {
- if (StringUtils.isEmpty(interfaceName)) {
- throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!");
- }
- completeCompoundConfigs();
- startConfigCenter();
- // get consumer's global configuration
- checkDefault();
- this.refresh();
- if (getGeneric() == null && getConsumer() != null) {
- setGeneric(getConsumer().getGeneric());
- }
- if (ProtocolUtils.isGeneric(getGeneric())) {
- interfaceClass = GenericService.class;
- } else {
- try {
- interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
- .getContextClassLoader());
- } catch (ClassNotFoundException e) {
- throw new IllegalStateException(e.getMessage(), e);
- }
- checkInterfaceAndMethods(interfaceClass, methods);
- }
- resolveFile();
- checkApplication();
- checkMetadataReport();
- }
-
- public synchronized T get() {
- checkAndUpdateSubConfigs();
-
- if (destroyed) {
- throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
- }
- if (ref == null) {
- init();
- }
- return ref;
- }
-
- public synchronized void destroy() {
- if (ref == null) {
- return;
- }
- if (destroyed) {
- return;
- }
- destroyed = true;
- try {
- invoker.destroy();
- } catch (Throwable t) {
- logger.warn("Unexpected error occured when destroy invoker of ReferenceConfig(" + url + ").", t);
- }
- invoker = null;
- ref = null;
- }
-
- private void init() {
- if (initialized) {
- return;
- }
- checkStubAndLocal(interfaceClass);
- checkMock(interfaceClass);
- Map<String, String> map = new HashMap<String, String>();
-
- map.put(SIDE_KEY, CONSUMER_SIDE);
-
- appendRuntimeParameters(map);
- if (!isGeneric()) {
- String revision = Version.getVersion(interfaceClass, version);
- if (revision != null && revision.length() > 0) {
- map.put(REVISION_KEY, revision);
- }
-
- String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
- if (methods.length == 0) {
- logger.warn("No method found in service interface " + interfaceClass.getName());
- map.put(METHODS_KEY, ANY_VALUE);
- } else {
- map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), COMMA_SEPARATOR));
- }
- }
- map.put(INTERFACE_KEY, interfaceName);
- appendParameters(map, metrics);
- appendParameters(map, application);
- appendParameters(map, module);
- // remove 'default.' prefix for configs from ConsumerConfig
- // appendParameters(map, consumer, Constants.DEFAULT_KEY);
- appendParameters(map, consumer);
- appendParameters(map, this);
- Map<String, Object> attributes = null;
- if (CollectionUtils.isNotEmpty(methods)) {
- attributes = new HashMap<String, Object>();
- for (MethodConfig methodConfig : methods) {
- appendParameters(map, methodConfig, methodConfig.getName());
- String retryKey = methodConfig.getName() + ".retry";
- if (map.containsKey(retryKey)) {
- String retryValue = map.remove(retryKey);
- if ("false".equals(retryValue)) {
- map.put(methodConfig.getName() + ".retries", "0");
- }
- }
- attributes.put(methodConfig.getName(), convertMethodConfig2AyncInfo(methodConfig));
- }
- }
-
- String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY);
- if (StringUtils.isEmpty(hostToRegistry)) {
- hostToRegistry = NetUtils.getLocalHost();
- } else if (isInvalidLocalHost(hostToRegistry)) {
- throw new IllegalArgumentException("Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
- }
- map.put(REGISTER_IP_KEY, hostToRegistry);
-
- ref = createProxy(map);
-
- String serviceKey = URL.buildKey(interfaceName, group, version);
- ApplicationModel.initConsumerModel(serviceKey, buildConsumerModel(serviceKey, attributes));
- initialized = true;
- }
-
- private ConsumerModel buildConsumerModel(String serviceKey, Map<String, Object> attributes) {
- Method[] methods = interfaceClass.getMethods();
- Class serviceInterface = interfaceClass;
- if (interfaceClass == GenericService.class) {
- try {
- serviceInterface = Class.forName(interfaceName);
- methods = serviceInterface.getMethods();
- } catch (ClassNotFoundException e) {
- methods = interfaceClass.getMethods();
- }
- }
- return new ConsumerModel(serviceKey, serviceInterface, ref, methods, attributes);
- }
-
- @SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
- private T createProxy(Map<String, String> map) {
- if (shouldJvmRefer(map)) {
- URL url = new URL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(map);
- invoker = REF_PROTOCOL.refer(interfaceClass, url);
- if (logger.isInfoEnabled()) {
- logger.info("Using injvm service " + interfaceClass.getName());
- }
- } else {
- urls.clear(); // reference retry init will add url to urls, lead to OOM
- if (url != null && url.length() > 0) { // user specified URL, could be peer-to-peer address, or register center's address.
- String[] us = SEMICOLON_SPLIT_PATTERN.split(url);
- if (us != null && us.length > 0) {
- for (String u : us) {
- URL url = URL.valueOf(u);
- if (StringUtils.isEmpty(url.getPath())) {
- url = url.setPath(interfaceName);
- }
- if (REGISTRY_PROTOCOL.equals(url.getProtocol())) {
- urls.add(url.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
- } else {
- urls.add(ClusterUtils.mergeUrl(url, map));
- }
- }
- }
- } else { // assemble URL from register center's configuration
- // if protocols not injvm checkRegistry
- if (!LOCAL_PROTOCOL.equalsIgnoreCase(getProtocol())){
- checkRegistry();
- List<URL> us = loadRegistries(false);
- if (CollectionUtils.isNotEmpty(us)) {
- for (URL u : us) {
- URL monitorUrl = loadMonitor(u);
- if (monitorUrl != null) {
- map.put(MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
- }
- urls.add(u.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
- }
- }
- if (urls.isEmpty()) {
- throw new IllegalStateException("No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config <dubbo:registry address=\"...\" /> to your spring config.");
- }
- }
- }
-
- if (urls.size() == 1) {
- invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));
- } else {
- List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
- URL registryURL = null;
- for (URL url : urls) {
- invokers.add(REF_PROTOCOL.refer(interfaceClass, url));
- if (REGISTRY_PROTOCOL.equals(url.getProtocol())) {
- registryURL = url; // use last registry url
- }
- }
- if (registryURL != null) { // registry url is available
- // use RegistryAwareCluster only when register's CLUSTER is available
- URL u = registryURL.addParameter(CLUSTER_KEY, RegistryAwareCluster.NAME);
- // The invoker wrap relation would be: RegistryAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker(RegistryDirectory, will execute route) -> Invoker
- invoker = CLUSTER.join(new StaticDirectory(u, invokers));
- } else { // not a registry url, must be direct invoke.
- invoker = CLUSTER.join(new StaticDirectory(invokers));
- }
- }
- }
-
- if (shouldCheck() && !invoker.isAvailable()) {
- throw new IllegalStateException("Failed to check the status of the service " + interfaceName + ". No provider available for the service " + (group == null ? "" : group + "/") + interfaceName + (version == null ? "" : ":" + version) + " from the url " + invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion());
- }
- if (logger.isInfoEnabled()) {
- logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl());
- }
- /**
- * @since 2.7.0
- * ServiceData Store
- */
- MetadataReportService metadataReportService = null;
- if ((metadataReportService = getMetadataReportService()) != null) {
- URL consumerURL = new URL(CONSUMER_PROTOCOL, map.remove(REGISTER_IP_KEY), 0, map.get(INTERFACE_KEY), map);
- metadataReportService.publishConsumer(consumerURL);
- }
- // create service proxy
- return (T) PROXY_FACTORY.getProxy(invoker);
- }
-
- /**
- * Figure out should refer the service in the same JVM from configurations. The default behavior is true
- * 1. if injvm is specified, then use it
- * 2. then if a url is specified, then assume it's a remote call
- * 3. otherwise, check scope parameter
- * 4. if scope is not specified but the target service is provided in the same JVM, then prefer to make the local
- * call, which is the default behavior
- */
- protected boolean shouldJvmRefer(Map<String, String> map) {
- URL tmpUrl = new URL("temp", "localhost", 0, map);
- boolean isJvmRefer;
- if (isInjvm() == null) {
- // if a url is specified, don't do local reference
- if (url != null && url.length() > 0) {
- isJvmRefer = false;
- } else {
- // by default, reference local service if there is
- isJvmRefer = InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl);
- }
- } else {
- isJvmRefer = isInjvm();
- }
- return isJvmRefer;
- }
-
- protected boolean shouldCheck() {
- Boolean shouldCheck = isCheck();
- if (shouldCheck == null && getConsumer() != null) {
- shouldCheck = getConsumer().isCheck();
- }
- if (shouldCheck == null) {
- // default true
- shouldCheck = true;
- }
- return shouldCheck;
- }
-
- protected boolean shouldInit() {
- Boolean shouldInit = isInit();
- if (shouldInit == null && getConsumer() != null) {
- shouldInit = getConsumer().isInit();
- }
- if (shouldInit == null) {
- // default is false
- return false;
- }
- return shouldInit;
- }
-
- private void checkDefault() {
- if (consumer != null) {
- return;
- }
- setConsumer(ConfigManager.getInstance().getDefaultConsumer().orElseGet(() -> {
- ConsumerConfig consumerConfig = new ConsumerConfig();
- consumerConfig.refresh();
- return consumerConfig;
- }));
- }
-
- private void completeCompoundConfigs() {
- if (consumer != null) {
- if (application == null) {
- setApplication(consumer.getApplication());
- }
- if (module == null) {
- setModule(consumer.getModule());
- }
- if (registries == null) {
- setRegistries(consumer.getRegistries());
- }
- if (monitor == null) {
- setMonitor(consumer.getMonitor());
- }
- }
- if (module != null) {
- if (registries == null) {
- setRegistries(module.getRegistries());
- }
- if (monitor == null) {
- setMonitor(module.getMonitor());
- }
- }
- if (application != null) {
- if (registries == null) {
- setRegistries(application.getRegistries());
- }
- if (monitor == null) {
- setMonitor(application.getMonitor());
- }
- }
- }
-
- public Class<?> getInterfaceClass() {
- if (interfaceClass != null) {
- return interfaceClass;
- }
- if (isGeneric()
- || (getConsumer() != null && getConsumer().isGeneric())) {
- return GenericService.class;
- }
- try {
- if (interfaceName != null && interfaceName.length() > 0) {
- this.interfaceClass = Class.forName(interfaceName, true, ClassUtils.getClassLoader());
- }
- } catch (ClassNotFoundException t) {
- throw new IllegalStateException(t.getMessage(), t);
- }
- return interfaceClass;
- }
-
- /**
- * @param interfaceClass
- * @see #setInterface(Class)
- * @deprecated
- */
- @Deprecated
- public void setInterfaceClass(Class<?> interfaceClass) {
- setInterface(interfaceClass);
- }
-
- public String getInterface() {
- return interfaceName;
- }
-
- public void setInterface(String interfaceName) {
- this.interfaceName = interfaceName;
- if (StringUtils.isEmpty(id)) {
- id = interfaceName;
- }
- }
-
- public void setInterface(Class<?> interfaceClass) {
- if (interfaceClass != null && !interfaceClass.isInterface()) {
- throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!");
- }
- this.interfaceClass = interfaceClass;
- setInterface(interfaceClass == null ? null : interfaceClass.getName());
- }
-
- public String getClient() {
- return client;
- }
-
- public void setClient(String client) {
- checkName(Constants.CLIENT_KEY, client);
- this.client = client;
- }
-
- @Parameter(excluded = true)
- public String getUrl() {
- return url;
- }
-
- public void setUrl(String url) {
- this.url = url;
- }
-
- public List<MethodConfig> getMethods() {
- return methods;
- }
-
- @SuppressWarnings("unchecked")
- public void setMethods(List<? extends MethodConfig> methods) {
- this.methods = (List<MethodConfig>) methods;
- }
-
- public ConsumerConfig getConsumer() {
- return consumer;
- }
-
- public void setConsumer(ConsumerConfig consumer) {
- ConfigManager.getInstance().addConsumer(consumer);
- this.consumer = consumer;
- }
-
- public String getProtocol() {
- return protocol;
- }
-
- public void setProtocol(String protocol) {
- this.protocol = protocol;
- }
-
- // just for test
- Invoker<?> getInvoker() {
- return invoker;
- }
-
- @Override
- @Parameter(excluded = true)
- public String getPrefix() {
- return DUBBO + ".reference." + interfaceName;
- }
-
- private void resolveFile() {
- String resolve = System.getProperty(interfaceName);
- String resolveFile = null;
- if (StringUtils.isEmpty(resolve)) {
- resolveFile = System.getProperty("dubbo.resolve.file");
- if (StringUtils.isEmpty(resolveFile)) {
- File userResolveFile = new File(new File(System.getProperty("user.home")), "dubbo-resolve.properties");
- if (userResolveFile.exists()) {
- resolveFile = userResolveFile.getAbsolutePath();
- }
- }
- if (resolveFile != null && resolveFile.length() > 0) {
- Properties properties = new Properties();
- try (FileInputStream fis = new FileInputStream(new File(resolveFile))) {
- properties.load(fis);
- } catch (IOException e) {
- throw new IllegalStateException("Failed to load " + resolveFile + ", cause: " + e.getMessage(), e);
- }
-
- resolve = properties.getProperty(interfaceName);
- }
- }
- if (resolve != null && resolve.length() > 0) {
- url = resolve;
- if (logger.isWarnEnabled()) {
- if (resolveFile != null) {
- logger.warn("Using default dubbo resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service.");
- } else {
- logger.warn("Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service.");
- }
- }
- }
- }
-}
+/*
+ * 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 org.apache.dubbo.config;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.Version;
+import org.apache.dubbo.common.bytecode.Wrapper;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.utils.ClassUtils;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.common.utils.ConfigUtils;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.config.annotation.Reference;
+import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.config.event.ReferenceConfigDestroyedEvent;
+import org.apache.dubbo.config.event.ReferenceConfigInitializedEvent;
+import org.apache.dubbo.config.support.Parameter;
+import org.apache.dubbo.event.Event;
+import org.apache.dubbo.event.EventDispatcher;
+import org.apache.dubbo.metadata.integration.MetadataReportService;
+import org.apache.dubbo.remoting.Constants;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Protocol;
+import org.apache.dubbo.rpc.ProxyFactory;
+import org.apache.dubbo.rpc.cluster.Cluster;
+import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
+import org.apache.dubbo.rpc.cluster.support.ClusterUtils;
+import org.apache.dubbo.rpc.cluster.support.RegistryAwareCluster;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.ConsumerModel;
+import org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol;
+import org.apache.dubbo.rpc.service.GenericService;
+import org.apache.dubbo.rpc.support.ProtocolUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
+import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;
+import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
+import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
+import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.SEMICOLON_SPLIT_PATTERN;
+import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;
+import static org.apache.dubbo.common.utils.NetUtils.isInvalidLocalHost;
+import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY;
+import static org.apache.dubbo.registry.Constants.CONSUMER_PROTOCOL;
+import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;
+import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
+import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
+
+/**
+ * ReferenceConfig
+ *
+ * @export
+ */
+public class ReferenceConfig<T> extends AbstractReferenceConfig {
+
+ private static final long serialVersionUID = -5864351140409987595L;
+
+ /**
+ * The {@link Protocol} implementation with adaptive functionality,it will be different in different scenarios.
+ * A particular {@link Protocol} implementation is determined by the protocol attribute in the {@link URL}.
+ * For example:
+ *
+ * <li>when the url is registry://224.5.6.7:1234/org.apache.dubbo.registry.RegistryService?application=dubbo-sample,
+ * then the protocol is <b>RegistryProtocol</b></li>
+ *
+ * <li>when the url is dubbo://224.5.6.7:1234/org.apache.dubbo.config.api.DemoService?application=dubbo-sample, then
+ * the protocol is <b>DubboProtocol</b></li>
+ * <p>
+ * Actually,when the {@link ExtensionLoader} init the {@link Protocol} instants,it will automatically wraps two
+ * layers, and eventually will get a <b>ProtocolFilterWrapper</b> or <b>ProtocolListenerWrapper</b>
+ */
+ private static final Protocol REF_PROTOCOL = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
+
+ /**
+ * The {@link Cluster}'s implementation with adaptive functionality, and actually it will get a {@link Cluster}'s
+ * specific implementation who is wrapped with <b>MockClusterInvoker</b>
+ */
+ private static final Cluster CLUSTER = ExtensionLoader.getExtensionLoader(Cluster.class).getAdaptiveExtension();
+
+ /**
+ * A {@link ProxyFactory} implementation that will generate a reference service's proxy,the JavassistProxyFactory is
+ * its default implementation
+ */
+ private static final ProxyFactory PROXY_FACTORY = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
+
+ /**
+ * The url of the reference service
+ */
+ private final List<URL> urls = new ArrayList<URL>();
+
+ /**
+ * The interface name of the reference service
+ */
+ private String interfaceName;
+
+ /**
+ * The interface class of the reference service
+ */
+ private Class<?> interfaceClass;
+
+ /**
+ * client type
+ */
+ private String client;
+
+ /**
+ * The url for peer-to-peer invocation
+ */
+ private String url;
+
+ /**
+ * The method configs
+ */
+ private List<MethodConfig> methods;
+
+ /**
+ * The consumer config (default)
+ */
+ private ConsumerConfig consumer;
+
+ /**
+ * Only the service provider of the specified protocol is invoked, and other protocols are ignored.
+ */
+ private String protocol;
+
+ /**
+ * The interface proxy reference
+ */
+ private transient volatile T ref;
+
+ /**
+ * The invoker of the reference service
+ */
+ private transient volatile Invoker<?> invoker;
+
+ /**
+ * The flag whether the ReferenceConfig has been initialized
+ */
+ private transient volatile boolean initialized;
+
+ /**
+ * whether this ReferenceConfig has been destroyed
+ */
+ private transient volatile boolean destroyed;
+
+ /**
+ * The {@link EventDispatcher}
+ *
+ * @since 2.7.3
+ */
+ private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension();
+
+ @SuppressWarnings("unused")
+ private final Object finalizerGuardian = new Object() {
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+
+ if (!ReferenceConfig.this.destroyed) {
+ logger.warn("ReferenceConfig(" + url + ") is not DESTROYED when FINALIZE");
+
+ /* don't destroy for now
+ try {
+ ReferenceConfig.this.destroy();
+ } catch (Throwable t) {
+ logger.warn("Unexpected err when destroy invoker of ReferenceConfig(" + url + ") in finalize method!", t);
+ }
+ */
+ }
+ }
+ };
+
+ public ReferenceConfig() {
+ }
+
+ public ReferenceConfig(Reference reference) {
+ appendAnnotation(Reference.class, reference);
+ setMethods(MethodConfig.constructMethodConfig(reference.methods()));
+ }
+
+ public URL toUrl() {
+ return urls.isEmpty() ? null : urls.iterator().next();
+ }
+
+ public List<URL> toUrls() {
+ return urls;
+ }
+
+ /**
+ * This method should be called right after the creation of this class's instance, before any property in other config modules is used.
+ * Check each config modules are created properly and override their properties if necessary.
+ */
+ public void checkAndUpdateSubConfigs() {
+ if (StringUtils.isEmpty(interfaceName)) {
+ throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!");
+ }
+ completeCompoundConfigs();
+ startConfigCenter();
+ // get consumer's global configuration
+ checkDefault();
+ this.refresh();
+ if (getGeneric() == null && getConsumer() != null) {
+ setGeneric(getConsumer().getGeneric());
+ }
+ if (ProtocolUtils.isGeneric(getGeneric())) {
+ interfaceClass = GenericService.class;
+ } else {
+ try {
+ interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
+ .getContextClassLoader());
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ checkInterfaceAndMethods(interfaceClass, methods);
+ }
+ resolveFile();
+ checkApplication();
+ checkMetadataReport();
+ }
+
+ public synchronized T get() {
+ checkAndUpdateSubConfigs();
+
+ if (destroyed) {
+ throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
+ }
+ if (ref == null) {
+ init();
+ }
+ return ref;
+ }
+
+ public synchronized void destroy() {
+ if (ref == null) {
+ return;
+ }
+ if (destroyed) {
+ return;
+ }
+ destroyed = true;
+ try {
+ invoker.destroy();
+ } catch (Throwable t) {
+ logger.warn("Unexpected error occured when destroy invoker of ReferenceConfig(" + url + ").", t);
+ }
+ invoker = null;
+ ref = null;
+
+ // dispatch a ReferenceConfigDestroyedEvent since 2.7.3
+ dispatch(new ReferenceConfigDestroyedEvent(this));
+ }
+
+ private void init() {
+ if (initialized) {
+ return;
+ }
+ checkStubAndLocal(interfaceClass);
+ checkMock(interfaceClass);
+ Map<String, String> map = new HashMap<String, String>();
+
+ map.put(SIDE_KEY, CONSUMER_SIDE);
+
+ appendRuntimeParameters(map);
+ if (!isGeneric()) {
+ String revision = Version.getVersion(interfaceClass, version);
+ if (revision != null && revision.length() > 0) {
+ map.put(REVISION_KEY, revision);
+ }
+
+ String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
+ if (methods.length == 0) {
+ logger.warn("No method found in service interface " + interfaceClass.getName());
+ map.put(METHODS_KEY, ANY_VALUE);
+ } else {
+ map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), COMMA_SEPARATOR));
+ }
+ }
+ map.put(INTERFACE_KEY, interfaceName);
+ appendParameters(map, metrics);
+ appendParameters(map, application);
+ appendParameters(map, module);
+ // remove 'default.' prefix for configs from ConsumerConfig
+ // appendParameters(map, consumer, Constants.DEFAULT_KEY);
+ appendParameters(map, consumer);
+ appendParameters(map, this);
+ Map<String, Object> attributes = null;
+ if (CollectionUtils.isNotEmpty(methods)) {
+ attributes = new HashMap<String, Object>();
+ for (MethodConfig methodConfig : methods) {
+ appendParameters(map, methodConfig, methodConfig.getName());
+ String retryKey = methodConfig.getName() + ".retry";
+ if (map.containsKey(retryKey)) {
+ String retryValue = map.remove(retryKey);
+ if ("false".equals(retryValue)) {
+ map.put(methodConfig.getName() + ".retries", "0");
+ }
+ }
+ attributes.put(methodConfig.getName(), convertMethodConfig2AyncInfo(methodConfig));
+ }
+ }
+
+ String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY);
+ if (StringUtils.isEmpty(hostToRegistry)) {
+ hostToRegistry = NetUtils.getLocalHost();
+ } else if (isInvalidLocalHost(hostToRegistry)) {
+ throw new IllegalArgumentException("Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
+ }
+ map.put(REGISTER_IP_KEY, hostToRegistry);
+
+ ref = createProxy(map);
+
+ String serviceKey = URL.buildKey(interfaceName, group, version);
+ ApplicationModel.initConsumerModel(serviceKey, buildConsumerModel(serviceKey, attributes));
+ initialized = true;
+
+ // dispatch a ReferenceConfigInitializedEvent since 2.7.3
+ dispatch(new ReferenceConfigInitializedEvent(this, invoker));
+ }
+
+ private ConsumerModel buildConsumerModel(String serviceKey, Map<String, Object> attributes) {
+ Method[] methods = interfaceClass.getMethods();
+ Class serviceInterface = interfaceClass;
+ if (interfaceClass == GenericService.class) {
+ try {
+ serviceInterface = Class.forName(interfaceName);
+ methods = serviceInterface.getMethods();
+ } catch (ClassNotFoundException e) {
+ methods = interfaceClass.getMethods();
+ }
+ }
+ return new ConsumerModel(serviceKey, serviceInterface, ref, methods, attributes);
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
+ private T createProxy(Map<String, String> map) {
+ if (shouldJvmRefer(map)) {
+ URL url = new URL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(map);
+ invoker = REF_PROTOCOL.refer(interfaceClass, url);
+ if (logger.isInfoEnabled()) {
+ logger.info("Using injvm service " + interfaceClass.getName());
+ }
+ } else {
+ urls.clear(); // reference retry init will add url to urls, lead to OOM
+ if (url != null && url.length() > 0) { // user specified URL, could be peer-to-peer address, or register center's address.
+ String[] us = SEMICOLON_SPLIT_PATTERN.split(url);
+ if (us != null && us.length > 0) {
+ for (String u : us) {
+ URL url = URL.valueOf(u);
+ if (StringUtils.isEmpty(url.getPath())) {
+ url = url.setPath(interfaceName);
+ }
+ if (REGISTRY_PROTOCOL.equals(url.getProtocol())) {
+ urls.add(url.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
+ } else {
+ urls.add(ClusterUtils.mergeUrl(url, map));
+ }
+ }
+ }
+ } else { // assemble URL from register center's configuration
+ // if protocols not injvm checkRegistry
+ if (!LOCAL_PROTOCOL.equalsIgnoreCase(getProtocol())) {
+ checkRegistry();
+ List<URL> us = loadRegistries(false);
+ if (CollectionUtils.isNotEmpty(us)) {
+ for (URL u : us) {
+ URL monitorUrl = loadMonitor(u);
+ if (monitorUrl != null) {
+ map.put(MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
+ }
+ urls.add(u.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
+ }
+ }
+ if (urls.isEmpty()) {
+ throw new IllegalStateException("No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config <dubbo:registry address=\"...\" /> to your spring config.");
+ }
+ }
+ }
+
+ if (urls.size() == 1) {
+ invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));
+ } else {
+ List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
+ URL registryURL = null;
+ for (URL url : urls) {
+ invokers.add(REF_PROTOCOL.refer(interfaceClass, url));
+ if (REGISTRY_PROTOCOL.equals(url.getProtocol())) {
+ registryURL = url; // use last registry url
+ }
+ }
+ if (registryURL != null) { // registry url is available
+ // use RegistryAwareCluster only when register's CLUSTER is available
+ URL u = registryURL.addParameter(CLUSTER_KEY, RegistryAwareCluster.NAME);
+ // The invoker wrap relation would be: RegistryAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker(RegistryDirectory, will execute route) -> Invoker
+ invoker = CLUSTER.join(new StaticDirectory(u, invokers));
+ } else { // not a registry url, must be direct invoke.
+ invoker = CLUSTER.join(new StaticDirectory(invokers));
+ }
+ }
+ }
+
+ if (shouldCheck() && !invoker.isAvailable()) {
+ throw new IllegalStateException("Failed to check the status of the service " + interfaceName + ". No provider available for the service " + (group == null ? "" : group + "/") + interfaceName + (version == null ? "" : ":" + version) + " from the url " + invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion());
+ }
+ if (logger.isInfoEnabled()) {
+ logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl());
+ }
+ /**
+ * @since 2.7.0
+ * ServiceData Store
+ */
+ MetadataReportService metadataReportService = null;
+ if ((metadataReportService = getMetadataReportService()) != null) {
+ URL consumerURL = new URL(CONSUMER_PROTOCOL, map.remove(REGISTER_IP_KEY), 0, map.get(INTERFACE_KEY), map);
+ metadataReportService.publishConsumer(consumerURL);
+ }
+ // create service proxy
+ return (T) PROXY_FACTORY.getProxy(invoker);
+ }
+
+ /**
+ * Figure out should refer the service in the same JVM from configurations. The default behavior is true
+ * 1. if injvm is specified, then use it
+ * 2. then if a url is specified, then assume it's a remote call
+ * 3. otherwise, check scope parameter
+ * 4. if scope is not specified but the target service is provided in the same JVM, then prefer to make the local
+ * call, which is the default behavior
+ */
+ protected boolean shouldJvmRefer(Map<String, String> map) {
+ URL tmpUrl = new URL("temp", "localhost", 0, map);
+ boolean isJvmRefer;
+ if (isInjvm() == null) {
+ // if a url is specified, don't do local reference
+ if (url != null && url.length() > 0) {
+ isJvmRefer = false;
+ } else {
+ // by default, reference local service if there is
+ isJvmRefer = InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl);
+ }
+ } else {
+ isJvmRefer = isInjvm();
+ }
+ return isJvmRefer;
+ }
+
+ protected boolean shouldCheck() {
+ Boolean shouldCheck = isCheck();
+ if (shouldCheck == null && getConsumer() != null) {
+ shouldCheck = getConsumer().isCheck();
+ }
+ if (shouldCheck == null) {
+ // default true
+ shouldCheck = true;
+ }
+ return shouldCheck;
+ }
+
+ protected boolean shouldInit() {
+ Boolean shouldInit = isInit();
+ if (shouldInit == null && getConsumer() != null) {
+ shouldInit = getConsumer().isInit();
+ }
+ if (shouldInit == null) {
+ // default is false
+ return false;
+ }
+ return shouldInit;
+ }
+
+ private void checkDefault() {
+ if (consumer != null) {
+ return;
+ }
+ setConsumer(ConfigManager.getInstance().getDefaultConsumer().orElseGet(() -> {
+ ConsumerConfig consumerConfig = new ConsumerConfig();
+ consumerConfig.refresh();
+ return consumerConfig;
+ }));
+ }
+
+ private void completeCompoundConfigs() {
+ if (consumer != null) {
+ if (application == null) {
+ setApplication(consumer.getApplication());
+ }
+ if (module == null) {
+ setModule(consumer.getModule());
+ }
+ if (registries == null) {
+ setRegistries(consumer.getRegistries());
+ }
+ if (monitor == null) {
+ setMonitor(consumer.getMonitor());
+ }
+ }
+ if (module != null) {
+ if (registries == null) {
+ setRegistries(module.getRegistries());
+ }
+ if (monitor == null) {
+ setMonitor(module.getMonitor());
+ }
+ }
+ if (application != null) {
+ if (registries == null) {
+ setRegistries(application.getRegistries());
+ }
+ if (monitor == null) {
+ setMonitor(application.getMonitor());
+ }
+ }
+ }
+
+ public Class<?> getInterfaceClass() {
+ if (interfaceClass != null) {
+ return interfaceClass;
+ }
+ if (isGeneric()
+ || (getConsumer() != null && getConsumer().isGeneric())) {
+ return GenericService.class;
+ }
+ try {
+ if (interfaceName != null && interfaceName.length() > 0) {
+ this.interfaceClass = Class.forName(interfaceName, true, ClassUtils.getClassLoader());
+ }
+ } catch (ClassNotFoundException t) {
+ throw new IllegalStateException(t.getMessage(), t);
+ }
+ return interfaceClass;
+ }
+
+ /**
+ * @param interfaceClass
+ * @see #setInterface(Class)
+ * @deprecated
+ */
+ @Deprecated
+ public void setInterfaceClass(Class<?> interfaceClass) {
+ setInterface(interfaceClass);
+ }
+
+ public String getInterface() {
+ return interfaceName;
+ }
+
+ public void setInterface(String interfaceName) {
+ this.interfaceName = interfaceName;
+ if (StringUtils.isEmpty(id)) {
+ id = interfaceName;
+ }
+ }
+
+ public void setInterface(Class<?> interfaceClass) {
+ if (interfaceClass != null && !interfaceClass.isInterface()) {
+ throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!");
+ }
+ this.interfaceClass = interfaceClass;
+ setInterface(interfaceClass == null ? null : interfaceClass.getName());
+ }
+
+ public String getClient() {
+ return client;
+ }
+
+ public void setClient(String client) {
+ checkName(Constants.CLIENT_KEY, client);
+ this.client = client;
+ }
+
+ @Parameter(excluded = true)
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public List<MethodConfig> getMethods() {
+ return methods;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void setMethods(List<? extends MethodConfig> methods) {
+ this.methods = (List<MethodConfig>) methods;
+ }
+
+ public ConsumerConfig getConsumer() {
+ return consumer;
+ }
+
+ public void setConsumer(ConsumerConfig consumer) {
+ ConfigManager.getInstance().addConsumer(consumer);
+ this.consumer = consumer;
+ }
+
+ public String getProtocol() {
+ return protocol;
+ }
+
+ public void setProtocol(String protocol) {
+ this.protocol = protocol;
+ }
+
+ // just for test
+ Invoker<?> getInvoker() {
+ return invoker;
+ }
+
+ @Override
+ @Parameter(excluded = true)
+ public String getPrefix() {
+ return DUBBO + ".reference." + interfaceName;
+ }
+
+ private void resolveFile() {
+ String resolve = System.getProperty(interfaceName);
+ String resolveFile = null;
+ if (StringUtils.isEmpty(resolve)) {
+ resolveFile = System.getProperty("dubbo.resolve.file");
+ if (StringUtils.isEmpty(resolveFile)) {
+ File userResolveFile = new File(new File(System.getProperty("user.home")), "dubbo-resolve.properties");
+ if (userResolveFile.exists()) {
+ resolveFile = userResolveFile.getAbsolutePath();
+ }
+ }
+ if (resolveFile != null && resolveFile.length() > 0) {
+ Properties properties = new Properties();
+ try (FileInputStream fis = new FileInputStream(new File(resolveFile))) {
+ properties.load(fis);
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to load " + resolveFile + ", cause: " + e.getMessage(), e);
+ }
+
+ resolve = properties.getProperty(interfaceName);
+ }
+ }
+ if (resolve != null && resolve.length() > 0) {
+ url = resolve;
+ if (logger.isWarnEnabled()) {
+ if (resolveFile != null) {
+ logger.warn("Using default dubbo resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service.");
+ } else {
+ logger.warn("Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service.");
+ }
+ }
+ }
+ }
+
+ /**
+ * Dispatch an {@link Event event}
+ *
+ * @param event an {@link Event event}
+ * @since 2.7.3
+ */
+ protected void dispatch(Event event) {
+ eventDispatcher.dispatch(event);
+ }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java
index 83f56b1..c9a96cb 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java
@@ -23,11 +23,11 @@ import org.apache.dubbo.remoting.Constants;
import java.util.Map;
import static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
-import static org.apache.dubbo.config.Constants.REGISTRIES_SUFFIX;
+import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;
+import static org.apache.dubbo.config.Constants.REGISTRIES_SUFFIX;
import static org.apache.dubbo.config.Constants.ZOOKEEPER_PROTOCOL;
import static org.apache.dubbo.registry.Constants.EXTRA_KEYS_KEY;
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
index 257d2a1..cc1138a 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
@@ -1,1054 +1,1081 @@
-/*
- * 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 org.apache.dubbo.config;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.URLBuilder;
-import org.apache.dubbo.common.Version;
-import org.apache.dubbo.common.bytecode.Wrapper;
-import org.apache.dubbo.common.config.Environment;
-import org.apache.dubbo.common.extension.ExtensionLoader;
-import org.apache.dubbo.common.utils.ClassUtils;
-import org.apache.dubbo.common.utils.CollectionUtils;
-import org.apache.dubbo.common.utils.ConfigUtils;
-import org.apache.dubbo.common.utils.NamedThreadFactory;
-import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.config.annotation.Service;
-import org.apache.dubbo.config.context.ConfigManager;
-import org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker;
-import org.apache.dubbo.config.support.Parameter;
-import org.apache.dubbo.metadata.integration.MetadataReportService;
-import org.apache.dubbo.remoting.Constants;
-import org.apache.dubbo.rpc.Exporter;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Protocol;
-import org.apache.dubbo.rpc.ProxyFactory;
-import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
-import org.apache.dubbo.rpc.model.ApplicationModel;
-import org.apache.dubbo.rpc.model.ProviderModel;
-import org.apache.dubbo.rpc.service.GenericService;
-import org.apache.dubbo.rpc.support.ProtocolUtils;
-
-import java.lang.reflect.Method;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.UUID;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
-import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
-import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
-import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
-import static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND;
-import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY;
-import static org.apache.dubbo.config.Constants.DUBBO_PORT_TO_BIND;
-import static org.apache.dubbo.config.Constants.DUBBO_PORT_TO_REGISTRY;
-import static org.apache.dubbo.rpc.cluster.Constants.EXPORT_KEY;
-import static org.apache.dubbo.config.Constants.MULTICAST;
-import static org.apache.dubbo.config.Constants.PROTOCOLS_SUFFIX;
-import static org.apache.dubbo.rpc.Constants.SCOPE_KEY;
-import static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;
-import static org.apache.dubbo.config.Constants.SCOPE_NONE;
-import static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;
-import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;
-import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
-import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
-import static org.apache.dubbo.rpc.Constants.PROXY_KEY;
-import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
-import static org.apache.dubbo.common.utils.NetUtils.getAvailablePort;
-import static org.apache.dubbo.common.utils.NetUtils.getLocalHost;
-import static org.apache.dubbo.common.utils.NetUtils.isInvalidLocalHost;
-import static org.apache.dubbo.common.utils.NetUtils.isInvalidPort;
-
-/**
- * ServiceConfig
- *
- * @export
- */
-public class ServiceConfig<T> extends AbstractServiceConfig {
-
- private static final long serialVersionUID = 3033787999037024738L;
-
- /**
- * The {@link Protocol} implementation with adaptive functionality,it will be different in different scenarios.
- * A particular {@link Protocol} implementation is determined by the protocol attribute in the {@link URL}.
- * For example:
- *
- * <li>when the url is registry://224.5.6.7:1234/org.apache.dubbo.registry.RegistryService?application=dubbo-sample,
- * then the protocol is <b>RegistryProtocol</b></li>
- *
- * <li>when the url is dubbo://224.5.6.7:1234/org.apache.dubbo.config.api.DemoService?application=dubbo-sample, then
- * the protocol is <b>DubboProtocol</b></li>
- * <p>
- * Actually,when the {@link ExtensionLoader} init the {@link Protocol} instants,it will automatically wraps two
- * layers, and eventually will get a <b>ProtocolFilterWrapper</b> or <b>ProtocolListenerWrapper</b>
- */
- private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
-
- /**
- * A {@link ProxyFactory} implementation that will generate a exported service proxy,the JavassistProxyFactory is its
- * default implementation
- */
- private static final ProxyFactory PROXY_FACTORY = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
-
- /**
- * A random port cache, the different protocols who has no port specified have different random port
- */
- private static final Map<String, Integer> RANDOM_PORT_MAP = new HashMap<String, Integer>();
-
- /**
- * A delayed exposure service timer
- */
- private static final ScheduledExecutorService DELAY_EXPORT_EXECUTOR = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true));
-
- /**
- * The urls of the services exported
- */
- private final List<URL> urls = new ArrayList<URL>();
-
- /**
- * The exported services
- */
- private final List<Exporter<?>> exporters = new ArrayList<Exporter<?>>();
-
- /**
- * The interface name of the exported service
- */
- private String interfaceName;
-
- /**
- * The interface class of the exported service
- */
- private Class<?> interfaceClass;
-
- /**
- * The reference of the interface implementation
- */
- private T ref;
-
- /**
- * The service name
- */
- private String path;
-
- /**
- * The method configuration
- */
- private List<MethodConfig> methods;
-
- /**
- * The provider configuration
- */
- private ProviderConfig provider;
-
- /**
- * The providerIds
- */
- private String providerIds;
-
- /**
- * Whether the provider has been exported
- */
- private transient volatile boolean exported;
-
- /**
- * The flag whether a service has unexported ,if the method unexported is invoked, the value is true
- */
- private transient volatile boolean unexported;
-
- /**
- * whether it is a GenericService
- */
- private volatile String generic;
-
- public ServiceConfig() {
- }
-
- public ServiceConfig(Service service) {
- appendAnnotation(Service.class, service);
- setMethods(MethodConfig.constructMethodConfig(service.methods()));
- }
-
- @Deprecated
- private static List<ProtocolConfig> convertProviderToProtocol(List<ProviderConfig> providers) {
- if (CollectionUtils.isEmpty(providers)) {
- return null;
- }
- List<ProtocolConfig> protocols = new ArrayList<ProtocolConfig>(providers.size());
- for (ProviderConfig provider : providers) {
- protocols.add(convertProviderToProtocol(provider));
- }
- return protocols;
- }
-
- @Deprecated
- private static List<ProviderConfig> convertProtocolToProvider(List<ProtocolConfig> protocols) {
- if (CollectionUtils.isEmpty(protocols)) {
- return null;
- }
- List<ProviderConfig> providers = new ArrayList<ProviderConfig>(protocols.size());
- for (ProtocolConfig provider : protocols) {
- providers.add(convertProtocolToProvider(provider));
- }
- return providers;
- }
-
- @Deprecated
- private static ProtocolConfig convertProviderToProtocol(ProviderConfig provider) {
- ProtocolConfig protocol = new ProtocolConfig();
- protocol.setName(provider.getProtocol().getName());
- protocol.setServer(provider.getServer());
- protocol.setClient(provider.getClient());
- protocol.setCodec(provider.getCodec());
- protocol.setHost(provider.getHost());
- protocol.setPort(provider.getPort());
- protocol.setPath(provider.getPath());
- protocol.setPayload(provider.getPayload());
- protocol.setThreads(provider.getThreads());
- protocol.setParameters(provider.getParameters());
- return protocol;
- }
-
- @Deprecated
- private static ProviderConfig convertProtocolToProvider(ProtocolConfig protocol) {
- ProviderConfig provider = new ProviderConfig();
- provider.setProtocol(protocol);
- provider.setServer(protocol.getServer());
- provider.setClient(protocol.getClient());
- provider.setCodec(protocol.getCodec());
- provider.setHost(protocol.getHost());
- provider.setPort(protocol.getPort());
- provider.setPath(protocol.getPath());
- provider.setPayload(protocol.getPayload());
- provider.setThreads(protocol.getThreads());
- provider.setParameters(protocol.getParameters());
- return provider;
- }
-
- private static Integer getRandomPort(String protocol) {
- protocol = protocol.toLowerCase();
- return RANDOM_PORT_MAP.getOrDefault(protocol, Integer.MIN_VALUE);
- }
-
- private static void putRandomPort(String protocol, Integer port) {
- protocol = protocol.toLowerCase();
- if (!RANDOM_PORT_MAP.containsKey(protocol)) {
- RANDOM_PORT_MAP.put(protocol, port);
- logger.warn("Use random available port(" + port + ") for protocol " + protocol);
- }
- }
-
- public URL toUrl() {
- return urls.isEmpty() ? null : urls.iterator().next();
- }
-
- public List<URL> toUrls() {
- return urls;
- }
-
- @Parameter(excluded = true)
- public boolean isExported() {
- return exported;
- }
-
- @Parameter(excluded = true)
- public boolean isUnexported() {
- return unexported;
- }
-
- public void checkAndUpdateSubConfigs() {
- // Use default configs defined explicitly on global configs
- completeCompoundConfigs();
- // Config Center should always being started first.
- startConfigCenter();
- checkDefault();
- checkProtocol();
- checkApplication();
- // if protocol is not injvm checkRegistry
- if (!isOnlyInJvm()) {
- checkRegistry();
- }
- this.refresh();
- checkMetadataReport();
-
- if (StringUtils.isEmpty(interfaceName)) {
- throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
- }
-
- if (ref instanceof GenericService) {
- interfaceClass = GenericService.class;
- if (StringUtils.isEmpty(generic)) {
- generic = Boolean.TRUE.toString();
- }
- } else {
- try {
- interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
- .getContextClassLoader());
- } catch (ClassNotFoundException e) {
- throw new IllegalStateException(e.getMessage(), e);
- }
- checkInterfaceAndMethods(interfaceClass, methods);
- checkRef();
- generic = Boolean.FALSE.toString();
- }
- if (local != null) {
- if ("true".equals(local)) {
- local = interfaceName + "Local";
- }
- Class<?> localClass;
- try {
- localClass = ClassUtils.forNameWithThreadContextClassLoader(local);
- } catch (ClassNotFoundException e) {
- throw new IllegalStateException(e.getMessage(), e);
- }
- if (!interfaceClass.isAssignableFrom(localClass)) {
- throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName);
- }
- }
- if (stub != null) {
- if ("true".equals(stub)) {
- stub = interfaceName + "Stub";
- }
- Class<?> stubClass;
- try {
- stubClass = ClassUtils.forNameWithThreadContextClassLoader(stub);
- } catch (ClassNotFoundException e) {
- throw new IllegalStateException(e.getMessage(), e);
- }
- if (!interfaceClass.isAssignableFrom(stubClass)) {
- throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
- }
- }
- checkStubAndLocal(interfaceClass);
- checkMock(interfaceClass);
- }
-
- /**
- * Determine if it is injvm
- *
- * @return
- */
- private boolean isOnlyInJvm() {
- return getProtocols().size() == 1 && LOCAL_PROTOCOL.equalsIgnoreCase(getProtocols().get(0).getName());
- }
-
- public synchronized void export() {
- checkAndUpdateSubConfigs();
-
- if (!shouldExport()) {
- return;
- }
-
- if (shouldDelay()) {
- DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
- } else {
- doExport();
- }
- }
-
- private boolean shouldExport() {
- Boolean export = getExport();
- // default value is true
- return export == null ? true : export;
- }
-
- @Override
- public Boolean getExport() {
- return (export == null && provider != null) ? provider.getExport() : export;
- }
-
- private boolean shouldDelay() {
- Integer delay = getDelay();
- return delay != null && delay > 0;
- }
-
- @Override
- public Integer getDelay() {
- return (delay == null && provider != null) ? provider.getDelay() : delay;
- }
-
- protected synchronized void doExport() {
- if (unexported) {
- throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!");
- }
- if (exported) {
- return;
- }
- exported = true;
-
- if (StringUtils.isEmpty(path)) {
- path = interfaceName;
- }
- doExportUrls();
- }
-
- private void checkRef() {
- // reference should not be null, and is the implementation of the given interface
- if (ref == null) {
- throw new IllegalStateException("ref not allow null!");
- }
- if (!interfaceClass.isInstance(ref)) {
- throw new IllegalStateException("The class "
- + ref.getClass().getName() + " unimplemented interface "
- + interfaceClass + "!");
- }
- }
-
- public synchronized void unexport() {
- if (!exported) {
- return;
- }
- if (unexported) {
- return;
- }
- if (!exporters.isEmpty()) {
- for (Exporter<?> exporter : exporters) {
- try {
- exporter.unexport();
- } catch (Throwable t) {
- logger.warn("Unexpected error occured when unexport " + exporter, t);
- }
- }
- exporters.clear();
- }
- unexported = true;
- }
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- private void doExportUrls() {
- List<URL> registryURLs = loadRegistries(true);
- for (ProtocolConfig protocolConfig : protocols) {
- String pathKey = URL.buildKey(getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), group, version);
- ProviderModel providerModel = new ProviderModel(pathKey, ref, interfaceClass);
- ApplicationModel.initProviderModel(pathKey, providerModel);
- doExportUrlsFor1Protocol(protocolConfig, registryURLs);
- }
- }
-
- private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
- String name = protocolConfig.getName();
- if (StringUtils.isEmpty(name)) {
- name = DUBBO;
- }
-
- Map<String, String> map = new HashMap<String, String>();
- map.put(SIDE_KEY, PROVIDER_SIDE);
-
- appendRuntimeParameters(map);
- appendParameters(map, metrics);
- appendParameters(map, application);
- appendParameters(map, module);
- // remove 'default.' prefix for configs from ProviderConfig
- // appendParameters(map, provider, Constants.DEFAULT_KEY);
- appendParameters(map, provider);
- appendParameters(map, protocolConfig);
- appendParameters(map, this);
- if (CollectionUtils.isNotEmpty(methods)) {
- for (MethodConfig method : methods) {
- appendParameters(map, method, method.getName());
- String retryKey = method.getName() + ".retry";
- if (map.containsKey(retryKey)) {
- String retryValue = map.remove(retryKey);
- if ("false".equals(retryValue)) {
- map.put(method.getName() + ".retries", "0");
- }
- }
- List<ArgumentConfig> arguments = method.getArguments();
- if (CollectionUtils.isNotEmpty(arguments)) {
- for (ArgumentConfig argument : arguments) {
- // convert argument type
- if (argument.getType() != null && argument.getType().length() > 0) {
- Method[] methods = interfaceClass.getMethods();
- // visit all methods
- if (methods != null && methods.length > 0) {
- for (int i = 0; i < methods.length; i++) {
- String methodName = methods[i].getName();
- // target the method, and get its signature
- if (methodName.equals(method.getName())) {
- Class<?>[] argtypes = methods[i].getParameterTypes();
- // one callback in the method
- if (argument.getIndex() != -1) {
- if (argtypes[argument.getIndex()].getName().equals(argument.getType())) {
- appendParameters(map, argument, method.getName() + "." + argument.getIndex());
- } else {
- throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
- }
- } else {
- // multiple callbacks in the method
- for (int j = 0; j < argtypes.length; j++) {
- Class<?> argclazz = argtypes[j];
- if (argclazz.getName().equals(argument.getType())) {
- appendParameters(map, argument, method.getName() + "." + j);
- if (argument.getIndex() != -1 && argument.getIndex() != j) {
- throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
- }
- }
- }
- }
- }
- }
- }
- } else if (argument.getIndex() != -1) {
- appendParameters(map, argument, method.getName() + "." + argument.getIndex());
- } else {
- throw new IllegalArgumentException("Argument config must set index or type attribute.eg: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>");
- }
-
- }
- }
- } // end of methods for
- }
-
- if (ProtocolUtils.isGeneric(generic)) {
- map.put(GENERIC_KEY, generic);
- map.put(METHODS_KEY, ANY_VALUE);
- } else {
- String revision = Version.getVersion(interfaceClass, version);
- if (revision != null && revision.length() > 0) {
- map.put(REVISION_KEY, revision);
- }
-
- String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
- if (methods.length == 0) {
- logger.warn("No method found in service interface " + interfaceClass.getName());
- map.put(METHODS_KEY, ANY_VALUE);
- } else {
- map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
- }
- }
- if (!ConfigUtils.isEmpty(token)) {
- if (ConfigUtils.isDefault(token)) {
- map.put(TOKEN_KEY, UUID.randomUUID().toString());
- } else {
- map.put(TOKEN_KEY, token);
- }
- }
- // export service
- String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
- Integer port = this.findConfigedPorts(protocolConfig, name, map);
- URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
-
- if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
- .hasExtension(url.getProtocol())) {
- url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
- .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
- }
-
- String scope = url.getParameter(SCOPE_KEY);
- // don't export when none is configured
- if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
-
- // export to local if the config is not remote (export to remote only when config is remote)
- if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
- exportLocal(url);
- }
- // export to remote if the config is not local (export to local only when config is local)
- if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
- if (!isOnlyInJvm() && logger.isInfoEnabled()) {
- logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
- }
- if (CollectionUtils.isNotEmpty(registryURLs)) {
- for (URL registryURL : registryURLs) {
- //if protocol is only injvm ,not register
- if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
- continue;
- }
- url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));
- URL monitorUrl = loadMonitor(registryURL);
- if (monitorUrl != null) {
- url = url.addParameterAndEncoded(MONITOR_KEY, monitorUrl.toFullString());
- }
- if (logger.isInfoEnabled()) {
- logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
- }
-
- // For providers, this is used to enable custom proxy to generate invoker
- String proxy = url.getParameter(PROXY_KEY);
- if (StringUtils.isNotEmpty(proxy)) {
- registryURL = registryURL.addParameter(PROXY_KEY, proxy);
- }
-
- Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
- DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
-
- Exporter<?> exporter = protocol.export(wrapperInvoker);
- exporters.add(exporter);
- }
- } else {
- Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, url);
- DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
-
- Exporter<?> exporter = protocol.export(wrapperInvoker);
- exporters.add(exporter);
- }
- /**
- * @since 2.7.0
- * ServiceData Store
- */
- MetadataReportService metadataReportService = null;
- if ((metadataReportService = getMetadataReportService()) != null) {
- metadataReportService.publishProvider(url);
- }
- }
- }
- this.urls.add(url);
- }
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- /**
- * always export injvm
- */
- private void exportLocal(URL url) {
- URL local = URLBuilder.from(url)
- .setProtocol(LOCAL_PROTOCOL)
- .setHost(LOCALHOST_VALUE)
- .setPort(0)
- .build();
- Exporter<?> exporter = protocol.export(
- PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, local));
- exporters.add(exporter);
- logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry url : " + local);
- }
-
- private Optional<String> getContextPath(ProtocolConfig protocolConfig) {
- String contextPath = protocolConfig.getContextpath();
- if (StringUtils.isEmpty(contextPath) && provider != null) {
- contextPath = provider.getContextpath();
- }
- return Optional.ofNullable(contextPath);
- }
-
- protected Class getServiceClass(T ref) {
- return ref.getClass();
- }
-
- /**
- * Register & bind IP address for service provider, can be configured separately.
- * Configuration priority: environment variables -> java system properties -> host property in config file ->
- * /etc/hosts -> default network address -> first available network address
- *
- * @param protocolConfig
- * @param registryURLs
- * @param map
- * @return
- */
- private String findConfigedHosts(ProtocolConfig protocolConfig, List<URL> registryURLs, Map<String, String> map) {
- boolean anyhost = false;
-
- String hostToBind = getValueFromConfig(protocolConfig, DUBBO_IP_TO_BIND);
- if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) {
- throw new IllegalArgumentException("Specified invalid bind ip from property:" + DUBBO_IP_TO_BIND + ", value:" + hostToBind);
- }
-
- // if bind ip is not found in environment, keep looking up
- if (StringUtils.isEmpty(hostToBind)) {
- hostToBind = protocolConfig.getHost();
- if (provider != null && StringUtils.isEmpty(hostToBind)) {
- hostToBind = provider.getHost();
- }
- if (isInvalidLocalHost(hostToBind)) {
- anyhost = true;
- try {
- hostToBind = InetAddress.getLocalHost().getHostAddress();
- } catch (UnknownHostException e) {
- logger.warn(e.getMessage(), e);
- }
- if (isInvalidLocalHost(hostToBind)) {
- if (CollectionUtils.isNotEmpty(registryURLs)) {
- for (URL registryURL : registryURLs) {
- if (MULTICAST.equalsIgnoreCase(registryURL.getParameter("registry"))) {
- // skip multicast registry since we cannot connect to it via Socket
- continue;
- }
- try (Socket socket = new Socket()) {
- SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
- socket.connect(addr, 1000);
- hostToBind = socket.getLocalAddress().getHostAddress();
- break;
- } catch (Exception e) {
- logger.warn(e.getMessage(), e);
- }
- }
- }
- if (isInvalidLocalHost(hostToBind)) {
- hostToBind = getLocalHost();
- }
- }
- }
- }
-
- map.put(Constants.BIND_IP_KEY, hostToBind);
-
- // registry ip is not used for bind ip by default
- String hostToRegistry = getValueFromConfig(protocolConfig, DUBBO_IP_TO_REGISTRY);
- if (hostToRegistry != null && hostToRegistry.length() > 0 && isInvalidLocalHost(hostToRegistry)) {
- throw new IllegalArgumentException("Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
- } else if (StringUtils.isEmpty(hostToRegistry)) {
- // bind ip is used as registry ip by default
- hostToRegistry = hostToBind;
- }
-
- map.put(ANYHOST_KEY, String.valueOf(anyhost));
-
- return hostToRegistry;
- }
-
- /**
- * Register port and bind port for the provider, can be configured separately
- * Configuration priority: environment variable -> java system properties -> port property in protocol config file
- * -> protocol default port
- *
- * @param protocolConfig
- * @param name
- * @return
- */
- private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map<String, String> map) {
- Integer portToBind = null;
-
- // parse bind port from environment
- String port = getValueFromConfig(protocolConfig, DUBBO_PORT_TO_BIND);
- portToBind = parsePort(port);
-
- // if there's no bind port found from environment, keep looking up.
- if (portToBind == null) {
- portToBind = protocolConfig.getPort();
- if (provider != null && (portToBind == null || portToBind == 0)) {
- portToBind = provider.getPort();
- }
- final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();
- if (portToBind == null || portToBind == 0) {
- portToBind = defaultPort;
- }
- if (portToBind == null || portToBind <= 0) {
- portToBind = getRandomPort(name);
- if (portToBind == null || portToBind < 0) {
- portToBind = getAvailablePort(defaultPort);
- putRandomPort(name, portToBind);
- }
- }
- }
-
- // save bind port, used as url's key later
- map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind));
-
- // registry port, not used as bind port by default
- String portToRegistryStr = getValueFromConfig(protocolConfig, DUBBO_PORT_TO_REGISTRY);
- Integer portToRegistry = parsePort(portToRegistryStr);
- if (portToRegistry == null) {
- portToRegistry = portToBind;
- }
-
- return portToRegistry;
- }
-
- private Integer parsePort(String configPort) {
- Integer port = null;
- if (configPort != null && configPort.length() > 0) {
- try {
- Integer intPort = Integer.parseInt(configPort);
- if (isInvalidPort(intPort)) {
- throw new IllegalArgumentException("Specified invalid port from env value:" + configPort);
- }
- port = intPort;
- } catch (Exception e) {
- throw new IllegalArgumentException("Specified invalid port from env value:" + configPort);
- }
- }
- return port;
- }
-
- private String getValueFromConfig(ProtocolConfig protocolConfig, String key) {
- String protocolPrefix = protocolConfig.getName().toUpperCase() + "_";
- String port = ConfigUtils.getSystemProperty(protocolPrefix + key);
- if (StringUtils.isEmpty(port)) {
- port = ConfigUtils.getSystemProperty(key);
- }
- return port;
- }
-
- private void completeCompoundConfigs() {
- if (provider != null) {
- if (application == null) {
- setApplication(provider.getApplication());
- }
- if (module == null) {
- setModule(provider.getModule());
- }
- if (registries == null) {
- setRegistries(provider.getRegistries());
- }
- if (monitor == null) {
- setMonitor(provider.getMonitor());
- }
- if (protocols == null) {
- setProtocols(provider.getProtocols());
- }
- if (configCenter == null) {
- setConfigCenter(provider.getConfigCenter());
- }
- }
- if (module != null) {
- if (registries == null) {
- setRegistries(module.getRegistries());
- }
- if (monitor == null) {
- setMonitor(module.getMonitor());
- }
- }
- if (application != null) {
- if (registries == null) {
- setRegistries(application.getRegistries());
- }
- if (monitor == null) {
- setMonitor(application.getMonitor());
- }
- }
- }
-
- private void checkDefault() {
- createProviderIfAbsent();
- }
-
- private void createProviderIfAbsent() {
- if (provider != null) {
- return;
- }
- setProvider(
- ConfigManager.getInstance()
- .getDefaultProvider()
- .orElseGet(() -> {
- ProviderConfig providerConfig = new ProviderConfig();
- providerConfig.refresh();
- return providerConfig;
- })
- );
- }
-
- private void checkProtocol() {
- if (CollectionUtils.isEmpty(protocols) && provider != null) {
- setProtocols(provider.getProtocols());
- }
- convertProtocolIdsToProtocols();
- }
-
- private void convertProtocolIdsToProtocols() {
- if (StringUtils.isEmpty(protocolIds) && CollectionUtils.isEmpty(protocols)) {
- List<String> configedProtocols = new ArrayList<>();
- configedProtocols.addAll(getSubProperties(Environment.getInstance()
- .getExternalConfigurationMap(), PROTOCOLS_SUFFIX));
- configedProtocols.addAll(getSubProperties(Environment.getInstance()
- .getAppExternalConfigurationMap(), PROTOCOLS_SUFFIX));
-
- protocolIds = String.join(",", configedProtocols);
- }
-
- if (StringUtils.isEmpty(protocolIds)) {
- if (CollectionUtils.isEmpty(protocols)) {
- setProtocols(
- ConfigManager.getInstance().getDefaultProtocols()
- .filter(CollectionUtils::isNotEmpty)
- .orElseGet(() -> {
- ProtocolConfig protocolConfig = new ProtocolConfig();
- protocolConfig.refresh();
- return new ArrayList<>(Arrays.asList(protocolConfig));
- })
- );
- }
- } else {
- String[] arr = COMMA_SPLIT_PATTERN.split(protocolIds);
- List<ProtocolConfig> tmpProtocols = CollectionUtils.isNotEmpty(protocols) ? protocols : new ArrayList<>();
- Arrays.stream(arr).forEach(id -> {
- if (tmpProtocols.stream().noneMatch(prot -> prot.getId().equals(id))) {
- tmpProtocols.add(ConfigManager.getInstance().getProtocol(id).orElseGet(() -> {
- ProtocolConfig protocolConfig = new ProtocolConfig();
- protocolConfig.setId(id);
- protocolConfig.refresh();
- return protocolConfig;
- }));
- }
- });
- if (tmpProtocols.size() > arr.length) {
- throw new IllegalStateException("Too much protocols found, the protocols comply to this service are :" + protocolIds + " but got " + protocols
- .size() + " registries!");
- }
- setProtocols(tmpProtocols);
- }
- }
-
- public Class<?> getInterfaceClass() {
- if (interfaceClass != null) {
- return interfaceClass;
- }
- if (ref instanceof GenericService) {
- return GenericService.class;
- }
- try {
- if (interfaceName != null && interfaceName.length() > 0) {
- this.interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
- .getContextClassLoader());
- }
- } catch (ClassNotFoundException t) {
- throw new IllegalStateException(t.getMessage(), t);
- }
- return interfaceClass;
- }
-
- /**
- * @param interfaceClass
- * @see #setInterface(Class)
- * @deprecated
- */
- public void setInterfaceClass(Class<?> interfaceClass) {
- setInterface(interfaceClass);
- }
-
- public String getInterface() {
- return interfaceName;
- }
-
- public void setInterface(Class<?> interfaceClass) {
- if (interfaceClass != null && !interfaceClass.isInterface()) {
- throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!");
- }
- this.interfaceClass = interfaceClass;
- setInterface(interfaceClass == null ? null : interfaceClass.getName());
- }
-
- public void setInterface(String interfaceName) {
- this.interfaceName = interfaceName;
- if (StringUtils.isEmpty(id)) {
- id = interfaceName;
- }
- }
-
- public T getRef() {
- return ref;
- }
-
- public void setRef(T ref) {
- this.ref = ref;
- }
-
- @Parameter(excluded = true)
- public String getPath() {
- return path;
- }
-
- public void setPath(String path) {
- checkPathName(PATH_KEY, path);
- this.path = path;
- }
-
- public List<MethodConfig> getMethods() {
- return methods;
- }
-
- // ======== Deprecated ========
-
- @SuppressWarnings("unchecked")
- public void setMethods(List<? extends MethodConfig> methods) {
- this.methods = (List<MethodConfig>) methods;
- }
-
- public ProviderConfig getProvider() {
- return provider;
- }
-
- public void setProvider(ProviderConfig provider) {
- ConfigManager.getInstance().addProvider(provider);
- this.provider = provider;
- }
-
- @Parameter(excluded = true)
- public String getProviderIds() {
- return providerIds;
- }
-
- public void setProviderIds(String providerIds) {
- this.providerIds = providerIds;
- }
-
- public String getGeneric() {
- return generic;
- }
-
- public void setGeneric(String generic) {
- if (StringUtils.isEmpty(generic)) {
- return;
- }
- if (ProtocolUtils.isGeneric(generic)) {
- this.generic = generic;
- } else {
- throw new IllegalArgumentException("Unsupported generic type " + generic);
- }
- }
-
- @Override
- public void setMock(Boolean mock) {
- throw new IllegalArgumentException("mock doesn't support on provider side");
- }
-
- @Override
- public void setMock(String mock) {
- throw new IllegalArgumentException("mock doesn't support on provider side");
- }
-
- public List<URL> getExportedUrls() {
- return urls;
- }
-
- /**
- * @deprecated Replace to getProtocols()
- */
- @Deprecated
- public List<ProviderConfig> getProviders() {
- return convertProtocolToProvider(protocols);
- }
-
- /**
- * @deprecated Replace to setProtocols()
- */
- @Deprecated
- public void setProviders(List<ProviderConfig> providers) {
- this.protocols = convertProviderToProtocol(providers);
- }
-
- @Override
- @Parameter(excluded = true)
- public String getPrefix() {
- return DUBBO + ".service." + interfaceName;
- }
-}
+
+/*
+ * 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 org.apache.dubbo.config;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.URLBuilder;
+import org.apache.dubbo.common.Version;
+import org.apache.dubbo.common.bytecode.Wrapper;
+import org.apache.dubbo.common.config.Environment;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.utils.ClassUtils;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.common.utils.ConfigUtils;
+import org.apache.dubbo.common.utils.NamedThreadFactory;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.config.annotation.Service;
+import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.config.event.ServiceConfigExportedEvent;
+import org.apache.dubbo.config.event.ServiceConfigUnexportedEvent;
+import org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker;
+import org.apache.dubbo.config.support.Parameter;
+import org.apache.dubbo.event.Event;
+import org.apache.dubbo.event.EventDispatcher;
+import org.apache.dubbo.metadata.integration.MetadataReportService;
+import org.apache.dubbo.remoting.Constants;
+import org.apache.dubbo.rpc.Exporter;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Protocol;
+import org.apache.dubbo.rpc.ProxyFactory;
+import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.ProviderModel;
+import org.apache.dubbo.rpc.service.GenericService;
+import org.apache.dubbo.rpc.support.ProtocolUtils;
+
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
+import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND;
+import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
+import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
+import static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;
+import static org.apache.dubbo.common.utils.NetUtils.getAvailablePort;
+import static org.apache.dubbo.common.utils.NetUtils.getLocalHost;
+import static org.apache.dubbo.common.utils.NetUtils.isInvalidLocalHost;
+import static org.apache.dubbo.common.utils.NetUtils.isInvalidPort;
+import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY;
+import static org.apache.dubbo.config.Constants.DUBBO_PORT_TO_BIND;
+import static org.apache.dubbo.config.Constants.DUBBO_PORT_TO_REGISTRY;
+import static org.apache.dubbo.config.Constants.MULTICAST;
+import static org.apache.dubbo.config.Constants.PROTOCOLS_SUFFIX;
+import static org.apache.dubbo.config.Constants.SCOPE_NONE;
+import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
+import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
+import static org.apache.dubbo.rpc.Constants.PROXY_KEY;
+import static org.apache.dubbo.rpc.Constants.SCOPE_KEY;
+import static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;
+import static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;
+import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.EXPORT_KEY;
+
+/**
+ * ServiceConfig
+ *
+ * @export
+ */
+public class ServiceConfig<T> extends AbstractServiceConfig {
+
+ private static final long serialVersionUID = 3033787999037024738L;
+
+ /**
+ * The {@link Protocol} implementation with adaptive functionality,it will be different in different scenarios.
+ * A particular {@link Protocol} implementation is determined by the protocol attribute in the {@link URL}.
+ * For example:
+ *
+ * <li>when the url is registry://224.5.6.7:1234/org.apache.dubbo.registry.RegistryService?application=dubbo-sample,
+ * then the protocol is <b>RegistryProtocol</b></li>
+ *
+ * <li>when the url is dubbo://224.5.6.7:1234/org.apache.dubbo.config.api.DemoService?application=dubbo-sample, then
+ * the protocol is <b>DubboProtocol</b></li>
+ * <p>
+ * Actually,when the {@link ExtensionLoader} init the {@link Protocol} instants,it will automatically wraps two
+ * layers, and eventually will get a <b>ProtocolFilterWrapper</b> or <b>ProtocolListenerWrapper</b>
+ */
+ private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
+
+ /**
+ * A {@link ProxyFactory} implementation that will generate a exported service proxy,the JavassistProxyFactory is its
+ * default implementation
+ */
+ private static final ProxyFactory PROXY_FACTORY = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
+
+ /**
+ * A random port cache, the different protocols who has no port specified have different random port
+ */
+ private static final Map<String, Integer> RANDOM_PORT_MAP = new HashMap<String, Integer>();
+
+ /**
+ * A delayed exposure service timer
+ */
+ private static final ScheduledExecutorService DELAY_EXPORT_EXECUTOR = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true));
+
+ /**
+ * The urls of the services exported
+ */
+ private final List<URL> urls = new ArrayList<URL>();
+
+ /**
+ * The exported services
+ */
+ private final List<Exporter<?>> exporters = new ArrayList<Exporter<?>>();
+
+ /**
+ * The interface name of the exported service
+ */
+ private String interfaceName;
+
+ /**
+ * The interface class of the exported service
+ */
+ private Class<?> interfaceClass;
+
+ /**
+ * The reference of the interface implementation
+ */
+ private T ref;
+
+ /**
+ * The service name
+ */
+ private String path;
+
+ /**
+ * The method configuration
+ */
+ private List<MethodConfig> methods;
+
+ /**
+ * The provider configuration
+ */
+ private ProviderConfig provider;
+
+ /**
+ * The providerIds
+ */
+ private String providerIds;
+
+ /**
+ * Whether the provider has been exported
+ */
+ private transient volatile boolean exported;
+
+ /**
+ * The flag whether a service has unexported ,if the method unexported is invoked, the value is true
+ */
+ private transient volatile boolean unexported;
+
+ /**
+ * whether it is a GenericService
+ */
+ private volatile String generic;
+
+ /**
+ * @since 2.7.3
+ */
+ private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension();
+
+
+ public ServiceConfig() {
+ }
+
+ public ServiceConfig(Service service) {
+ appendAnnotation(Service.class, service);
+ setMethods(MethodConfig.constructMethodConfig(service.methods()));
+ }
+
+ @Deprecated
+ private static List<ProtocolConfig> convertProviderToProtocol(List<ProviderConfig> providers) {
+ if (CollectionUtils.isEmpty(providers)) {
+ return null;
+ }
+ List<ProtocolConfig> protocols = new ArrayList<ProtocolConfig>(providers.size());
+ for (ProviderConfig provider : providers) {
+ protocols.add(convertProviderToProtocol(provider));
+ }
+ return protocols;
+ }
+
+ @Deprecated
+ private static List<ProviderConfig> convertProtocolToProvider(List<ProtocolConfig> protocols) {
+ if (CollectionUtils.isEmpty(protocols)) {
+ return null;
+ }
+ List<ProviderConfig> providers = new ArrayList<ProviderConfig>(protocols.size());
+ for (ProtocolConfig provider : protocols) {
+ providers.add(convertProtocolToProvider(provider));
+ }
+ return providers;
+ }
+
+ @Deprecated
+ private static ProtocolConfig convertProviderToProtocol(ProviderConfig provider) {
+ ProtocolConfig protocol = new ProtocolConfig();
+ protocol.setName(provider.getProtocol().getName());
+ protocol.setServer(provider.getServer());
+ protocol.setClient(provider.getClient());
+ protocol.setCodec(provider.getCodec());
+ protocol.setHost(provider.getHost());
+ protocol.setPort(provider.getPort());
+ protocol.setPath(provider.getPath());
+ protocol.setPayload(provider.getPayload());
+ protocol.setThreads(provider.getThreads());
+ protocol.setParameters(provider.getParameters());
+ return protocol;
+ }
+
+ @Deprecated
+ private static ProviderConfig convertProtocolToProvider(ProtocolConfig protocol) {
+ ProviderConfig provider = new ProviderConfig();
+ provider.setProtocol(protocol);
+ provider.setServer(protocol.getServer());
+ provider.setClient(protocol.getClient());
+ provider.setCodec(protocol.getCodec());
+ provider.setHost(protocol.getHost());
+ provider.setPort(protocol.getPort());
+ provider.setPath(protocol.getPath());
+ provider.setPayload(protocol.getPayload());
+ provider.setThreads(protocol.getThreads());
+ provider.setParameters(protocol.getParameters());
+ return provider;
+ }
+
+ private static Integer getRandomPort(String protocol) {
+ protocol = protocol.toLowerCase();
+ return RANDOM_PORT_MAP.getOrDefault(protocol, Integer.MIN_VALUE);
+ }
+
+ private static void putRandomPort(String protocol, Integer port) {
+ protocol = protocol.toLowerCase();
+ if (!RANDOM_PORT_MAP.containsKey(protocol)) {
+ RANDOM_PORT_MAP.put(protocol, port);
+ logger.warn("Use random available port(" + port + ") for protocol " + protocol);
+ }
+ }
+
+ public URL toUrl() {
+ return urls.isEmpty() ? null : urls.iterator().next();
+ }
+
+ public List<URL> toUrls() {
+ return urls;
+ }
+
+ @Parameter(excluded = true)
+ public boolean isExported() {
+ return exported;
+ }
+
+ @Parameter(excluded = true)
+ public boolean isUnexported() {
+ return unexported;
+ }
+
+ public void checkAndUpdateSubConfigs() {
+ // Use default configs defined explicitly on global configs
+ completeCompoundConfigs();
+ // Config Center should always being started first.
+ startConfigCenter();
+ checkDefault();
+ checkProtocol();
+ checkApplication();
+ // if protocol is not injvm checkRegistry
+ if (!isOnlyInJvm()) {
+ checkRegistry();
+ }
+ this.refresh();
+ checkMetadataReport();
+
+ if (StringUtils.isEmpty(interfaceName)) {
+ throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
+ }
+
+ if (ref instanceof GenericService) {
+ interfaceClass = GenericService.class;
+ if (StringUtils.isEmpty(generic)) {
+ generic = Boolean.TRUE.toString();
+ }
+ } else {
+ try {
+ interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
+ .getContextClassLoader());
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ checkInterfaceAndMethods(interfaceClass, methods);
+ checkRef();
+ generic = Boolean.FALSE.toString();
+ }
+ if (local != null) {
+ if ("true".equals(local)) {
+ local = interfaceName + "Local";
+ }
+ Class<?> localClass;
+ try {
+ localClass = ClassUtils.forNameWithThreadContextClassLoader(local);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ if (!interfaceClass.isAssignableFrom(localClass)) {
+ throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName);
+ }
+ }
+ if (stub != null) {
+ if ("true".equals(stub)) {
+ stub = interfaceName + "Stub";
+ }
+ Class<?> stubClass;
+ try {
+ stubClass = ClassUtils.forNameWithThreadContextClassLoader(stub);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ if (!interfaceClass.isAssignableFrom(stubClass)) {
+ throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
+ }
+ }
+ checkStubAndLocal(interfaceClass);
+ checkMock(interfaceClass);
+ }
+
+ /**
+ * Determine if it is injvm
+ *
+ * @return
+ */
+ private boolean isOnlyInJvm() {
+ return getProtocols().size() == 1 && LOCAL_PROTOCOL.equalsIgnoreCase(getProtocols().get(0).getName());
+ }
+
+ public synchronized void export() {
+ checkAndUpdateSubConfigs();
+
+ if (!shouldExport()) {
+ return;
+ }
+
+ if (shouldDelay()) {
+ DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
+ } else {
+ doExport();
+ }
+ }
+
+ private boolean shouldExport() {
+ Boolean export = getExport();
+ // default value is true
+ return export == null ? true : export;
+ }
+
+ @Override
+ public Boolean getExport() {
+ return (export == null && provider != null) ? provider.getExport() : export;
+ }
+
+ private boolean shouldDelay() {
+ Integer delay = getDelay();
+ return delay != null && delay > 0;
+ }
+
+ @Override
+ public Integer getDelay() {
+ return (delay == null && provider != null) ? provider.getDelay() : delay;
+ }
+
+ protected synchronized void doExport() {
+ if (unexported) {
+ throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!");
+ }
+ if (exported) {
+ return;
+ }
+ exported = true;
+
+ if (StringUtils.isEmpty(path)) {
+ path = interfaceName;
+ }
+ doExportUrls();
+
+ // dispatch a ServiceConfigExportedEvent since 2.7.3
+ dispatch(new ServiceConfigExportedEvent(this));
+ }
+
+ private void checkRef() {
+ // reference should not be null, and is the implementation of the given interface
+ if (ref == null) {
+ throw new IllegalStateException("ref not allow null!");
+ }
+ if (!interfaceClass.isInstance(ref)) {
+ throw new IllegalStateException("The class "
+ + ref.getClass().getName() + " unimplemented interface "
+ + interfaceClass + "!");
+ }
+ }
+
+ public synchronized void unexport() {
+ if (!exported) {
+ return;
+ }
+ if (unexported) {
+ return;
+ }
+ if (!exporters.isEmpty()) {
+ for (Exporter<?> exporter : exporters) {
+ try {
+ exporter.unexport();
+ } catch (Throwable t) {
+ logger.warn("Unexpected error occured when unexport " + exporter, t);
+ }
+ }
+ exporters.clear();
+ }
+ unexported = true;
+
+ // dispatch a ServiceConfigUnExportedEvent since 2.7.3
+ dispatch(new ServiceConfigUnexportedEvent(this));
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ private void doExportUrls() {
+ List<URL> registryURLs = loadRegistries(true);
+ for (ProtocolConfig protocolConfig : protocols) {
+ String pathKey = URL.buildKey(getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), group, version);
+ ProviderModel providerModel = new ProviderModel(pathKey, ref, interfaceClass);
+ ApplicationModel.initProviderModel(pathKey, providerModel);
+ doExportUrlsFor1Protocol(protocolConfig, registryURLs);
+ }
+ }
+
+ private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
+ String name = protocolConfig.getName();
+ if (StringUtils.isEmpty(name)) {
+ name = DUBBO;
+ }
+
+ Map<String, String> map = new HashMap<String, String>();
+ map.put(SIDE_KEY, PROVIDER_SIDE);
+
+ appendRuntimeParameters(map);
+ appendParameters(map, metrics);
+ appendParameters(map, application);
+ appendParameters(map, module);
+ // remove 'default.' prefix for configs from ProviderConfig
+ // appendParameters(map, provider, Constants.DEFAULT_KEY);
+ appendParameters(map, provider);
+ appendParameters(map, protocolConfig);
+ appendParameters(map, this);
+ if (CollectionUtils.isNotEmpty(methods)) {
+ for (MethodConfig method : methods) {
+ appendParameters(map, method, method.getName());
+ String retryKey = method.getName() + ".retry";
+ if (map.containsKey(retryKey)) {
+ String retryValue = map.remove(retryKey);
+ if ("false".equals(retryValue)) {
+ map.put(method.getName() + ".retries", "0");
+ }
+ }
+ List<ArgumentConfig> arguments = method.getArguments();
+ if (CollectionUtils.isNotEmpty(arguments)) {
+ for (ArgumentConfig argument : arguments) {
+ // convert argument type
+ if (argument.getType() != null && argument.getType().length() > 0) {
+ Method[] methods = interfaceClass.getMethods();
+ // visit all methods
+ if (methods != null && methods.length > 0) {
+ for (int i = 0; i < methods.length; i++) {
+ String methodName = methods[i].getName();
+ // target the method, and get its signature
+ if (methodName.equals(method.getName())) {
+ Class<?>[] argtypes = methods[i].getParameterTypes();
+ // one callback in the method
+ if (argument.getIndex() != -1) {
+ if (argtypes[argument.getIndex()].getName().equals(argument.getType())) {
+ appendParameters(map, argument, method.getName() + "." + argument.getIndex());
+ } else {
+ throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
+ }
+ } else {
+ // multiple callbacks in the method
+ for (int j = 0; j < argtypes.length; j++) {
+ Class<?> argclazz = argtypes[j];
+ if (argclazz.getName().equals(argument.getType())) {
+ appendParameters(map, argument, method.getName() + "." + j);
+ if (argument.getIndex() != -1 && argument.getIndex() != j) {
+ throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } else if (argument.getIndex() != -1) {
+ appendParameters(map, argument, method.getName() + "." + argument.getIndex());
+ } else {
+ throw new IllegalArgumentException("Argument config must set index or type attribute.eg: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>");
+ }
+
+ }
+ }
+ } // end of methods for
+ }
+
+ if (ProtocolUtils.isGeneric(generic)) {
+ map.put(GENERIC_KEY, generic);
+ map.put(METHODS_KEY, ANY_VALUE);
+ } else {
+ String revision = Version.getVersion(interfaceClass, version);
+ if (revision != null && revision.length() > 0) {
+ map.put(REVISION_KEY, revision);
+ }
+
+ String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
+ if (methods.length == 0) {
+ logger.warn("No method found in service interface " + interfaceClass.getName());
+ map.put(METHODS_KEY, ANY_VALUE);
+ } else {
+ map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
+ }
+ }
+ if (!ConfigUtils.isEmpty(token)) {
+ if (ConfigUtils.isDefault(token)) {
+ map.put(TOKEN_KEY, UUID.randomUUID().toString());
+ } else {
+ map.put(TOKEN_KEY, token);
+ }
+ }
+ // export service
+ String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
+ Integer port = this.findConfigedPorts(protocolConfig, name, map);
+ URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
+
+ if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
+ .hasExtension(url.getProtocol())) {
+ url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
+ .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
+ }
+
+ String scope = url.getParameter(SCOPE_KEY);
+ // don't export when none is configured
+ if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
+
+ // export to local if the config is not remote (export to remote only when config is remote)
+ if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
+ exportLocal(url);
+ }
+ // export to remote if the config is not local (export to local only when config is local)
+ if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
+ if (!isOnlyInJvm() && logger.isInfoEnabled()) {
+ logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
+ }
+ if (CollectionUtils.isNotEmpty(registryURLs)) {
+ for (URL registryURL : registryURLs) {
+ //if protocol is only injvm ,not register
+ if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
+ continue;
+ }
+ url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));
+ URL monitorUrl = loadMonitor(registryURL);
+ if (monitorUrl != null) {
+ url = url.addParameterAndEncoded(MONITOR_KEY, monitorUrl.toFullString());
+ }
+ if (logger.isInfoEnabled()) {
+ logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
+ }
+
+ // For providers, this is used to enable custom proxy to generate invoker
+ String proxy = url.getParameter(PROXY_KEY);
+ if (StringUtils.isNotEmpty(proxy)) {
+ registryURL = registryURL.addParameter(PROXY_KEY, proxy);
+ }
+
+ Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
+ DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
+
+ Exporter<?> exporter = protocol.export(wrapperInvoker);
+ exporters.add(exporter);
+ }
+ } else {
+ Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, url);
+ DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
+
+ Exporter<?> exporter = protocol.export(wrapperInvoker);
+ exporters.add(exporter);
+ }
+ /**
+ * @since 2.7.0
+ * ServiceData Store
+ */
+ MetadataReportService metadataReportService = null;
+ if ((metadataReportService = getMetadataReportService()) != null) {
+ metadataReportService.publishProvider(url);
+ }
+ }
+ }
+ this.urls.add(url);
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ /**
+ * always export injvm
+ */
+ private void exportLocal(URL url) {
+ URL local = URLBuilder.from(url)
+ .setProtocol(LOCAL_PROTOCOL)
+ .setHost(LOCALHOST_VALUE)
+ .setPort(0)
+ .build();
+ Exporter<?> exporter = protocol.export(
+ PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, local));
+ exporters.add(exporter);
+ logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry url : " + local);
+ }
+
+ private Optional<String> getContextPath(ProtocolConfig protocolConfig) {
+ String contextPath = protocolConfig.getContextpath();
+ if (StringUtils.isEmpty(contextPath) && provider != null) {
+ contextPath = provider.getContextpath();
+ }
+ return Optional.ofNullable(contextPath);
+ }
+
+ protected Class getServiceClass(T ref) {
+ return ref.getClass();
+ }
+
+ /**
+ * Register & bind IP address for service provider, can be configured separately.
+ * Configuration priority: environment variables -> java system properties -> host property in config file ->
+ * /etc/hosts -> default network address -> first available network address
+ *
+ * @param protocolConfig
+ * @param registryURLs
+ * @param map
+ * @return
+ */
+ private String findConfigedHosts(ProtocolConfig protocolConfig, List<URL> registryURLs, Map<String, String> map) {
+ boolean anyhost = false;
+
+ String hostToBind = getValueFromConfig(protocolConfig, DUBBO_IP_TO_BIND);
+ if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) {
+ throw new IllegalArgumentException("Specified invalid bind ip from property:" + DUBBO_IP_TO_BIND + ", value:" + hostToBind);
+ }
+
+ // if bind ip is not found in environment, keep looking up
+ if (StringUtils.isEmpty(hostToBind)) {
+ hostToBind = protocolConfig.getHost();
+ if (provider != null && StringUtils.isEmpty(hostToBind)) {
+ hostToBind = provider.getHost();
+ }
+ if (isInvalidLocalHost(hostToBind)) {
+ anyhost = true;
+ try {
+ hostToBind = InetAddress.getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ logger.warn(e.getMessage(), e);
+ }
+ if (isInvalidLocalHost(hostToBind)) {
+ if (CollectionUtils.isNotEmpty(registryURLs)) {
+ for (URL registryURL : registryURLs) {
+ if (MULTICAST.equalsIgnoreCase(registryURL.getParameter("registry"))) {
+ // skip multicast registry since we cannot connect to it via Socket
+ continue;
+ }
+ try (Socket socket = new Socket()) {
+ SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
+ socket.connect(addr, 1000);
+ hostToBind = socket.getLocalAddress().getHostAddress();
+ break;
+ } catch (Exception e) {
+ logger.warn(e.getMessage(), e);
+ }
+ }
+ }
+ if (isInvalidLocalHost(hostToBind)) {
+ hostToBind = getLocalHost();
+ }
+ }
+ }
+ }
+
+ map.put(Constants.BIND_IP_KEY, hostToBind);
+
+ // registry ip is not used for bind ip by default
+ String hostToRegistry = getValueFromConfig(protocolConfig, DUBBO_IP_TO_REGISTRY);
+ if (hostToRegistry != null && hostToRegistry.length() > 0 && isInvalidLocalHost(hostToRegistry)) {
+ throw new IllegalArgumentException("Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
+ } else if (StringUtils.isEmpty(hostToRegistry)) {
+ // bind ip is used as registry ip by default
+ hostToRegistry = hostToBind;
+ }
+
+ map.put(ANYHOST_KEY, String.valueOf(anyhost));
+
+ return hostToRegistry;
+ }
+
+ /**
+ * Register port and bind port for the provider, can be configured separately
+ * Configuration priority: environment variable -> java system properties -> port property in protocol config file
+ * -> protocol default port
+ *
+ * @param protocolConfig
+ * @param name
+ * @return
+ */
+ private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map<String, String> map) {
+ Integer portToBind = null;
+
+ // parse bind port from environment
+ String port = getValueFromConfig(protocolConfig, DUBBO_PORT_TO_BIND);
+ portToBind = parsePort(port);
+
+ // if there's no bind port found from environment, keep looking up.
+ if (portToBind == null) {
+ portToBind = protocolConfig.getPort();
+ if (provider != null && (portToBind == null || portToBind == 0)) {
+ portToBind = provider.getPort();
+ }
+ final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();
+ if (portToBind == null || portToBind == 0) {
+ portToBind = defaultPort;
+ }
+ if (portToBind == null || portToBind <= 0) {
+ portToBind = getRandomPort(name);
+ if (portToBind == null || portToBind < 0) {
+ portToBind = getAvailablePort(defaultPort);
+ putRandomPort(name, portToBind);
+ }
+ }
+ }
+
+ // save bind port, used as url's key later
+ map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind));
+
+ // registry port, not used as bind port by default
+ String portToRegistryStr = getValueFromConfig(protocolConfig, DUBBO_PORT_TO_REGISTRY);
+ Integer portToRegistry = parsePort(portToRegistryStr);
+ if (portToRegistry == null) {
+ portToRegistry = portToBind;
+ }
+
+ return portToRegistry;
+ }
+
+ private Integer parsePort(String configPort) {
+ Integer port = null;
+ if (configPort != null && configPort.length() > 0) {
+ try {
+ Integer intPort = Integer.parseInt(configPort);
+ if (isInvalidPort(intPort)) {
+ throw new IllegalArgumentException("Specified invalid port from env value:" + configPort);
+ }
+ port = intPort;
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Specified invalid port from env value:" + configPort);
+ }
+ }
+ return port;
+ }
+
+ private String getValueFromConfig(ProtocolConfig protocolConfig, String key) {
+ String protocolPrefix = protocolConfig.getName().toUpperCase() + "_";
+ String port = ConfigUtils.getSystemProperty(protocolPrefix + key);
+ if (StringUtils.isEmpty(port)) {
+ port = ConfigUtils.getSystemProperty(key);
+ }
+ return port;
+ }
+
+ private void completeCompoundConfigs() {
+ if (provider != null) {
+ if (application == null) {
+ setApplication(provider.getApplication());
+ }
+ if (module == null) {
+ setModule(provider.getModule());
+ }
+ if (registries == null) {
+ setRegistries(provider.getRegistries());
+ }
+ if (monitor == null) {
+ setMonitor(provider.getMonitor());
+ }
+ if (protocols == null) {
+ setProtocols(provider.getProtocols());
+ }
+ if (configCenter == null) {
+ setConfigCenter(provider.getConfigCenter());
+ }
+ }
+ if (module != null) {
+ if (registries == null) {
+ setRegistries(module.getRegistries());
+ }
+ if (monitor == null) {
+ setMonitor(module.getMonitor());
+ }
+ }
+ if (application != null) {
+ if (registries == null) {
+ setRegistries(application.getRegistries());
+ }
+ if (monitor == null) {
+ setMonitor(application.getMonitor());
+ }
+ }
+ }
+
+ private void checkDefault() {
+ createProviderIfAbsent();
+ }
+
+ private void createProviderIfAbsent() {
+ if (provider != null) {
+ return;
+ }
+ setProvider(
+ ConfigManager.getInstance()
+ .getDefaultProvider()
+ .orElseGet(() -> {
+ ProviderConfig providerConfig = new ProviderConfig();
+ providerConfig.refresh();
+ return providerConfig;
+ })
+ );
+ }
+
+ private void checkProtocol() {
+ if (CollectionUtils.isEmpty(protocols) && provider != null) {
+ setProtocols(provider.getProtocols());
+ }
+ convertProtocolIdsToProtocols();
+ }
+
+ private void convertProtocolIdsToProtocols() {
+ if (StringUtils.isEmpty(protocolIds) && CollectionUtils.isEmpty(protocols)) {
+ List<String> configedProtocols = new ArrayList<>();
+ configedProtocols.addAll(getSubProperties(Environment.getInstance()
+ .getExternalConfigurationMap(), PROTOCOLS_SUFFIX));
+ configedProtocols.addAll(getSubProperties(Environment.getInstance()
+ .getAppExternalConfigurationMap(), PROTOCOLS_SUFFIX));
+
+ protocolIds = String.join(",", configedProtocols);
+ }
+
+ if (StringUtils.isEmpty(protocolIds)) {
+ if (CollectionUtils.isEmpty(protocols)) {
+ setProtocols(
+ ConfigManager.getInstance().getDefaultProtocols()
+ .filter(CollectionUtils::isNotEmpty)
+ .orElseGet(() -> {
+ ProtocolConfig protocolConfig = new ProtocolConfig();
+ protocolConfig.refresh();
+ return new ArrayList<>(Arrays.asList(protocolConfig));
+ })
+ );
+ }
+ } else {
+ String[] arr = COMMA_SPLIT_PATTERN.split(protocolIds);
+ List<ProtocolConfig> tmpProtocols = CollectionUtils.isNotEmpty(protocols) ? protocols : new ArrayList<>();
+ Arrays.stream(arr).forEach(id -> {
+ if (tmpProtocols.stream().noneMatch(prot -> prot.getId().equals(id))) {
+ tmpProtocols.add(ConfigManager.getInstance().getProtocol(id).orElseGet(() -> {
+ ProtocolConfig protocolConfig = new ProtocolConfig();
+ protocolConfig.setId(id);
+ protocolConfig.refresh();
+ return protocolConfig;
+ }));
+ }
+ });
+ if (tmpProtocols.size() > arr.length) {
+ throw new IllegalStateException("Too much protocols found, the protocols comply to this service are :" + protocolIds + " but got " + protocols
+ .size() + " registries!");
+ }
+ setProtocols(tmpProtocols);
+ }
+ }
+
+ public Class<?> getInterfaceClass() {
+ if (interfaceClass != null) {
+ return interfaceClass;
+ }
+ if (ref instanceof GenericService) {
+ return GenericService.class;
+ }
+ try {
+ if (interfaceName != null && interfaceName.length() > 0) {
+ this.interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
+ .getContextClassLoader());
+ }
+ } catch (ClassNotFoundException t) {
+ throw new IllegalStateException(t.getMessage(), t);
+ }
+ return interfaceClass;
+ }
+
+ /**
+ * @param interfaceClass
+ * @see #setInterface(Class)
+ * @deprecated
+ */
+ public void setInterfaceClass(Class<?> interfaceClass) {
+ setInterface(interfaceClass);
+ }
+
+ public String getInterface() {
+ return interfaceName;
+ }
+
+ public void setInterface(Class<?> interfaceClass) {
+ if (interfaceClass != null && !interfaceClass.isInterface()) {
+ throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!");
+ }
+ this.interfaceClass = interfaceClass;
+ setInterface(interfaceClass == null ? null : interfaceClass.getName());
+ }
+
+ public void setInterface(String interfaceName) {
+ this.interfaceName = interfaceName;
+ if (StringUtils.isEmpty(id)) {
+ id = interfaceName;
+ }
+ }
+
+ public T getRef() {
+ return ref;
+ }
+
+ public void setRef(T ref) {
+ this.ref = ref;
+ }
+
+ @Parameter(excluded = true)
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ checkPathName(PATH_KEY, path);
+ this.path = path;
+ }
+
+ public List<MethodConfig> getMethods() {
+ return methods;
+ }
+
+ // ======== Deprecated ========
+
+ @SuppressWarnings("unchecked")
+ public void setMethods(List<? extends MethodConfig> methods) {
+ this.methods = (List<MethodConfig>) methods;
+ }
+
+ public ProviderConfig getProvider() {
+ return provider;
+ }
+
+ public void setProvider(ProviderConfig provider) {
+ ConfigManager.getInstance().addProvider(provider);
+ this.provider = provider;
+ }
+
+ @Parameter(excluded = true)
+ public String getProviderIds() {
+ return providerIds;
+ }
+
+ public void setProviderIds(String providerIds) {
+ this.providerIds = providerIds;
+ }
+
+ public String getGeneric() {
+ return generic;
+ }
+
+ public void setGeneric(String generic) {
+ if (StringUtils.isEmpty(generic)) {
+ return;
+ }
+ if (ProtocolUtils.isGeneric(generic)) {
+ this.generic = generic;
+ } else {
+ throw new IllegalArgumentException("Unsupported generic type " + generic);
+ }
+ }
+
+ @Override
+ public void setMock(Boolean mock) {
+ throw new IllegalArgumentException("mock doesn't support on provider side");
+ }
+
+ @Override
+ public void setMock(String mock) {
+ throw new IllegalArgumentException("mock doesn't support on provider side");
+ }
+
+ public List<URL> getExportedUrls() {
+ return urls;
+ }
+
+ /**
+ * @deprecated Replace to getProtocols()
+ */
+ @Deprecated
+ public List<ProviderConfig> getProviders() {
+ return convertProtocolToProvider(protocols);
+ }
+
+ /**
+ * @deprecated Replace to setProtocols()
+ */
+ @Deprecated
+ public void setProviders(List<ProviderConfig> providers) {
+ this.protocols = convertProviderToProtocol(providers);
+ }
+
+ @Override
+ @Parameter(excluded = true)
+ public String getPrefix() {
+ return DUBBO + ".service." + interfaceName;
+ }
+
+ /**
+ * Dispatch an {@link Event event}
+ *
+ * @param event an {@link Event event}
+ * @since 2.7.3
+ */
+ protected void dispatch(Event event) {
+ eventDispatcher.dispatch(event);
+ }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java
index d1e33c6..12d09bf 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java
@@ -25,9 +25,11 @@ import java.util.Map;
/**
* AbstractBuilder
*
+ * @param <C> The type of {@link AbstractConfig Config}
+ * @param <B> The type of {@link AbstractBuilder Builder}
* @since 2.7
*/
-public abstract class AbstractBuilder<T extends AbstractConfig, B extends AbstractBuilder> {
+public abstract class AbstractBuilder<C extends AbstractConfig, B extends AbstractBuilder> {
/**
* The config id
*/
@@ -62,7 +64,7 @@ public abstract class AbstractBuilder<T extends AbstractConfig, B extends Abstra
return parameters;
}
- protected void build(T instance) {
+ protected void build(C instance) {
if (!StringUtils.isEmpty(id)) {
instance.setId(id);
}
@@ -70,4 +72,11 @@ public abstract class AbstractBuilder<T extends AbstractConfig, B extends Abstra
instance.setPrefix(prefix);
}
}
+
+ /**
+ * Build an instance of {@link AbstractConfig config}
+ *
+ * @return an instance of {@link AbstractConfig config}
+ */
+ public abstract C build();
}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ProtocolBuilder.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ProtocolBuilder.java
index 42e5550..4ddd943 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ProtocolBuilder.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ProtocolBuilder.java
@@ -185,6 +185,10 @@ public class ProtocolBuilder extends AbstractBuilder<ProtocolConfig, ProtocolBui
*/
private Boolean isDefault;
+ public ProtocolBuilder id(String id) {
+ return super.id(id);
+ }
+
public ProtocolBuilder name(String name) {
this.name = name;
return getThis();
@@ -206,9 +210,9 @@ public class ProtocolBuilder extends AbstractBuilder<ProtocolConfig, ProtocolBui
}
/**
- * @see org.apache.dubbo.config.builders.ProtocolBuilder#contextpath(String)
* @param path
* @return ProtocolBuilder
+ * @see org.apache.dubbo.config.builders.ProtocolBuilder#contextpath(String)
*/
@Deprecated
public ProtocolBuilder path(String path) {
@@ -297,9 +301,9 @@ public class ProtocolBuilder extends AbstractBuilder<ProtocolConfig, ProtocolBui
}
/**
- * @see org.apache.dubbo.config.builders.ProtocolBuilder#dispatcher(String)
* @param dispather
* @return ProtocolBuilder
+ * @see org.apache.dubbo.config.builders.ProtocolBuilder#dispatcher(String)
*/
@Deprecated
public ProtocolBuilder dispather(String dispather) {
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ReferenceBuilder.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ReferenceBuilder.java
index d0df602..52ceb94 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ReferenceBuilder.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ReferenceBuilder.java
@@ -64,6 +64,10 @@ public class ReferenceBuilder<T> extends AbstractReferenceBuilder<ReferenceConfi
*/
private String protocol;
+ public ReferenceBuilder<T> id(String id) {
+ return super.id(id);
+ }
+
public ReferenceBuilder<T> interfaceName(String interfaceName) {
this.interfaceName = interfaceName;
return getThis();
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/RegistryBuilder.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/RegistryBuilder.java
index f64e595..616e6af 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/RegistryBuilder.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/RegistryBuilder.java
@@ -16,10 +16,10 @@
*/
package org.apache.dubbo.config.builders;
-import java.util.Map;
-
import org.apache.dubbo.config.RegistryConfig;
+import java.util.Map;
+
/**
* This is a builder for build {@link RegistryConfig}.
*
@@ -134,6 +134,10 @@ public class RegistryBuilder extends AbstractBuilder<RegistryConfig, RegistryBui
*/
private String extraKeys;
+ public RegistryBuilder id(String id) {
+ return super.id(id);
+ }
+
public RegistryBuilder address(String address) {
this.address = address;
return getThis();
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ServiceBuilder.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ServiceBuilder.java
index 6628d3a..65cc916 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ServiceBuilder.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ServiceBuilder.java
@@ -16,13 +16,13 @@
*/
package org.apache.dubbo.config.builders;
-import java.util.ArrayList;
-import java.util.List;
-
import org.apache.dubbo.config.MethodConfig;
import org.apache.dubbo.config.ProviderConfig;
import org.apache.dubbo.config.ServiceConfig;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* This is a builder for build {@link ServiceConfig}.
*
@@ -68,6 +68,10 @@ public class ServiceBuilder<U> extends AbstractServiceBuilder<ServiceConfig, Ser
*/
private String generic;
+ public ServiceBuilder id(String id) {
+ return super.id(id);
+ }
+
public ServiceBuilder<U> interfaceName(String interfaceName) {
this.interfaceName = interfaceName;
return getThis();
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/DubboServiceDestroyedEvent.java
similarity index 71%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/DubboServiceDestroyedEvent.java
index c5bc722..a3384aa 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/DubboServiceDestroyedEvent.java
@@ -14,24 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.api;
-
-import java.util.List;
+package org.apache.dubbo.config.event;
+import org.apache.dubbo.event.Event;
/**
- * DemoService
+ * An {@link Event Dubbo event} when the Dubbo service is about to be destroyed.
+ *
+ * @see Event
+ * @since 2.7.3
*/
-public interface DemoService {
-
- String sayName(String name);
-
- Box getBox();
-
- void throwDemoException() throws DemoException;
-
- List<User> getUsers(List<User> users);
-
- int echo(int i);
+public class DubboServiceDestroyedEvent extends Event {
-}
\ No newline at end of file
+ public DubboServiceDestroyedEvent(Object source) {
+ super(source);
+ }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ReferenceConfigDestroyedEvent.java
similarity index 56%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ReferenceConfigDestroyedEvent.java
index c5bc722..8f07e51 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ReferenceConfigDestroyedEvent.java
@@ -14,24 +14,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.api;
-
-import java.util.List;
+package org.apache.dubbo.config.event;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.annotation.Reference;
+import org.apache.dubbo.event.Event;
/**
- * DemoService
+ * The {@link ReferenceConfig Dubbo service ReferenceConfig} destroyed {@link Event event}
+ *
+ * @see Reference
+ * @see ReferenceConfig#destroy()
+ * @see Event
+ * @since 2.7.3
*/
-public interface DemoService {
-
- String sayName(String name);
-
- Box getBox();
-
- void throwDemoException() throws DemoException;
+public class ReferenceConfigDestroyedEvent extends Event {
- List<User> getUsers(List<User> users);
+ public ReferenceConfigDestroyedEvent(ReferenceConfig referenceConfig) {
+ super(referenceConfig);
+ }
- int echo(int i);
+ public ReferenceConfig getReferenceConfig() {
+ return (ReferenceConfig) getSource();
+ }
}
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/provider/impl/DemoServiceImpl.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ReferenceConfigInitializedEvent.java
similarity index 50%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/provider/impl/DemoServiceImpl.java
copy to dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ReferenceConfigInitializedEvent.java
index d81269e..359c8bc 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/provider/impl/DemoServiceImpl.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ReferenceConfigInitializedEvent.java
@@ -14,38 +14,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.provider.impl;
+package org.apache.dubbo.config.event;
-import org.apache.dubbo.config.api.Box;
-import org.apache.dubbo.config.api.DemoException;
-import org.apache.dubbo.config.api.DemoService;
-import org.apache.dubbo.config.api.User;
-
-import java.util.List;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.annotation.Reference;
+import org.apache.dubbo.event.Event;
+import org.apache.dubbo.rpc.Invoker;
/**
- * DemoServiceImpl
+ * The {@link ReferenceConfig Dubbo service ReferenceConfig} initialized {@link Event event}
+ *
+ * @see Reference
+ * @see ReferenceConfig#get()
+ * @see Event
+ * @since 2.7.3
*/
-public class DemoServiceImpl implements DemoService {
-
- public String sayName(String name) {
- return "say:" + name;
- }
+public class ReferenceConfigInitializedEvent extends Event {
- public Box getBox() {
- return null;
- }
+ private final Invoker<?> invoker;
- public void throwDemoException() throws DemoException {
- throw new DemoException("DemoServiceImpl");
+ public ReferenceConfigInitializedEvent(ReferenceConfig referenceConfig, Invoker<?> invoker) {
+ super(referenceConfig);
+ this.invoker = invoker;
}
- public List<User> getUsers(List<User> users) {
- return users;
+ public ReferenceConfig getReferenceConfig() {
+ return (ReferenceConfig) getSource();
}
- public int echo(int i) {
- return i;
+ public Invoker<?> getInvoker() {
+ return invoker;
}
-
-}
\ No newline at end of file
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ServiceConfigExportedEvent.java
similarity index 63%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ServiceConfigExportedEvent.java
index c5bc722..ebf15f3 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ServiceConfigExportedEvent.java
@@ -14,24 +14,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.api;
-
-import java.util.List;
+package org.apache.dubbo.config.event;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.event.Event;
/**
- * DemoService
+ * {@link ServiceConfig} event post-{@link ServiceConfig#export() export}
+ *
+ * @since 2.7.3
*/
-public interface DemoService {
-
- String sayName(String name);
-
- Box getBox();
-
- void throwDemoException() throws DemoException;
-
- List<User> getUsers(List<User> users);
+public class ServiceConfigExportedEvent extends Event {
- int echo(int i);
+ public ServiceConfigExportedEvent(ServiceConfig source) {
+ super(source);
+ }
-}
\ No newline at end of file
+ public ServiceConfig getServiceConfig() {
+ return (ServiceConfig) getSource();
+ }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ServiceConfigUnexportedEvent.java
similarity index 63%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ServiceConfigUnexportedEvent.java
index c5bc722..15bd3e5 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ServiceConfigUnexportedEvent.java
@@ -14,24 +14,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.api;
-
-import java.util.List;
+package org.apache.dubbo.config.event;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.event.Event;
/**
- * DemoService
+ * {@link ServiceConfig} event post-{@link ServiceConfig#unexport() unexport}
+ *
+ * @since 2.7.3
*/
-public interface DemoService {
-
- String sayName(String name);
-
- Box getBox();
-
- void throwDemoException() throws DemoException;
-
- List<User> getUsers(List<User> users);
+public class ServiceConfigUnexportedEvent extends Event {
- int echo(int i);
+ public ServiceConfigUnexportedEvent(ServiceConfig source) {
+ super(source);
+ }
-}
\ No newline at end of file
+ public ServiceConfig getServiceConfig() {
+ return (ServiceConfig) getSource();
+ }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/LoggingEventListener.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/LoggingEventListener.java
new file mode 100644
index 0000000..661c3d7
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/LoggingEventListener.java
@@ -0,0 +1,51 @@
+/*
+ * 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 org.apache.dubbo.config.event.listener;
+
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.config.event.DubboServiceDestroyedEvent;
+import org.apache.dubbo.config.event.ServiceConfigExportedEvent;
+import org.apache.dubbo.event.Event;
+import org.apache.dubbo.event.GenericEventListener;
+
+import static java.lang.String.format;
+
+/**
+ * A listener for logging the {@link Event Dubbo event}
+ *
+ * @see ServiceConfigExportedEvent
+ * @since 2.7.3
+ */
+public class LoggingEventListener extends GenericEventListener {
+
+ private static final String NAME = "Dubbo Service";
+
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ public void onEvent(DubboServiceDestroyedEvent event) {
+ if (logger.isInfoEnabled()) {
+ logger.info(NAME + " has been destroyed.");
+ }
+ }
+
+ private void debug(String pattern, Object... args) {
+ if (logger.isDebugEnabled()) {
+ logger.debug(format(pattern, args));
+ }
+ }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/ServiceNameMappingListener.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/ServiceNameMappingListener.java
new file mode 100644
index 0000000..bef416a
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/ServiceNameMappingListener.java
@@ -0,0 +1,55 @@
+/*
+ * 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 org.apache.dubbo.config.event.listener;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.event.ServiceConfigExportedEvent;
+import org.apache.dubbo.event.EventListener;
+import org.apache.dubbo.metadata.ServiceNameMapping;
+
+import java.util.List;
+
+import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
+import static org.apache.dubbo.metadata.ServiceNameMapping.getDefaultExtension;
+
+/**
+ * An {@link EventListener event listener} for mapping {@link ServiceConfig#getExportedUrls() the exported Dubbo
+ * service inerface} to its service name
+ *
+ * @see ServiceNameMapping
+ * @see ServiceConfig#getExportedUrls()
+ * @since 2.7.3
+ */
+public class ServiceNameMappingListener implements EventListener<ServiceConfigExportedEvent> {
+
+ private final ServiceNameMapping serviceNameMapping = getDefaultExtension();
+
+ @Override
+ public void onEvent(ServiceConfigExportedEvent event) {
+ ServiceConfig serviceConfig = event.getServiceConfig();
+ List<URL> exportedURLs = serviceConfig.getExportedUrls();
+ exportedURLs.forEach(url -> {
+ String serviceInterface = url.getServiceInterface();
+ String group = url.getParameter(GROUP_KEY);
+ String version = url.getParameter(VERSION_KEY);
+ String protocol = url.getProtocol();
+ serviceNameMapping.map(serviceInterface, group, version, protocol);
+ });
+ }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporter.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporter.java
new file mode 100644
index 0000000..ac36f9e
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporter.java
@@ -0,0 +1,131 @@
+/*
+ * 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 org.apache.dubbo.config.metadata;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.config.AbstractConfig;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.metadata.LocalMetadataService;
+import org.apache.dubbo.metadata.MetadataService;
+import org.apache.dubbo.metadata.MetadataServiceExporter;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import static java.util.Collections.unmodifiableList;
+
+/**
+ * {@link MetadataServiceExporter} implementation based on {@link AbstractConfig Dubbo configurations}, the clients
+ * should make sure the {@link ApplicationConfig}, {@link RegistryConfig} and {@link ProtocolConfig} are ready before
+ * {@link #export()}.
+ * <p>
+ * Typically, do not worry about their ready status, because they are initialized before
+ * any {@link ServiceConfig} exports, or The Dubbo export will be failed.
+ *
+ * @see MetadataServiceExporter
+ * @see ServiceConfig
+ * @see ConfigManager
+ * @since 2.7.3
+ */
+public class ConfigurableMetadataServiceExporter implements MetadataServiceExporter {
+
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ private volatile ServiceConfig<MetadataService> serviceConfig;
+
+ private ApplicationConfig applicationConfig;
+
+ private List<RegistryConfig> registries = new LinkedList<>();
+
+ private List<ProtocolConfig> protocols = new LinkedList<>();
+
+ public void setApplicationConfig(ApplicationConfig applicationConfig) {
+ this.applicationConfig = applicationConfig;
+ }
+
+ public void setRegistries(Collection<RegistryConfig> registries) {
+ this.registries.clear();
+ this.registries.addAll(registries);
+ }
+
+ public void setProtocols(Collection<ProtocolConfig> protocols) {
+ this.protocols.clear();
+ this.protocols.addAll(protocols);
+ }
+
+ @Override
+ public List<URL> export() {
+
+ if (!isExported()) {
+
+ LocalMetadataService metadataService = LocalMetadataService.getDefaultExtension();
+
+ ServiceConfig<MetadataService> serviceConfig = new ServiceConfig<>();
+ serviceConfig.setApplication(applicationConfig);
+ serviceConfig.setRegistries(registries);
+ serviceConfig.setProtocols(protocols);
+ serviceConfig.setInterface(MetadataService.class);
+ serviceConfig.setRef(metadataService);
+ serviceConfig.setGroup(getApplicationConfig().getName());
+ serviceConfig.setVersion(metadataService.version());
+
+ // export
... 9935 lines suppressed ...