Move some SPI extensions to apache/dubbo-spi-extensions, add sub package modules (#6157)
This commit is contained in:
parent
0e4bbb8ead
commit
8bdecea7ef
|
|
@ -68,6 +68,16 @@
|
|||
<artifactId>dubbo-rpc-thrift</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-filter-cache</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-filter-validation</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-serialization-hessian2</artifactId>
|
||||
|
|
|
|||
|
|
@ -55,16 +55,6 @@
|
|||
<artifactId>dubbo-rpc-injvm</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-filter-validation</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-filter-cache</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- FIXME, we shouldn't rely on these modules, even in test scope -->
|
||||
<dependency>
|
||||
|
|
@ -231,6 +221,19 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-filter-cache</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-filter-validation</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -16,12 +16,13 @@
|
|||
-->
|
||||
<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>
|
||||
<artifactId>dubbo-configcenter</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
<version>2.7.7-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dubbo-configcenter-apollo</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>${project.artifactId}</name>
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-configcenter</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>dubbo-configcenter-consul</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-common</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.orbitz.consul</groupId>
|
||||
<artifactId>consul-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.pszymczyk.consul</groupId>
|
||||
<artifactId>embedded-consul</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
|
|
@ -1,181 +0,0 @@
|
|||
/*
|
||||
* 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.configcenter.consul;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
|
||||
import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
|
||||
import org.apache.dubbo.common.config.configcenter.ConfigurationListener;
|
||||
import org.apache.dubbo.common.config.configcenter.TreePathDynamicConfiguration;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.orbitz.consul.Consul;
|
||||
import com.orbitz.consul.KeyValueClient;
|
||||
import com.orbitz.consul.cache.KVCache;
|
||||
import com.orbitz.consul.model.kv.Value;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;
|
||||
|
||||
/**
|
||||
* config center implementation for consul
|
||||
*/
|
||||
public class ConsulDynamicConfiguration extends TreePathDynamicConfiguration {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ConsulDynamicConfiguration.class);
|
||||
|
||||
private static final int DEFAULT_PORT = 8500;
|
||||
private static final int DEFAULT_WATCH_TIMEOUT = 60 * 1000;
|
||||
private static final String WATCH_TIMEOUT = "consul-watch-timeout";
|
||||
|
||||
private final Consul client;
|
||||
|
||||
private final KeyValueClient kvClient;
|
||||
|
||||
private final int watchTimeout;
|
||||
|
||||
private final ConcurrentMap<String, ConsulListener> watchers = new ConcurrentHashMap<>();
|
||||
|
||||
public ConsulDynamicConfiguration(URL url) {
|
||||
super(url);
|
||||
watchTimeout = url.getParameter(WATCH_TIMEOUT, DEFAULT_WATCH_TIMEOUT);
|
||||
String host = url.getHost();
|
||||
int port = url.getPort() != 0 ? url.getPort() : DEFAULT_PORT;
|
||||
Consul.Builder builder = Consul.builder()
|
||||
.withHostAndPort(HostAndPort.fromParts(host, port));
|
||||
String token = url.getParameter("token", (String) null);
|
||||
if (StringUtils.isNotEmpty(token)) {
|
||||
builder.withAclToken(token);
|
||||
}
|
||||
client = builder.build();
|
||||
this.kvClient = client.keyValueClient();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalProperty(String key) {
|
||||
logger.info("getting config from: " + key);
|
||||
return kvClient.getValueAsString(key, Charsets.UTF_8).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doPublishConfig(String pathKey, String content) throws Exception {
|
||||
return kvClient.putValue(pathKey, content);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doGetConfig(String pathKey) throws Exception {
|
||||
return getInternalProperty(pathKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doRemoveConfig(String pathKey) throws Exception {
|
||||
kvClient.deleteKey(pathKey);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> doGetConfigKeys(String groupPath) {
|
||||
List<String> keys = kvClient.getKeys(groupPath);
|
||||
List<String> configKeys = new LinkedList<>();
|
||||
if (CollectionUtils.isNotEmpty(keys)) {
|
||||
keys.stream()
|
||||
.filter(k -> !k.equals(groupPath))
|
||||
.map(k -> k.substring(k.lastIndexOf(PATH_SEPARATOR) + 1))
|
||||
.forEach(configKeys::add);
|
||||
}
|
||||
return configKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAddListener(String pathKey, ConfigurationListener listener) {
|
||||
logger.info("register listener " + listener.getClass() + " for config with key: " + pathKey);
|
||||
ConsulListener watcher = watchers.computeIfAbsent(pathKey, k -> new ConsulListener(pathKey));
|
||||
watcher.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRemoveListener(String pathKey, ConfigurationListener listener) {
|
||||
logger.info("unregister listener " + listener.getClass() + " for config with key: " + pathKey);
|
||||
ConsulListener watcher = watchers.get(pathKey);
|
||||
if (watcher != null) {
|
||||
watcher.removeListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doClose() throws Exception {
|
||||
client.destroy();
|
||||
}
|
||||
|
||||
private class ConsulListener implements KVCache.Listener<String, Value> {
|
||||
|
||||
private KVCache kvCache;
|
||||
private final Set<ConfigurationListener> listeners = new LinkedHashSet<>();
|
||||
private final String normalizedKey;
|
||||
|
||||
public ConsulListener(String normalizedKey) {
|
||||
this.normalizedKey = normalizedKey;
|
||||
initKVCache();
|
||||
}
|
||||
|
||||
private void initKVCache() {
|
||||
this.kvCache = KVCache.newCache(kvClient, normalizedKey, watchTimeout);
|
||||
kvCache.addListener(this);
|
||||
kvCache.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(Map<String, Value> newValues) {
|
||||
// Cache notifies all paths with "foo" the root path
|
||||
// If you want to watch only "foo" value, you must filter other paths
|
||||
Optional<Value> newValue = newValues.values().stream()
|
||||
.filter(value -> value.getKey().equals(normalizedKey))
|
||||
.findAny();
|
||||
|
||||
newValue.ifPresent(value -> {
|
||||
// Values are encoded in key/value store, decode it if needed
|
||||
Optional<String> decodedValue = newValue.get().getValueAsString();
|
||||
decodedValue.ifPresent(v -> listeners.forEach(l -> {
|
||||
ConfigChangedEvent event = new ConfigChangedEvent(normalizedKey, getGroup(), v, ConfigChangeType.MODIFIED);
|
||||
l.process(event);
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
private void addListener(ConfigurationListener listener) {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
private void removeListener(ConfigurationListener listener) {
|
||||
this.listeners.remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* 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.configcenter.consul;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.config.configcenter.AbstractDynamicConfigurationFactory;
|
||||
import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
|
||||
|
||||
/**
|
||||
* Config center factory for consul
|
||||
*/
|
||||
public class ConsulDynamicConfigurationFactory extends AbstractDynamicConfigurationFactory {
|
||||
@Override
|
||||
protected DynamicConfiguration createDynamicConfiguration(URL url) {
|
||||
return new ConsulDynamicConfiguration(url);
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
consul=org.apache.dubbo.configcenter.consul.ConsulDynamicConfigurationFactory
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
/*
|
||||
* 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.configcenter.consul;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.orbitz.consul.Consul;
|
||||
import com.orbitz.consul.KeyValueClient;
|
||||
import com.orbitz.consul.cache.KVCache;
|
||||
import com.orbitz.consul.model.kv.Value;
|
||||
import com.pszymczyk.consul.ConsulProcess;
|
||||
import com.pszymczyk.consul.ConsulStarterBuilder;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class ConsulDynamicConfigurationTest {
|
||||
|
||||
private static ConsulProcess consul;
|
||||
private static URL configCenterUrl;
|
||||
private static ConsulDynamicConfiguration configuration;
|
||||
|
||||
private static Consul client;
|
||||
private static KeyValueClient kvClient;
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp() throws Exception {
|
||||
consul = ConsulStarterBuilder.consulStarter()
|
||||
.build()
|
||||
.start();
|
||||
configCenterUrl = URL.valueOf("consul://127.0.0.1:" + consul.getHttpPort());
|
||||
|
||||
configuration = new ConsulDynamicConfiguration(configCenterUrl);
|
||||
client = Consul.builder().withHostAndPort(HostAndPort.fromParts("127.0.0.1", consul.getHttpPort())).build();
|
||||
kvClient = client.keyValueClient();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDown() throws Exception {
|
||||
consul.close();
|
||||
configuration.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetConfig() {
|
||||
kvClient.putValue("/dubbo/config/dubbo/foo", "bar");
|
||||
// test equals
|
||||
assertEquals("bar", configuration.getConfig("foo", "dubbo"));
|
||||
// test does not block
|
||||
assertEquals("bar", configuration.getConfig("foo", "dubbo"));
|
||||
Assertions.assertNull(configuration.getConfig("not-exist", "dubbo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublishConfig() {
|
||||
configuration.publishConfig("value", "metadata", "1");
|
||||
// test equals
|
||||
assertEquals("1", configuration.getConfig("value", "/metadata"));
|
||||
assertEquals("1", kvClient.getValueAsString("/dubbo/config/metadata/value").get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddListener() {
|
||||
KVCache cache = KVCache.newCache(kvClient, "/dubbo/config/dubbo/foo");
|
||||
cache.addListener(newValues -> {
|
||||
// Cache notifies all paths with "foo" the root path
|
||||
// If you want to watch only "foo" value, you must filter other paths
|
||||
Optional<Value> newValue = newValues.values().stream()
|
||||
.filter(value -> value.getKey().equals("foo"))
|
||||
.findAny();
|
||||
|
||||
newValue.ifPresent(value -> {
|
||||
// Values are encoded in key/value store, decode it if needed
|
||||
Optional<String> decodedValue = newValue.get().getValueAsString();
|
||||
decodedValue.ifPresent(v -> System.out.println(String.format("Value is: %s", v))); //prints "bar"
|
||||
});
|
||||
});
|
||||
cache.start();
|
||||
|
||||
kvClient.putValue("/dubbo/config/dubbo/foo", "new-value");
|
||||
kvClient.putValue("/dubbo/config/dubbo/foo/sub", "sub-value");
|
||||
kvClient.putValue("/dubbo/config/dubbo/foo/sub2", "sub-value2");
|
||||
kvClient.putValue("/dubbo/config/foo", "parent-value");
|
||||
|
||||
System.out.println(kvClient.getKeys("/dubbo/config/dubbo/foo"));
|
||||
System.out.println(kvClient.getKeys("/dubbo/config"));
|
||||
System.out.println(kvClient.getValues("/dubbo/config/dubbo/foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetConfigKeys() {
|
||||
configuration.publishConfig("v1", "metadata", "1");
|
||||
configuration.publishConfig("v2", "metadata", "2");
|
||||
configuration.publishConfig("v3", "metadata", "3");
|
||||
// test equals
|
||||
assertEquals(new TreeSet(Arrays.asList("v1", "v2", "v3")), configuration.getConfigKeys("metadata"));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-configcenter</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>dubbo-configcenter-etcd</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>The etcd implementation of the config-center api</description>
|
||||
|
||||
<properties>
|
||||
<skipIntegrationTests>true</skipIntegrationTests>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.etcd</groupId>
|
||||
<artifactId>jetcd-launcher</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-common</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-etcd3</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skipTests>${skipIntegrationTests}</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -1,197 +0,0 @@
|
|||
/*
|
||||
* 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.configcenter.support.etcd;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
|
||||
import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
|
||||
import org.apache.dubbo.common.config.configcenter.ConfigurationListener;
|
||||
import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.remoting.etcd.StateListener;
|
||||
import org.apache.dubbo.remoting.etcd.jetcd.JEtcdClient;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import io.etcd.jetcd.api.Event;
|
||||
import io.etcd.jetcd.api.WatchCancelRequest;
|
||||
import io.etcd.jetcd.api.WatchCreateRequest;
|
||||
import io.etcd.jetcd.api.WatchGrpc;
|
||||
import io.etcd.jetcd.api.WatchRequest;
|
||||
import io.etcd.jetcd.api.WatchResponse;
|
||||
import io.grpc.ManagedChannel;
|
||||
import io.grpc.stub.StreamObserver;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.apache.dubbo.common.config.configcenter.Constants.CONFIG_NAMESPACE_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;
|
||||
|
||||
/**
|
||||
* The etcd implementation of {@link DynamicConfiguration}
|
||||
*/
|
||||
public class EtcdDynamicConfiguration implements DynamicConfiguration {
|
||||
|
||||
/**
|
||||
* The final root path would be: /$NAME_SPACE/config
|
||||
*/
|
||||
private String rootPath;
|
||||
|
||||
/**
|
||||
* The etcd client
|
||||
*/
|
||||
private final JEtcdClient etcdClient;
|
||||
|
||||
/**
|
||||
* The map store the key to {@link EtcdConfigWatcher} mapping
|
||||
*/
|
||||
private final ConcurrentMap<ConfigurationListener, EtcdConfigWatcher> watchListenerMap;
|
||||
|
||||
EtcdDynamicConfiguration(URL url) {
|
||||
rootPath = PATH_SEPARATOR + url.getParameter(CONFIG_NAMESPACE_KEY, DEFAULT_GROUP) + "/config";
|
||||
etcdClient = new JEtcdClient(url);
|
||||
etcdClient.addStateListener(state -> {
|
||||
if (state == StateListener.CONNECTED) {
|
||||
try {
|
||||
recover();
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
});
|
||||
watchListenerMap = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(String key, String group, ConfigurationListener listener) {
|
||||
if (watchListenerMap.get(listener) == null) {
|
||||
EtcdConfigWatcher watcher = new EtcdConfigWatcher(key, group, listener);
|
||||
watchListenerMap.put(listener, watcher);
|
||||
watcher.watch();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(String key, String group, ConfigurationListener listener) {
|
||||
EtcdConfigWatcher watcher = watchListenerMap.get(listener);
|
||||
watcher.cancelWatch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfig(String key, String group, long timeout) throws IllegalStateException {
|
||||
return (String) getInternalProperty(convertKey(group, key));
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public String getConfigs(String key, String group, long timeout) throws IllegalStateException {
|
||||
// if (StringUtils.isEmpty(group)) {
|
||||
// group = DEFAULT_GROUP;
|
||||
// }
|
||||
// return (String) getInternalProperty(convertKey(group, key));
|
||||
// }
|
||||
|
||||
@Override
|
||||
public Object getInternalProperty(String key) {
|
||||
return etcdClient.getKVValue(key);
|
||||
}
|
||||
|
||||
private String buildPath(String group) {
|
||||
String actualGroup = StringUtils.isEmpty(group) ? DEFAULT_GROUP : group;
|
||||
return rootPath + PATH_SEPARATOR + actualGroup;
|
||||
}
|
||||
|
||||
private String convertKey(String group, String key) {
|
||||
return buildPath(group) + PATH_SEPARATOR + key;
|
||||
}
|
||||
|
||||
private void recover() {
|
||||
for (EtcdConfigWatcher watcher : watchListenerMap.values()) {
|
||||
watcher.watch();
|
||||
}
|
||||
}
|
||||
|
||||
public class EtcdConfigWatcher implements StreamObserver<WatchResponse> {
|
||||
|
||||
private ConfigurationListener listener;
|
||||
protected WatchGrpc.WatchStub watchStub;
|
||||
private StreamObserver<WatchRequest> observer;
|
||||
protected long watchId;
|
||||
private ManagedChannel channel;
|
||||
|
||||
private final String key;
|
||||
|
||||
private final String group;
|
||||
|
||||
private String normalizedKey;
|
||||
|
||||
public EtcdConfigWatcher(String key, String group, ConfigurationListener listener) {
|
||||
this.key = key;
|
||||
this.group = group;
|
||||
this.normalizedKey = convertKey(group, key);
|
||||
this.listener = listener;
|
||||
this.channel = etcdClient.getChannel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(WatchResponse watchResponse) {
|
||||
this.watchId = watchResponse.getWatchId();
|
||||
for (Event etcdEvent : watchResponse.getEventsList()) {
|
||||
ConfigChangeType type = ConfigChangeType.MODIFIED;
|
||||
if (etcdEvent.getType() == Event.EventType.DELETE) {
|
||||
type = ConfigChangeType.DELETED;
|
||||
}
|
||||
ConfigChangedEvent event = new ConfigChangedEvent(key, group,
|
||||
etcdEvent.getKv().getValue().toString(UTF_8), type);
|
||||
listener.process(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable throwable) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
// ignore
|
||||
}
|
||||
|
||||
public long getWatchId() {
|
||||
return watchId;
|
||||
}
|
||||
|
||||
private void watch() {
|
||||
watchStub = WatchGrpc.newStub(channel);
|
||||
observer = watchStub.watch(this);
|
||||
WatchCreateRequest.Builder builder = WatchCreateRequest.newBuilder()
|
||||
.setKey(ByteString.copyFromUtf8(normalizedKey))
|
||||
.setProgressNotify(true);
|
||||
WatchRequest req = WatchRequest.newBuilder().setCreateRequest(builder).build();
|
||||
observer.onNext(req);
|
||||
}
|
||||
|
||||
private void cancelWatch() {
|
||||
WatchCancelRequest watchCancelRequest =
|
||||
WatchCancelRequest.newBuilder().setWatchId(watchId).build();
|
||||
WatchRequest cancelRequest = WatchRequest.newBuilder()
|
||||
.setCancelRequest(watchCancelRequest).build();
|
||||
observer.onNext(cancelRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* 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.configcenter.support.etcd;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.config.configcenter.AbstractDynamicConfigurationFactory;
|
||||
import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
|
||||
|
||||
/**
|
||||
* The etcd implementation of {@link AbstractDynamicConfigurationFactory}
|
||||
*/
|
||||
public class EtcdDynamicConfigurationFactory extends AbstractDynamicConfigurationFactory {
|
||||
|
||||
@Override
|
||||
protected DynamicConfiguration createDynamicConfiguration(URL url) {
|
||||
return new EtcdDynamicConfiguration(url);
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
etcd=org.apache.dubbo.configcenter.support.etcd.EtcdDynamicConfigurationFactory
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
/*
|
||||
* 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.configcenter.support.etcd;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
|
||||
import org.apache.dubbo.common.config.configcenter.ConfigurationListener;
|
||||
import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
|
||||
|
||||
import io.etcd.jetcd.ByteSequence;
|
||||
import io.etcd.jetcd.Client;
|
||||
import io.etcd.jetcd.launcher.EtcdCluster;
|
||||
import io.etcd.jetcd.launcher.EtcdClusterFactory;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.apache.dubbo.remoting.etcd.Constants.SESSION_TIMEOUT_KEY;
|
||||
|
||||
/**
|
||||
* Unit test for etcd config center support
|
||||
* Integrate with https://github.com/etcd-io/jetcd#launcher
|
||||
*/
|
||||
public class EtcdDynamicConfigurationTest {
|
||||
|
||||
private static EtcdDynamicConfiguration config;
|
||||
|
||||
public EtcdCluster etcdCluster = EtcdClusterFactory.buildCluster(getClass().getSimpleName(), 3, false, false);
|
||||
|
||||
private static Client client;
|
||||
|
||||
@Test
|
||||
public void testGetConfig() {
|
||||
|
||||
put("/dubbo/config/org.apache.dubbo.etcd.testService/configurators", "hello");
|
||||
put("/dubbo/config/test/dubbo.properties", "aaa=bbb");
|
||||
Assert.assertEquals("hello", config.getConfig("org.apache.dubbo.etcd.testService.configurators", DynamicConfiguration.DEFAULT_GROUP));
|
||||
Assert.assertEquals("aaa=bbb", config.getConfig("dubbo.properties", "test"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddListener() throws Exception {
|
||||
CountDownLatch latch = new CountDownLatch(4);
|
||||
TestListener listener1 = new TestListener(latch);
|
||||
TestListener listener2 = new TestListener(latch);
|
||||
TestListener listener3 = new TestListener(latch);
|
||||
TestListener listener4 = new TestListener(latch);
|
||||
config.addListener("AService.configurators", listener1);
|
||||
config.addListener("AService.configurators", listener2);
|
||||
config.addListener("testapp.tagrouters", listener3);
|
||||
config.addListener("testapp.tagrouters", listener4);
|
||||
|
||||
put("/dubbo/config/AService/configurators", "new value1");
|
||||
Thread.sleep(200);
|
||||
put("/dubbo/config/testapp/tagrouters", "new value2");
|
||||
Thread.sleep(200);
|
||||
put("/dubbo/config/testapp", "new value3");
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
Assert.assertEquals(1, listener1.getCount("/dubbo/config/AService/configurators"));
|
||||
Assert.assertEquals(1, listener2.getCount("/dubbo/config/AService/configurators"));
|
||||
Assert.assertEquals(1, listener3.getCount("/dubbo/config/testapp/tagrouters"));
|
||||
Assert.assertEquals(1, listener4.getCount("/dubbo/config/testapp/tagrouters"));
|
||||
|
||||
Assert.assertEquals("new value1", listener1.getValue());
|
||||
Assert.assertEquals("new value1", listener2.getValue());
|
||||
Assert.assertEquals("new value2", listener3.getValue());
|
||||
Assert.assertEquals("new value2", listener4.getValue());
|
||||
}
|
||||
|
||||
private class TestListener implements ConfigurationListener {
|
||||
private CountDownLatch latch;
|
||||
private String value;
|
||||
private Map<String, Integer> countMap = new HashMap<>();
|
||||
|
||||
public TestListener(CountDownLatch latch) {
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ConfigChangedEvent event) {
|
||||
Integer count = countMap.computeIfAbsent(event.getKey(), k -> 0);
|
||||
countMap.put(event.getKey(), ++count);
|
||||
value = event.getContent();
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
public int getCount(String key) {
|
||||
return countMap.get(key);
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private void put(String key, String value) {
|
||||
try {
|
||||
client.getKVClient().put(ByteSequence.from(key, UTF_8), ByteSequence.from(value, UTF_8)).get();
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error put value to etcd.");
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
etcdCluster.start();
|
||||
|
||||
client = Client.builder().endpoints(etcdCluster.getClientEndpoints()).build();
|
||||
|
||||
List<URI> clientEndPoints = etcdCluster.getClientEndpoints();
|
||||
|
||||
String ipAddress = clientEndPoints.get(0).getHost() + ":" + clientEndPoints.get(0).getPort();
|
||||
String urlForDubbo = "etcd3://" + ipAddress + "/org.apache.dubbo.etcd.testService";
|
||||
|
||||
// timeout in 15 seconds.
|
||||
URL url = URL.valueOf(urlForDubbo)
|
||||
.addParameter(SESSION_TIMEOUT_KEY, 15000);
|
||||
config = new EtcdDynamicConfiguration(url);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
etcdCluster.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -22,8 +22,7 @@
|
|||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-configcenter</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
<version>2.7.7-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
|||
|
|
@ -33,8 +33,6 @@
|
|||
<modules>
|
||||
<module>dubbo-configcenter-zookeeper</module>
|
||||
<module>dubbo-configcenter-apollo</module>
|
||||
<module>dubbo-configcenter-consul</module>
|
||||
<module>dubbo-configcenter-etcd</module>
|
||||
<module>dubbo-configcenter-nacos</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-container</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>dubbo-container-log4j</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>The log4j container module of dubbo project</description>
|
||||
<properties>
|
||||
<skip_maven_deploy>false</skip_maven_deploy>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-container-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
/*
|
||||
* 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.container.log4j;
|
||||
|
||||
import org.apache.dubbo.common.config.ConfigurationUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.container.Container;
|
||||
|
||||
import org.apache.log4j.Appender;
|
||||
import org.apache.log4j.FileAppender;
|
||||
import org.apache.log4j.LogManager;
|
||||
import org.apache.log4j.PropertyConfigurator;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Log4jContainer. (SPI, Singleton, ThreadSafe)
|
||||
*
|
||||
* The container class implementation for Log4j
|
||||
*/
|
||||
public class Log4jContainer implements Container {
|
||||
|
||||
public static final String LOG4J_FILE = "dubbo.log4j.file";
|
||||
|
||||
public static final String LOG4J_LEVEL = "dubbo.log4j.level";
|
||||
|
||||
public static final String LOG4J_SUBDIRECTORY = "dubbo.log4j.subdirectory";
|
||||
|
||||
public static final String DEFAULT_LOG4J_LEVEL = "ERROR";
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void start() {
|
||||
String file = ConfigurationUtils.getProperty(LOG4J_FILE);
|
||||
if (file != null && file.length() > 0) {
|
||||
String level = ConfigurationUtils.getProperty(LOG4J_LEVEL);
|
||||
if (StringUtils.isEmpty(level)) {
|
||||
level = DEFAULT_LOG4J_LEVEL;
|
||||
}
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("log4j.rootLogger", level + ",application");
|
||||
properties.setProperty("log4j.appender.application", "org.apache.log4j.DailyRollingFileAppender");
|
||||
properties.setProperty("log4j.appender.application.File", file);
|
||||
properties.setProperty("log4j.appender.application.Append", "true");
|
||||
properties.setProperty("log4j.appender.application.DatePattern", "'.'yyyy-MM-dd");
|
||||
properties.setProperty("log4j.appender.application.layout", "org.apache.log4j.PatternLayout");
|
||||
properties.setProperty("log4j.appender.application.layout.ConversionPattern", "%d [%t] %-5p %C{6} (%F:%L) - %m%n");
|
||||
PropertyConfigurator.configure(properties);
|
||||
}
|
||||
String subdirectory = ConfigurationUtils.getProperty(LOG4J_SUBDIRECTORY);
|
||||
if (subdirectory != null && subdirectory.length() > 0) {
|
||||
Enumeration<org.apache.log4j.Logger> ls = LogManager.getCurrentLoggers();
|
||||
while (ls.hasMoreElements()) {
|
||||
org.apache.log4j.Logger l = ls.nextElement();
|
||||
if (l != null) {
|
||||
Enumeration<Appender> as = l.getAllAppenders();
|
||||
while (as.hasMoreElements()) {
|
||||
Appender a = as.nextElement();
|
||||
if (a instanceof FileAppender) {
|
||||
FileAppender fa = (FileAppender) a;
|
||||
String f = fa.getFile();
|
||||
if (f != null && f.length() > 0) {
|
||||
int i = f.replace('\\', '/').lastIndexOf('/');
|
||||
String path;
|
||||
if (i == -1) {
|
||||
path = subdirectory;
|
||||
} else {
|
||||
path = f.substring(0, i);
|
||||
if (!path.endsWith(subdirectory)) {
|
||||
path = path + "/" + subdirectory;
|
||||
}
|
||||
f = f.substring(i + 1);
|
||||
}
|
||||
fa.setFile(path + "/" + f);
|
||||
fa.activateOptions();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
log4j=org.apache.dubbo.container.log4j.Log4jContainer
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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.container.log4j;
|
||||
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.container.Container;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* StandaloneContainerTest
|
||||
*/
|
||||
public class Log4jContainerTest {
|
||||
|
||||
@Test
|
||||
public void testContainer() {
|
||||
Log4jContainer container = (Log4jContainer) ExtensionLoader.getExtensionLoader(Container.class).getExtension("log4j");
|
||||
container.start();
|
||||
container.stop();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-container</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>dubbo-container-logback</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>The logback container module of dubbo project</description>
|
||||
<properties>
|
||||
<skip_maven_deploy>false</skip_maven_deploy>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-container-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
* 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.container.logback;
|
||||
|
||||
import org.apache.dubbo.common.utils.ConfigUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.container.Container;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.rolling.RollingFileAppender;
|
||||
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* LogbackContainer. (SPI, Singleton, ThreadSafe)
|
||||
*
|
||||
* The container class implementation for Logback
|
||||
*/
|
||||
public class LogbackContainer implements Container {
|
||||
|
||||
public static final String LOGBACK_FILE = "dubbo.logback.file";
|
||||
|
||||
public static final String LOGBACK_LEVEL = "dubbo.logback.level";
|
||||
|
||||
public static final String LOGBACK_MAX_HISTORY = "dubbo.logback.maxhistory";
|
||||
|
||||
public static final String DEFAULT_LOGBACK_LEVEL = "ERROR";
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
String file = ConfigUtils.getProperty(LOGBACK_FILE);
|
||||
if (file != null && file.length() > 0) {
|
||||
String level = ConfigUtils.getProperty(LOGBACK_LEVEL);
|
||||
if (StringUtils.isEmpty(level)) {
|
||||
level = DEFAULT_LOGBACK_LEVEL;
|
||||
}
|
||||
// maxHistory=0 Infinite history
|
||||
int maxHistory = StringUtils.parseInteger(ConfigUtils.getProperty(LOGBACK_MAX_HISTORY));
|
||||
|
||||
doInitializer(file, level, maxHistory);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializer logback
|
||||
*
|
||||
* @param file
|
||||
* @param level
|
||||
* @param maxHistory
|
||||
*/
|
||||
private void doInitializer(String file, String level, int maxHistory) {
|
||||
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||
Logger rootLogger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||
rootLogger.detachAndStopAllAppenders();
|
||||
|
||||
// appender
|
||||
RollingFileAppender<ILoggingEvent> fileAppender = new RollingFileAppender<ILoggingEvent>();
|
||||
fileAppender.setContext(loggerContext);
|
||||
fileAppender.setName("application");
|
||||
fileAppender.setFile(file);
|
||||
fileAppender.setAppend(true);
|
||||
|
||||
// policy
|
||||
TimeBasedRollingPolicy<ILoggingEvent> policy = new TimeBasedRollingPolicy<ILoggingEvent>();
|
||||
policy.setContext(loggerContext);
|
||||
policy.setMaxHistory(maxHistory);
|
||||
policy.setFileNamePattern(file + ".%d{yyyy-MM-dd}");
|
||||
policy.setParent(fileAppender);
|
||||
policy.start();
|
||||
fileAppender.setRollingPolicy(policy);
|
||||
|
||||
// encoder
|
||||
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
|
||||
encoder.setContext(loggerContext);
|
||||
encoder.setPattern("%date [%thread] %-5level %logger (%file:%line\\) - %msg%n");
|
||||
encoder.start();
|
||||
fileAppender.setEncoder(encoder);
|
||||
|
||||
fileAppender.start();
|
||||
|
||||
rootLogger.addAppender(fileAppender);
|
||||
rootLogger.setLevel(Level.toLevel(level));
|
||||
rootLogger.setAdditive(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
logback=org.apache.dubbo.container.logback.LogbackContainer
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* 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.container.logback;
|
||||
|
||||
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.container.Container;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* StandaloneContainerTest
|
||||
*/
|
||||
public class LogbackContainerTest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LogbackContainerTest.class);
|
||||
|
||||
@Test
|
||||
public void testContainer() {
|
||||
LogbackContainer container = (LogbackContainer) ExtensionLoader.getExtensionLoader(Container.class)
|
||||
.getExtension("logback");
|
||||
container.start();
|
||||
|
||||
logger.debug("Test debug:" + this.getClass().getName());
|
||||
logger.warn("Test warn:" + this.getClass().getName());
|
||||
logger.info("Test info:" + this.getClass().getName());
|
||||
logger.error("Test error:" + this.getClass().getName());
|
||||
|
||||
container.stop();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -32,7 +32,5 @@
|
|||
<modules>
|
||||
<module>dubbo-container-api</module>
|
||||
<module>dubbo-container-spring</module>
|
||||
<module>dubbo-container-log4j</module>
|
||||
<module>dubbo-container-logback</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@
|
|||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-parent</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>dubbo</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>dubbo-all</name>
|
||||
<name>dubbo</name>
|
||||
<description>The all in one project of dubbo</description>
|
||||
<properties>
|
||||
<skip_maven_deploy>false</skip_maven_deploy>
|
||||
|
|
@ -59,20 +59,6 @@
|
|||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-filter-cache</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-filter-validation</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-api</artifactId>
|
||||
|
|
@ -96,35 +82,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-etcd3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-mina</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-grizzly</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-p2p</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-http</artifactId>
|
||||
<artifactId>dubbo-remoting-zookeeper</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
|
|
@ -150,62 +108,6 @@
|
|||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-http</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-rmi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-hessian</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-webservice</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-thrift</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-native-thrift</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-memcached</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-redis</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-rest</artifactId>
|
||||
|
|
@ -213,13 +115,6 @@
|
|||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-xml</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-grpc</artifactId>
|
||||
|
|
@ -234,13 +129,6 @@
|
|||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-default</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-multicast</artifactId>
|
||||
|
|
@ -255,44 +143,6 @@
|
|||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-redis</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-consul</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-etcd3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-netty</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-eureka</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-nacos</artifactId>
|
||||
|
|
@ -300,13 +150,6 @@
|
|||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-sofa</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-multiple</artifactId>
|
||||
|
|
@ -335,20 +178,6 @@
|
|||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-container-log4j</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-container-logback</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-qos</artifactId>
|
||||
|
|
@ -363,20 +192,6 @@
|
|||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-serialization-fastjson</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-serialization-fst</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-serialization-hessian2</artifactId>
|
||||
|
|
@ -384,13 +199,6 @@
|
|||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-serialization-native-hession</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-serialization-jdk</artifactId>
|
||||
|
|
@ -398,41 +206,6 @@
|
|||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-serialization-kryo</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-serialization-avro</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-serialization-protostuff</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-serialization-gson</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-serialization-protobuf</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-configcenter-zookeeper</artifactId>
|
||||
|
|
@ -454,30 +227,6 @@
|
|||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-configcenter-consul</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-configcenter-etcd</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-netty</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-compatible</artifactId>
|
||||
|
|
@ -515,31 +264,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metadata-report-consul</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metadata-report-etcd</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-netty</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metadata-report-nacos</artifactId>
|
||||
<artifactId>dubbo-auth</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
|
|
@ -620,71 +345,35 @@
|
|||
<include>org.apache.dubbo:dubbo-remoting-api</include>
|
||||
<include>org.apache.dubbo:dubbo-remoting-netty</include>
|
||||
<include>org.apache.dubbo:dubbo-remoting-netty4</include>
|
||||
<include>org.apache.dubbo:dubbo-remoting-etcd3</include>
|
||||
<include>org.apache.dubbo:dubbo-remoting-mina</include>
|
||||
<include>org.apache.dubbo:dubbo-remoting-grizzly</include>
|
||||
<include>org.apache.dubbo:dubbo-remoting-p2p</include>
|
||||
<include>org.apache.dubbo:dubbo-remoting-http</include>
|
||||
<include>org.apache.dubbo:dubbo-remoting-zookeeper</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-api</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-dubbo</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-injvm</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-http</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-rmi</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-hessian</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-webservice</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-thrift</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-native-thrift</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-memcached</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-redis</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-rest</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-xml</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-grpc</include>
|
||||
<include>org.apache.dubbo:dubbo-filter-validation</include>
|
||||
<include>org.apache.dubbo:dubbo-filter-cache</include>
|
||||
<include>org.apache.dubbo:dubbo-cluster</include>
|
||||
<include>org.apache.dubbo:dubbo-registry-api</include>
|
||||
<include>org.apache.dubbo:dubbo-registry-default</include>
|
||||
<include>org.apache.dubbo:dubbo-registry-multicast</include>
|
||||
<include>org.apache.dubbo:dubbo-registry-zookeeper</include>
|
||||
<include>org.apache.dubbo:dubbo-registry-redis</include>
|
||||
<include>org.apache.dubbo:dubbo-registry-consul</include>
|
||||
<include>org.apache.dubbo:dubbo-registry-etcd3</include>
|
||||
<include>org.apache.dubbo:dubbo-registry-eureka</include>
|
||||
<include>org.apache.dubbo:dubbo-registry-nacos</include>
|
||||
<include>org.apache.dubbo:dubbo-registry-sofa</include>
|
||||
<include>org.apache.dubbo:dubbo-registry-multiple</include>
|
||||
<include>org.apache.dubbo:dubbo-monitor-api</include>
|
||||
<include>org.apache.dubbo:dubbo-monitor-default</include>
|
||||
<include>org.apache.dubbo:dubbo-container-api</include>
|
||||
<include>org.apache.dubbo:dubbo-container-spring</include>
|
||||
<include>org.apache.dubbo:dubbo-container-log4j</include>
|
||||
<include>org.apache.dubbo:dubbo-container-logback</include>
|
||||
<include>org.apache.dubbo:dubbo-qos</include>
|
||||
<include>org.apache.dubbo:dubbo-serialization-api</include>
|
||||
<include>org.apache.dubbo:dubbo-serialization-fastjson</include>
|
||||
<include>org.apache.dubbo:dubbo-serialization-hessian2</include>
|
||||
<include>org.apache.dubbo:dubbo-serialization-fst</include>
|
||||
<include>org.apache.dubbo:dubbo-serialization-kryo</include>
|
||||
<include>org.apache.dubbo:dubbo-serialization-avro</include>
|
||||
<include>org.apache.dubbo:dubbo-serialization-jdk</include>
|
||||
<include>org.apache.dubbo:dubbo-serialization-protostuff</include>
|
||||
<include>org.apache.dubbo:dubbo-serialization-gson</include>
|
||||
<include>org.apache.dubbo:dubbo-serialization-protobuf</include>
|
||||
<include>org.apache.dubbo:dubbo-configcenter-api</include>
|
||||
<include>org.apache.dubbo:dubbo-configcenter-definition</include>
|
||||
<include>org.apache.dubbo:dubbo-configcenter-apollo</include>
|
||||
<include>org.apache.dubbo:dubbo-configcenter-zookeeper</include>
|
||||
<include>org.apache.dubbo:dubbo-configcenter-consul</include>
|
||||
<include>org.apache.dubbo:dubbo-configcenter-etcd</include>
|
||||
<include>org.apache.dubbo:dubbo-configcenter-nacos</include>
|
||||
<include>org.apache.dubbo:dubbo-metadata-api</include>
|
||||
<include>org.apache.dubbo:dubbo-metadata-report-redis</include>
|
||||
<include>org.apache.dubbo:dubbo-metadata-report-zookeeper</include>
|
||||
<include>org.apache.dubbo:dubbo-metadata-report-consul</include>
|
||||
<include>org.apache.dubbo:dubbo-metadata-report-etcd</include>
|
||||
<include>org.apache.dubbo:dubbo-metadata-report-nacos</include>
|
||||
<include>org.apache.dubbo:dubbo-serialization-native-hession</include>
|
||||
<include>org.apache.dubbo:dubbo-qos</include>
|
||||
<include>org.apache.dubbo:dubbo-auth</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<transformers>
|
||||
|
|
@ -980,6 +669,18 @@
|
|||
META-INF/services/org.apache.dubbo.common.extension.LoadingStrategy
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.auth.spi.AccessKeyStorage
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.auth.spi.Authenticator
|
||||
</resource>
|
||||
</transformer>
|
||||
|
||||
<!-- @since 2.7.8 -->
|
||||
<transformer
|
||||
|
|
@ -994,7 +695,7 @@
|
|||
<filter>
|
||||
<artifact>org.apache.dubbo:dubbo</artifact>
|
||||
<excludes>
|
||||
<!-- These two line is optional, it can remove some warn log -->
|
||||
<!-- These following two line is optional, it can remove some warn log -->
|
||||
<exclude>com/**</exclude>
|
||||
<exclude>org/**</exclude>
|
||||
<!-- This one is required -->
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-distribution</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>dubbo-apache-release</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>dubbo-apache-release</name>
|
||||
<description>The apache source release</description>
|
||||
<properties>
|
||||
<skip_maven_deploy>true</skip_maven_deploy>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-demo-api-provider</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-demo-api-consumer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
<finalName>apache-dubbo-${project.version}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>bin</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/assembly/bin-release.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>src</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/assembly/source-release.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
<baseDirectory>${project.build.finalName}-bin</baseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>../</directory>
|
||||
<directory>../../</directory>
|
||||
<includes>
|
||||
<include>DISCLAIMER</include>
|
||||
<include>NOTICE</include>
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
</includes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>../dubbo-demo</directory>
|
||||
<directory>../../dubbo-demo</directory>
|
||||
<includes>
|
||||
<include>README.md</include>
|
||||
</includes>
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>../</directory>
|
||||
<directory>../../</directory>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
|
|
@ -23,68 +23,13 @@
|
|||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-parent</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>dubbo-bom</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>dubbo-bom</name>
|
||||
<description>Dubbo dependencies BOM</description>
|
||||
<url>https://github.com/apache/dubbo</url>
|
||||
<inceptionYear>2011</inceptionYear>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<scm>
|
||||
<url>https://github.com/apache/dubbo</url>
|
||||
<connection>scm:git:https://github.com/apache/dubbo.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/apache/dubbo.git</developerConnection>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
<mailingLists>
|
||||
<mailingList>
|
||||
<name>Development List</name>
|
||||
<subscribe>dev-subscribe@dubbo.apache.org</subscribe>
|
||||
<unsubscribe>dev-unsubscribe@dubbo.apache.org</unsubscribe>
|
||||
<post>dev@dubbo.apache.org</post>
|
||||
</mailingList>
|
||||
<mailingList>
|
||||
<name>Commits List</name>
|
||||
<subscribe>commits-subscribe@dubbo.apache.org</subscribe>
|
||||
<unsubscribe>commits-unsubscribe@dubbo.apache.org</unsubscribe>
|
||||
<post>commits@dubbo.apache.org</post>
|
||||
</mailingList>
|
||||
<mailingList>
|
||||
<name>Issues List</name>
|
||||
<subscribe>issues-subscribe@dubbo.apache.org</subscribe>
|
||||
<unsubscribe>issues-unsubscribe@dubbo.apache.org</unsubscribe>
|
||||
<post>issues@dubbo.apache.org</post>
|
||||
</mailingList>
|
||||
</mailingLists>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>dubbo.io</id>
|
||||
<name>The Dubbo Project Contributors</name>
|
||||
<email>dev-subscribe@dubbo.apache.org</email>
|
||||
<url>http://dubbo.apache.org/</url>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<organization>
|
||||
<name>The Apache Software Foundation</name>
|
||||
<url>http://www.apache.org/</url>
|
||||
</organization>
|
||||
|
||||
<issueManagement>
|
||||
<system>Github Issues</system>
|
||||
<url>https://github.com/apache/dubbo/issues</url>
|
||||
</issueManagement>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
|
@ -0,0 +1,444 @@
|
|||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-parent</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>dubbo-core-spi</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>dubbo-core-spi</name>
|
||||
<description>All the SPI definitions of Dubbo</description>
|
||||
<properties>
|
||||
<skip_maven_deploy>true</skip_maven_deploy>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-cluster</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-monitor-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-qos</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-serialization-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- metadata -->
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metadata-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<createSourcesJar>true</createSourcesJar>
|
||||
<promoteTransitiveDependencies>false</promoteTransitiveDependencies>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>org.apache.dubbo:dubbo-common</include>
|
||||
<include>org.apache.dubbo:dubbo-cluster</include>
|
||||
<include>org.apache.dubbo:dubbo-qos</include>
|
||||
<include>org.apache.dubbo:dubbo-remoting-api</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-api</include>
|
||||
<include>org.apache.dubbo:dubbo-cluster</include>
|
||||
<include>org.apache.dubbo:dubbo-registry-api</include>
|
||||
<include>org.apache.dubbo:dubbo-monitor-api</include>
|
||||
<include>org.apache.dubbo:dubbo-container-api</include>
|
||||
<include>org.apache.dubbo:dubbo-serialization-api</include>
|
||||
<include>org.apache.dubbo:dubbo-metadata-api</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<transformers>
|
||||
<!-- dubbo-common beginning -->
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.common.compiler.Compiler
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.common.infra.InfraAdapter
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.common.logger.LoggerAdapter
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.common.status.StatusChecker
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.common.store.DataStore
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.ThreadPool
|
||||
</resource>
|
||||
</transformer>
|
||||
<!-- dubbo-common end -->
|
||||
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.common.serialize.Serialization
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.Dispatcher</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.Codec2</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.Transporter</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.exchange.Exchanger
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http.HttpBinder
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.p2p.Networker
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.telnet.TelnetHandler
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.InvokerListener</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.ExporterListener</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.ProxyFactory</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Cluster</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.LoadBalance
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Merger</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ConfiguratorFactory
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.container.Container</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.monitor.MonitorFactory
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.validation.Validation</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.cache.CacheFactory</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.qos.command.BaseCommand
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory
|
||||
</resource>
|
||||
</transformer>
|
||||
<!-- @since 2.7.5 -->
|
||||
<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.WritableMetadataService
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.ServiceNameMapping
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.proxy.MetadataServiceProxyFactory
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscovery
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.metadata.definition.builder.TypeBuilder
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.event.EventListener
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceInstanceCustomizer
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.MetadataServiceURLBuilder
|
||||
</resource>
|
||||
</transformer>
|
||||
|
||||
<!-- @since 2.7.6 -->
|
||||
|
||||
<!-- 'dubbo-common' module -->
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.common.convert.Converter
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.common.convert.multiple.MultiValueConverter
|
||||
</resource>
|
||||
</transformer>
|
||||
|
||||
<!-- 'dubbo-metadata-api' module -->
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.metadata.rest.ServiceRestMetadataResolver
|
||||
</resource>
|
||||
</transformer>
|
||||
|
||||
<!-- 'dubbo-metadata-processor' module -->
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.builder.TypeDefinitionBuilder
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.rest.ServiceRestMetadataResolver
|
||||
</resource>
|
||||
</transformer>
|
||||
|
||||
<!-- @since 2.7.7 -->
|
||||
|
||||
<!-- 'dubbo-common' module -->
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/services/org.apache.dubbo.common.extension.LoadingStrategy
|
||||
</resource>
|
||||
</transformer>
|
||||
|
||||
</transformers>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>org.apache.dubbo:dubbo</artifact>
|
||||
<excludes>
|
||||
<!-- These following two line is optional, it can remove some warn log -->
|
||||
<exclude>com/**</exclude>
|
||||
<exclude>org/**</exclude>
|
||||
<!-- This one is required -->
|
||||
<exclude>META-INF/dubbo/**</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
@ -14,86 +14,44 @@
|
|||
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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<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-distribution</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>dubbo-distribution</name>
|
||||
<description>The binary distribution module for dubbo temporarily</description>
|
||||
<properties>
|
||||
<skip_maven_deploy>true</skip_maven_deploy>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-demo-api-provider</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-demo-api-consumer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
<finalName>apache-dubbo-${project.version}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>bin</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/assembly/bin-release.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>src</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/assembly/source-release.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<modules>
|
||||
<module>dubbo-all</module>
|
||||
<module>dubbo-apache-release</module>
|
||||
<module>dubbo-bom</module>
|
||||
<module>dubbo-core-spi</module>
|
||||
</modules>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>dubbo-all</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<modules>
|
||||
<module>dubbo-all</module>
|
||||
</modules>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>dubbo-core-spi</id>
|
||||
<modules>
|
||||
<module>dubbo-all</module>
|
||||
</modules>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@
|
|||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-filter</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
<version>2.7.7-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>dubbo-filter-cache</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
|
|
|||
|
|
@ -1,43 +1,43 @@
|
|||
/*
|
||||
* 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.cache;
|
||||
|
||||
/**
|
||||
* Cache interface to support storing and retrieval of value against a lookup key. It has two operation <b>get</b> and <b>put</b>.
|
||||
* <li><b>put</b>-Storing value against a key.</li>
|
||||
* <li><b>get</b>-Retrieval of object.</li>
|
||||
* @see org.apache.dubbo.cache.support.lru.LruCache
|
||||
* @see org.apache.dubbo.cache.support.jcache.JCache
|
||||
* @see org.apache.dubbo.cache.support.expiring.ExpiringCache
|
||||
* @see org.apache.dubbo.cache.support.threadlocal.ThreadLocalCache
|
||||
*/
|
||||
public interface Cache {
|
||||
/**
|
||||
* API to store value against a key
|
||||
* @param key Unique identifier for the object being store.
|
||||
* @param value Value getting store
|
||||
*/
|
||||
void put(Object key, Object value);
|
||||
|
||||
/**
|
||||
* API to return stored value using a key.
|
||||
* @param key Unique identifier for cache lookup
|
||||
* @return Return stored object against key
|
||||
*/
|
||||
Object get(Object key);
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.cache;
|
||||
|
||||
/**
|
||||
* Cache interface to support storing and retrieval of value against a lookup key. It has two operation <b>get</b> and <b>put</b>.
|
||||
* <li><b>put</b>-Storing value against a key.</li>
|
||||
* <li><b>get</b>-Retrieval of object.</li>
|
||||
* @see org.apache.dubbo.cache.support.lru.LruCache
|
||||
* @see org.apache.dubbo.cache.support.jcache.JCache
|
||||
* @see org.apache.dubbo.cache.support.expiring.ExpiringCache
|
||||
* @see org.apache.dubbo.cache.support.threadlocal.ThreadLocalCache
|
||||
*/
|
||||
public interface Cache {
|
||||
/**
|
||||
* API to store value against a key
|
||||
* @param key Unique identifier for the object being store.
|
||||
* @param value Value getting store
|
||||
*/
|
||||
void put(Object key, Object value);
|
||||
|
||||
/**
|
||||
* API to return stored value using a key.
|
||||
* @param key Unique identifier for cache lookup
|
||||
* @return Return stored object against key
|
||||
*/
|
||||
Object get(Object key);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,43 @@
|
|||
/*
|
||||
* 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.cache;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.Adaptive;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
|
||||
/**
|
||||
* Interface needs to be implemented by all the cache store provider.Along with implementing <b>CacheFactory</b> interface
|
||||
* entry needs to be added in org.apache.dubbo.cache.CacheFactory file in a classpath META-INF sub directories.
|
||||
*
|
||||
* @see Cache
|
||||
*/
|
||||
@SPI("lru")
|
||||
public interface CacheFactory {
|
||||
|
||||
/**
|
||||
* CacheFactory implementation class needs to implement this return underlying cache instance for method against
|
||||
* url and invocation.
|
||||
* @param url
|
||||
* @param invocation
|
||||
* @return Instance of Cache containing cached value against method url and invocation.
|
||||
*/
|
||||
@Adaptive("cache")
|
||||
Cache getCache(URL url, Invocation invocation);
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.cache;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.Adaptive;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
|
||||
/**
|
||||
* Interface needs to be implemented by all the cache store provider.Along with implementing <b>CacheFactory</b> interface
|
||||
* entry needs to be added in org.apache.dubbo.cache.CacheFactory file in a classpath META-INF sub directories.
|
||||
*
|
||||
* @see Cache
|
||||
*/
|
||||
@SPI("lru")
|
||||
public interface CacheFactory {
|
||||
|
||||
/**
|
||||
* CacheFactory implementation class needs to implement this return underlying cache instance for method against
|
||||
* url and invocation.
|
||||
* @param url
|
||||
* @param invocation
|
||||
* @return Instance of Cache containing cached value against method url and invocation.
|
||||
*/
|
||||
@Adaptive("cache")
|
||||
Cache getCache(URL url, Invocation invocation);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,133 +1,133 @@
|
|||
/*
|
||||
* 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.cache.filter;
|
||||
|
||||
import org.apache.dubbo.cache.Cache;
|
||||
import org.apache.dubbo.cache.CacheFactory;
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.utils.ConfigUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
|
||||
import static org.apache.dubbo.common.constants.FilterConstants.CACHE_KEY;
|
||||
|
||||
/**
|
||||
* CacheFilter is a core component of dubbo.Enabling <b>cache</b> key of service,method,consumer or provider dubbo will cache method return value.
|
||||
* Along with cache key we need to configure cache type. Dubbo default implemented cache types are
|
||||
* <li>lur</li>
|
||||
* <li>threadlocal</li>
|
||||
* <li>jcache</li>
|
||||
* <li>expiring</li>
|
||||
*
|
||||
* <pre>
|
||||
* e.g. 1)<dubbo:service cache="lru" />
|
||||
* 2)<dubbo:service /> <dubbo:method name="method2" cache="threadlocal" /> <dubbo:service/>
|
||||
* 3)<dubbo:provider cache="expiring" />
|
||||
* 4)<dubbo:consumer cache="jcache" />
|
||||
*
|
||||
*If cache type is defined in method level then method level type will get precedence. According to above provided
|
||||
*example, if service has two method, method1 and method2, method2 will have cache type as <b>threadlocal</b> where others will
|
||||
*be backed by <b>lru</b>
|
||||
*</pre>
|
||||
*
|
||||
* @see org.apache.dubbo.rpc.Filter
|
||||
* @see org.apache.dubbo.cache.support.lru.LruCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.lru.LruCache
|
||||
* @see org.apache.dubbo.cache.support.jcache.JCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.jcache.JCache
|
||||
* @see org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.threadlocal.ThreadLocalCache
|
||||
* @see org.apache.dubbo.cache.support.expiring.ExpiringCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.expiring.ExpiringCache
|
||||
*
|
||||
*/
|
||||
@Activate(group = {CONSUMER, PROVIDER}, value = CACHE_KEY)
|
||||
public class CacheFilter implements Filter {
|
||||
|
||||
private CacheFactory cacheFactory;
|
||||
|
||||
/**
|
||||
* Dubbo will populate and set the cache factory instance based on service/method/consumer/provider configured
|
||||
* cache attribute value. Dubbo will search for the class name implementing configured <b>cache</b> in file org.apache.dubbo.cache.CacheFactory
|
||||
* under META-INF sub folders.
|
||||
*
|
||||
* @param cacheFactory instance of CacheFactory based on <b>cache</b> type
|
||||
*/
|
||||
public void setCacheFactory(CacheFactory cacheFactory) {
|
||||
this.cacheFactory = cacheFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* If cache is configured, dubbo will invoke method on each method call. If cache value is returned by cache store
|
||||
* then it will return otherwise call the remote method and return value. If remote method's return value has error
|
||||
* then it will not cache the value.
|
||||
* @param invoker service
|
||||
* @param invocation invocation.
|
||||
* @return Cache returned value if found by the underlying cache store. If cache miss it will call target method.
|
||||
* @throws RpcException
|
||||
*/
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
if (cacheFactory != null && ConfigUtils.isNotEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), CACHE_KEY))) {
|
||||
Cache cache = cacheFactory.getCache(invoker.getUrl(), invocation);
|
||||
if (cache != null) {
|
||||
String key = StringUtils.toArgumentString(invocation.getArguments());
|
||||
Object value = cache.get(key);
|
||||
if (value != null) {
|
||||
if (value instanceof ValueWrapper) {
|
||||
return AsyncRpcResult.newDefaultAsyncResult(((ValueWrapper) value).get(), invocation);
|
||||
} else {
|
||||
return AsyncRpcResult.newDefaultAsyncResult(value, invocation);
|
||||
}
|
||||
}
|
||||
Result result = invoker.invoke(invocation);
|
||||
if (!result.hasException()) {
|
||||
cache.put(key, new ValueWrapper(result.getValue()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return invoker.invoke(invocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache value wrapper.
|
||||
*/
|
||||
static class ValueWrapper implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -1777337318019193256L;
|
||||
|
||||
private final Object value;
|
||||
|
||||
public ValueWrapper (Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Object get() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.cache.filter;
|
||||
|
||||
import org.apache.dubbo.cache.Cache;
|
||||
import org.apache.dubbo.cache.CacheFactory;
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.utils.ConfigUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
|
||||
import static org.apache.dubbo.common.constants.FilterConstants.CACHE_KEY;
|
||||
|
||||
/**
|
||||
* CacheFilter is a core component of dubbo.Enabling <b>cache</b> key of service,method,consumer or provider dubbo will cache method return value.
|
||||
* Along with cache key we need to configure cache type. Dubbo default implemented cache types are
|
||||
* <li>lur</li>
|
||||
* <li>threadlocal</li>
|
||||
* <li>jcache</li>
|
||||
* <li>expiring</li>
|
||||
*
|
||||
* <pre>
|
||||
* e.g. 1)<dubbo:service cache="lru" />
|
||||
* 2)<dubbo:service /> <dubbo:method name="method2" cache="threadlocal" /> <dubbo:service/>
|
||||
* 3)<dubbo:provider cache="expiring" />
|
||||
* 4)<dubbo:consumer cache="jcache" />
|
||||
*
|
||||
*If cache type is defined in method level then method level type will get precedence. According to above provided
|
||||
*example, if service has two method, method1 and method2, method2 will have cache type as <b>threadlocal</b> where others will
|
||||
*be backed by <b>lru</b>
|
||||
*</pre>
|
||||
*
|
||||
* @see org.apache.dubbo.rpc.Filter
|
||||
* @see org.apache.dubbo.cache.support.lru.LruCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.lru.LruCache
|
||||
* @see org.apache.dubbo.cache.support.jcache.JCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.jcache.JCache
|
||||
* @see org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.threadlocal.ThreadLocalCache
|
||||
* @see org.apache.dubbo.cache.support.expiring.ExpiringCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.expiring.ExpiringCache
|
||||
*
|
||||
*/
|
||||
@Activate(group = {CONSUMER, PROVIDER}, value = CACHE_KEY)
|
||||
public class CacheFilter implements Filter {
|
||||
|
||||
private CacheFactory cacheFactory;
|
||||
|
||||
/**
|
||||
* Dubbo will populate and set the cache factory instance based on service/method/consumer/provider configured
|
||||
* cache attribute value. Dubbo will search for the class name implementing configured <b>cache</b> in file org.apache.dubbo.cache.CacheFactory
|
||||
* under META-INF sub folders.
|
||||
*
|
||||
* @param cacheFactory instance of CacheFactory based on <b>cache</b> type
|
||||
*/
|
||||
public void setCacheFactory(CacheFactory cacheFactory) {
|
||||
this.cacheFactory = cacheFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* If cache is configured, dubbo will invoke method on each method call. If cache value is returned by cache store
|
||||
* then it will return otherwise call the remote method and return value. If remote method's return value has error
|
||||
* then it will not cache the value.
|
||||
* @param invoker service
|
||||
* @param invocation invocation.
|
||||
* @return Cache returned value if found by the underlying cache store. If cache miss it will call target method.
|
||||
* @throws RpcException
|
||||
*/
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
if (cacheFactory != null && ConfigUtils.isNotEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), CACHE_KEY))) {
|
||||
Cache cache = cacheFactory.getCache(invoker.getUrl(), invocation);
|
||||
if (cache != null) {
|
||||
String key = StringUtils.toArgumentString(invocation.getArguments());
|
||||
Object value = cache.get(key);
|
||||
if (value != null) {
|
||||
if (value instanceof ValueWrapper) {
|
||||
return AsyncRpcResult.newDefaultAsyncResult(((ValueWrapper) value).get(), invocation);
|
||||
} else {
|
||||
return AsyncRpcResult.newDefaultAsyncResult(value, invocation);
|
||||
}
|
||||
}
|
||||
Result result = invoker.invoke(invocation);
|
||||
if (!result.hasException()) {
|
||||
cache.put(key, new ValueWrapper(result.getValue()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return invoker.invoke(invocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache value wrapper.
|
||||
*/
|
||||
static class ValueWrapper implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -1777337318019193256L;
|
||||
|
||||
private final Object value;
|
||||
|
||||
public ValueWrapper (Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Object get() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,72 +1,72 @@
|
|||
/*
|
||||
* 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.cache.support;
|
||||
|
||||
import org.apache.dubbo.cache.Cache;
|
||||
import org.apache.dubbo.cache.CacheFactory;
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;
|
||||
|
||||
/**
|
||||
* AbstractCacheFactory is a default implementation of {@link CacheFactory}. It abstract out the key formation from URL along with
|
||||
* invocation method. It initially check if the value for key already present in own local in-memory store then it won't check underlying storage cache {@link Cache}.
|
||||
* Internally it used {@link ConcurrentHashMap} to store do level-1 caching.
|
||||
*
|
||||
* @see CacheFactory
|
||||
* @see org.apache.dubbo.cache.support.jcache.JCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.lru.LruCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.expiring.ExpiringCacheFactory
|
||||
*/
|
||||
public abstract class AbstractCacheFactory implements CacheFactory {
|
||||
|
||||
/**
|
||||
* This is used to store factory level-1 cached data.
|
||||
*/
|
||||
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
|
||||
|
||||
/**
|
||||
* Takes URL and invocation instance and return cache instance for a given url.
|
||||
* @param url url of the method
|
||||
* @param invocation invocation context.
|
||||
* @return Instance of cache store used as storage for caching return values.
|
||||
*/
|
||||
@Override
|
||||
public Cache getCache(URL url, Invocation invocation) {
|
||||
url = url.addParameter(METHOD_KEY, invocation.getMethodName());
|
||||
String key = url.toFullString();
|
||||
Cache cache = caches.get(key);
|
||||
if (cache == null) {
|
||||
caches.put(key, createCache(url));
|
||||
cache = caches.get(key);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes url as an method argument and return new instance of cache store implemented by AbstractCacheFactory subclass.
|
||||
* @param url url of the method
|
||||
* @return Create and return new instance of cache store used as storage for caching return values.
|
||||
*/
|
||||
protected abstract Cache createCache(URL url);
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.cache.support;
|
||||
|
||||
import org.apache.dubbo.cache.Cache;
|
||||
import org.apache.dubbo.cache.CacheFactory;
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;
|
||||
|
||||
/**
|
||||
* AbstractCacheFactory is a default implementation of {@link CacheFactory}. It abstract out the key formation from URL along with
|
||||
* invocation method. It initially check if the value for key already present in own local in-memory store then it won't check underlying storage cache {@link Cache}.
|
||||
* Internally it used {@link ConcurrentHashMap} to store do level-1 caching.
|
||||
*
|
||||
* @see CacheFactory
|
||||
* @see org.apache.dubbo.cache.support.jcache.JCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.lru.LruCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.expiring.ExpiringCacheFactory
|
||||
*/
|
||||
public abstract class AbstractCacheFactory implements CacheFactory {
|
||||
|
||||
/**
|
||||
* This is used to store factory level-1 cached data.
|
||||
*/
|
||||
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
|
||||
|
||||
/**
|
||||
* Takes URL and invocation instance and return cache instance for a given url.
|
||||
* @param url url of the method
|
||||
* @param invocation invocation context.
|
||||
* @return Instance of cache store used as storage for caching return values.
|
||||
*/
|
||||
@Override
|
||||
public Cache getCache(URL url, Invocation invocation) {
|
||||
url = url.addParameter(METHOD_KEY, invocation.getMethodName());
|
||||
String key = url.toFullString();
|
||||
Cache cache = caches.get(key);
|
||||
if (cache == null) {
|
||||
caches.put(key, createCache(url));
|
||||
cache = caches.get(key);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes url as an method argument and return new instance of cache store implemented by AbstractCacheFactory subclass.
|
||||
* @param url url of the method
|
||||
* @return Create and return new instance of cache store used as storage for caching return values.
|
||||
*/
|
||||
protected abstract Cache createCache(URL url);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,87 +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.cache.support.jcache;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
|
||||
import javax.cache.Cache;
|
||||
import javax.cache.CacheException;
|
||||
import javax.cache.CacheManager;
|
||||
import javax.cache.Caching;
|
||||
import javax.cache.configuration.MutableConfiguration;
|
||||
import javax.cache.expiry.CreatedExpiryPolicy;
|
||||
import javax.cache.expiry.Duration;
|
||||
import javax.cache.spi.CachingProvider;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;
|
||||
|
||||
/**
|
||||
* This class store the cache value per thread. If a service,method,consumer or provided is configured with key <b>cache</b>
|
||||
* with value <b>jcache</b>, dubbo initialize the instance of this class using {@link JCacheFactory} to store method's returns value
|
||||
* to server from store without making method call.
|
||||
*
|
||||
* @see Cache
|
||||
* @see JCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.AbstractCacheFactory
|
||||
* @see org.apache.dubbo.cache.filter.CacheFilter
|
||||
*/
|
||||
public class JCache implements org.apache.dubbo.cache.Cache {
|
||||
|
||||
private final Cache<Object, Object> store;
|
||||
|
||||
public JCache(URL url) {
|
||||
String method = url.getParameter(METHOD_KEY, "");
|
||||
String key = url.getAddress() + "." + url.getServiceKey() + "." + method;
|
||||
// jcache parameter is the full-qualified class name of SPI implementation
|
||||
String type = url.getParameter("jcache");
|
||||
|
||||
CachingProvider provider = StringUtils.isEmpty(type) ? Caching.getCachingProvider() : Caching.getCachingProvider(type);
|
||||
CacheManager cacheManager = provider.getCacheManager();
|
||||
Cache<Object, Object> cache = cacheManager.getCache(key);
|
||||
if (cache == null) {
|
||||
try {
|
||||
//configure the cache
|
||||
MutableConfiguration config =
|
||||
new MutableConfiguration<>()
|
||||
.setTypes(Object.class, Object.class)
|
||||
.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.MILLISECONDS, url.getMethodParameter(method, "cache.write.expire", 60 * 1000))))
|
||||
.setStoreByValue(false)
|
||||
.setManagementEnabled(true)
|
||||
.setStatisticsEnabled(true);
|
||||
cache = cacheManager.createCache(key, config);
|
||||
} catch (CacheException e) {
|
||||
// concurrent cache initialization
|
||||
cache = cacheManager.getCache(key);
|
||||
}
|
||||
}
|
||||
|
||||
this.store = cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Object key, Object value) {
|
||||
store.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return store.get(key);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.cache.support.jcache;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
|
||||
import javax.cache.Cache;
|
||||
import javax.cache.CacheException;
|
||||
import javax.cache.CacheManager;
|
||||
import javax.cache.Caching;
|
||||
import javax.cache.configuration.MutableConfiguration;
|
||||
import javax.cache.expiry.CreatedExpiryPolicy;
|
||||
import javax.cache.expiry.Duration;
|
||||
import javax.cache.spi.CachingProvider;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;
|
||||
|
||||
/**
|
||||
* This class store the cache value per thread. If a service,method,consumer or provided is configured with key <b>cache</b>
|
||||
* with value <b>jcache</b>, dubbo initialize the instance of this class using {@link JCacheFactory} to store method's returns value
|
||||
* to server from store without making method call.
|
||||
*
|
||||
* @see Cache
|
||||
* @see JCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.AbstractCacheFactory
|
||||
* @see org.apache.dubbo.cache.filter.CacheFilter
|
||||
*/
|
||||
public class JCache implements org.apache.dubbo.cache.Cache {
|
||||
|
||||
private final Cache<Object, Object> store;
|
||||
|
||||
public JCache(URL url) {
|
||||
String method = url.getParameter(METHOD_KEY, "");
|
||||
String key = url.getAddress() + "." + url.getServiceKey() + "." + method;
|
||||
// jcache parameter is the full-qualified class name of SPI implementation
|
||||
String type = url.getParameter("jcache");
|
||||
|
||||
CachingProvider provider = StringUtils.isEmpty(type) ? Caching.getCachingProvider() : Caching.getCachingProvider(type);
|
||||
CacheManager cacheManager = provider.getCacheManager();
|
||||
Cache<Object, Object> cache = cacheManager.getCache(key);
|
||||
if (cache == null) {
|
||||
try {
|
||||
//configure the cache
|
||||
MutableConfiguration config =
|
||||
new MutableConfiguration<>()
|
||||
.setTypes(Object.class, Object.class)
|
||||
.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.MILLISECONDS, url.getMethodParameter(method, "cache.write.expire", 60 * 1000))))
|
||||
.setStoreByValue(false)
|
||||
.setManagementEnabled(true)
|
||||
.setStatisticsEnabled(true);
|
||||
cache = cacheManager.createCache(key, config);
|
||||
} catch (CacheException e) {
|
||||
// concurrent cache initialization
|
||||
cache = cacheManager.getCache(key);
|
||||
}
|
||||
}
|
||||
|
||||
this.store = cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Object key, Object value) {
|
||||
store.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return store.get(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,48 +1,48 @@
|
|||
/*
|
||||
* 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.cache.support.jcache;
|
||||
|
||||
import org.apache.dubbo.cache.Cache;
|
||||
import org.apache.dubbo.cache.support.AbstractCacheFactory;
|
||||
import org.apache.dubbo.common.URL;
|
||||
|
||||
import javax.cache.spi.CachingProvider;
|
||||
|
||||
/**
|
||||
* JCacheFactory is factory class to provide instance of javax spi cache.Implement {@link org.apache.dubbo.cache.CacheFactory} by
|
||||
* extending {@link AbstractCacheFactory} and provide
|
||||
* @see AbstractCacheFactory
|
||||
* @see JCache
|
||||
* @see org.apache.dubbo.cache.filter.CacheFilter
|
||||
* @see Cache
|
||||
* @see CachingProvider
|
||||
* @see javax.cache.Cache
|
||||
* @see javax.cache.CacheManager
|
||||
*/
|
||||
public class JCacheFactory extends AbstractCacheFactory {
|
||||
|
||||
/**
|
||||
* Takes url as an method argument and return new instance of cache store implemented by JCache.
|
||||
* @param url url of the method
|
||||
* @return JCache instance of cache
|
||||
*/
|
||||
@Override
|
||||
protected Cache createCache(URL url) {
|
||||
return new JCache(url);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.cache.support.jcache;
|
||||
|
||||
import org.apache.dubbo.cache.Cache;
|
||||
import org.apache.dubbo.cache.support.AbstractCacheFactory;
|
||||
import org.apache.dubbo.common.URL;
|
||||
|
||||
import javax.cache.spi.CachingProvider;
|
||||
|
||||
/**
|
||||
* JCacheFactory is factory class to provide instance of javax spi cache.Implement {@link org.apache.dubbo.cache.CacheFactory} by
|
||||
* extending {@link AbstractCacheFactory} and provide
|
||||
* @see AbstractCacheFactory
|
||||
* @see JCache
|
||||
* @see org.apache.dubbo.cache.filter.CacheFilter
|
||||
* @see Cache
|
||||
* @see CachingProvider
|
||||
* @see javax.cache.Cache
|
||||
* @see javax.cache.CacheManager
|
||||
*/
|
||||
public class JCacheFactory extends AbstractCacheFactory {
|
||||
|
||||
/**
|
||||
* Takes url as an method argument and return new instance of cache store implemented by JCache.
|
||||
* @param url url of the method
|
||||
* @return JCache instance of cache
|
||||
*/
|
||||
@Override
|
||||
protected Cache createCache(URL url) {
|
||||
return new JCache(url);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,80 +1,80 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.cache.support.lru;
|
||||
|
||||
import org.apache.dubbo.cache.Cache;
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.utils.LRUCache;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class store the cache value per thread. If a service,method,consumer or provided is configured with key <b>cache</b>
|
||||
* with value <b>lru</b>, dubbo initialize the instance of this class using {@link LruCacheFactory} to store method's returns value
|
||||
* to server from store without making method call.
|
||||
* <pre>
|
||||
* e.g. 1) <dubbo:service cache="lru" cache.size="5000"/>
|
||||
* 2) <dubbo:consumer cache="lru" />
|
||||
* </pre>
|
||||
* <pre>
|
||||
* LruCache uses url's <b>cache.size</b> value for its max store size, if nothing is provided then
|
||||
* default value will be 1000
|
||||
* </pre>
|
||||
*
|
||||
* @see Cache
|
||||
* @see LruCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.AbstractCacheFactory
|
||||
* @see org.apache.dubbo.cache.filter.CacheFilter
|
||||
*/
|
||||
public class LruCache implements Cache {
|
||||
|
||||
/**
|
||||
* This is used to store cache records
|
||||
*/
|
||||
private final Map<Object, Object> store;
|
||||
|
||||
/**
|
||||
* Initialize LruCache, it uses constructor argument <b>cache.size</b> value as its storage max size.
|
||||
* If nothing is provided then it will use 1000 as default value.
|
||||
* @param url A valid URL instance
|
||||
*/
|
||||
public LruCache(URL url) {
|
||||
final int max = url.getParameter("cache.size", 1000);
|
||||
this.store = new LRUCache<>(max);
|
||||
}
|
||||
|
||||
/**
|
||||
* API to store value against a key in the calling thread scope.
|
||||
* @param key Unique identifier for the object being store.
|
||||
* @param value Value getting store
|
||||
*/
|
||||
@Override
|
||||
public void put(Object key, Object value) {
|
||||
store.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* API to return stored value using a key against the calling thread specific store.
|
||||
* @param key Unique identifier for cache lookup
|
||||
* @return Return stored object against key
|
||||
*/
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return store.get(key);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.cache.support.lru;
|
||||
|
||||
import org.apache.dubbo.cache.Cache;
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.utils.LRUCache;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class store the cache value per thread. If a service,method,consumer or provided is configured with key <b>cache</b>
|
||||
* with value <b>lru</b>, dubbo initialize the instance of this class using {@link LruCacheFactory} to store method's returns value
|
||||
* to server from store without making method call.
|
||||
* <pre>
|
||||
* e.g. 1) <dubbo:service cache="lru" cache.size="5000"/>
|
||||
* 2) <dubbo:consumer cache="lru" />
|
||||
* </pre>
|
||||
* <pre>
|
||||
* LruCache uses url's <b>cache.size</b> value for its max store size, if nothing is provided then
|
||||
* default value will be 1000
|
||||
* </pre>
|
||||
*
|
||||
* @see Cache
|
||||
* @see LruCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.AbstractCacheFactory
|
||||
* @see org.apache.dubbo.cache.filter.CacheFilter
|
||||
*/
|
||||
public class LruCache implements Cache {
|
||||
|
||||
/**
|
||||
* This is used to store cache records
|
||||
*/
|
||||
private final Map<Object, Object> store;
|
||||
|
||||
/**
|
||||
* Initialize LruCache, it uses constructor argument <b>cache.size</b> value as its storage max size.
|
||||
* If nothing is provided then it will use 1000 as default value.
|
||||
* @param url A valid URL instance
|
||||
*/
|
||||
public LruCache(URL url) {
|
||||
final int max = url.getParameter("cache.size", 1000);
|
||||
this.store = new LRUCache<>(max);
|
||||
}
|
||||
|
||||
/**
|
||||
* API to store value against a key in the calling thread scope.
|
||||
* @param key Unique identifier for the object being store.
|
||||
* @param value Value getting store
|
||||
*/
|
||||
@Override
|
||||
public void put(Object key, Object value) {
|
||||
store.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* API to return stored value using a key against the calling thread specific store.
|
||||
* @param key Unique identifier for cache lookup
|
||||
* @return Return stored object against key
|
||||
*/
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return store.get(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,43 @@
|
|||
/*
|
||||
* 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.cache.support.lru;
|
||||
|
||||
import org.apache.dubbo.cache.Cache;
|
||||
import org.apache.dubbo.cache.support.AbstractCacheFactory;
|
||||
import org.apache.dubbo.common.URL;
|
||||
|
||||
/**
|
||||
* Implement {@link org.apache.dubbo.cache.CacheFactory} by extending {@link AbstractCacheFactory} and provide
|
||||
* instance of new {@link LruCache}.
|
||||
*
|
||||
* @see AbstractCacheFactory
|
||||
* @see LruCache
|
||||
* @see Cache
|
||||
*/
|
||||
public class LruCacheFactory extends AbstractCacheFactory {
|
||||
|
||||
/**
|
||||
* Takes url as an method argument and return new instance of cache store implemented by LruCache.
|
||||
* @param url url of the method
|
||||
* @return ThreadLocalCache instance of cache
|
||||
*/
|
||||
@Override
|
||||
protected Cache createCache(URL url) {
|
||||
return new LruCache(url);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.cache.support.lru;
|
||||
|
||||
import org.apache.dubbo.cache.Cache;
|
||||
import org.apache.dubbo.cache.support.AbstractCacheFactory;
|
||||
import org.apache.dubbo.common.URL;
|
||||
|
||||
/**
|
||||
* Implement {@link org.apache.dubbo.cache.CacheFactory} by extending {@link AbstractCacheFactory} and provide
|
||||
* instance of new {@link LruCache}.
|
||||
*
|
||||
* @see AbstractCacheFactory
|
||||
* @see LruCache
|
||||
* @see Cache
|
||||
*/
|
||||
public class LruCacheFactory extends AbstractCacheFactory {
|
||||
|
||||
/**
|
||||
* Takes url as an method argument and return new instance of cache store implemented by LruCache.
|
||||
* @param url url of the method
|
||||
* @return ThreadLocalCache instance of cache
|
||||
*/
|
||||
@Override
|
||||
protected Cache createCache(URL url) {
|
||||
return new LruCache(url);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,77 +1,77 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.cache.support.threadlocal;
|
||||
|
||||
import org.apache.dubbo.cache.Cache;
|
||||
import org.apache.dubbo.common.URL;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class store the cache value per thread. If a service,method,consumer or provided is configured with key <b>cache</b>
|
||||
* with value <b>threadlocal</b>, dubbo initialize the instance of this class using {@link ThreadLocalCacheFactory} to store method's returns value
|
||||
* to server from store without making method call.
|
||||
* <pre>
|
||||
* e.g. <dubbo:service cache="threadlocal" />
|
||||
* </pre>
|
||||
* <pre>
|
||||
* As this ThreadLocalCache stores key-value in memory without any expiry or delete support per thread wise, if number threads and number of key-value are high then jvm should be
|
||||
* configured with appropriate memory.
|
||||
* </pre>
|
||||
*
|
||||
* @see org.apache.dubbo.cache.support.AbstractCacheFactory
|
||||
* @see org.apache.dubbo.cache.filter.CacheFilter
|
||||
* @see Cache
|
||||
*/
|
||||
public class ThreadLocalCache implements Cache {
|
||||
|
||||
/**
|
||||
* Thread local variable to store cached data.
|
||||
*/
|
||||
private final ThreadLocal<Map<Object, Object>> store;
|
||||
|
||||
/**
|
||||
* Taken URL as an argument to create an instance of ThreadLocalCache. In this version of implementation constructor
|
||||
* argument is not getting used in the scope of this class.
|
||||
* @param url
|
||||
*/
|
||||
public ThreadLocalCache(URL url) {
|
||||
this.store = ThreadLocal.withInitial(HashMap::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* API to store value against a key in the calling thread scope.
|
||||
* @param key Unique identifier for the object being store.
|
||||
* @param value Value getting store
|
||||
*/
|
||||
@Override
|
||||
public void put(Object key, Object value) {
|
||||
store.get().put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* API to return stored value using a key against the calling thread specific store.
|
||||
* @param key Unique identifier for cache lookup
|
||||
* @return Return stored object against key
|
||||
*/
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return store.get().get(key);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.cache.support.threadlocal;
|
||||
|
||||
import org.apache.dubbo.cache.Cache;
|
||||
import org.apache.dubbo.common.URL;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class store the cache value per thread. If a service,method,consumer or provided is configured with key <b>cache</b>
|
||||
* with value <b>threadlocal</b>, dubbo initialize the instance of this class using {@link ThreadLocalCacheFactory} to store method's returns value
|
||||
* to server from store without making method call.
|
||||
* <pre>
|
||||
* e.g. <dubbo:service cache="threadlocal" />
|
||||
* </pre>
|
||||
* <pre>
|
||||
* As this ThreadLocalCache stores key-value in memory without any expiry or delete support per thread wise, if number threads and number of key-value are high then jvm should be
|
||||
* configured with appropriate memory.
|
||||
* </pre>
|
||||
*
|
||||
* @see org.apache.dubbo.cache.support.AbstractCacheFactory
|
||||
* @see org.apache.dubbo.cache.filter.CacheFilter
|
||||
* @see Cache
|
||||
*/
|
||||
public class ThreadLocalCache implements Cache {
|
||||
|
||||
/**
|
||||
* Thread local variable to store cached data.
|
||||
*/
|
||||
private final ThreadLocal<Map<Object, Object>> store;
|
||||
|
||||
/**
|
||||
* Taken URL as an argument to create an instance of ThreadLocalCache. In this version of implementation constructor
|
||||
* argument is not getting used in the scope of this class.
|
||||
* @param url
|
||||
*/
|
||||
public ThreadLocalCache(URL url) {
|
||||
this.store = ThreadLocal.withInitial(HashMap::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* API to store value against a key in the calling thread scope.
|
||||
* @param key Unique identifier for the object being store.
|
||||
* @param value Value getting store
|
||||
*/
|
||||
@Override
|
||||
public void put(Object key, Object value) {
|
||||
store.get().put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* API to return stored value using a key against the calling thread specific store.
|
||||
* @param key Unique identifier for cache lookup
|
||||
* @return Return stored object against key
|
||||
*/
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return store.get().get(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,43 @@
|
|||
/*
|
||||
* 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.cache.support.threadlocal;
|
||||
|
||||
import org.apache.dubbo.cache.Cache;
|
||||
import org.apache.dubbo.cache.support.AbstractCacheFactory;
|
||||
import org.apache.dubbo.common.URL;
|
||||
|
||||
/**
|
||||
* Implement {@link org.apache.dubbo.cache.CacheFactory} by extending {@link AbstractCacheFactory} and provide
|
||||
* instance of new {@link ThreadLocalCache}. Note about this class is, each thread does not have a local copy of factory.
|
||||
*
|
||||
* @see AbstractCacheFactory
|
||||
* @see ThreadLocalCache
|
||||
* @see Cache
|
||||
*/
|
||||
public class ThreadLocalCacheFactory extends AbstractCacheFactory {
|
||||
|
||||
/**
|
||||
* Takes url as an method argument and return new instance of cache store implemented by ThreadLocalCache.
|
||||
* @param url url of the method
|
||||
* @return ThreadLocalCache instance of cache
|
||||
*/
|
||||
@Override
|
||||
protected Cache createCache(URL url) {
|
||||
return new ThreadLocalCache(url);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.cache.support.threadlocal;
|
||||
|
||||
import org.apache.dubbo.cache.Cache;
|
||||
import org.apache.dubbo.cache.support.AbstractCacheFactory;
|
||||
import org.apache.dubbo.common.URL;
|
||||
|
||||
/**
|
||||
* Implement {@link org.apache.dubbo.cache.CacheFactory} by extending {@link AbstractCacheFactory} and provide
|
||||
* instance of new {@link ThreadLocalCache}. Note about this class is, each thread does not have a local copy of factory.
|
||||
*
|
||||
* @see AbstractCacheFactory
|
||||
* @see ThreadLocalCache
|
||||
* @see Cache
|
||||
*/
|
||||
public class ThreadLocalCacheFactory extends AbstractCacheFactory {
|
||||
|
||||
/**
|
||||
* Takes url as an method argument and return new instance of cache store implemented by ThreadLocalCache.
|
||||
* @param url url of the method
|
||||
* @return ThreadLocalCache instance of cache
|
||||
*/
|
||||
@Override
|
||||
protected Cache createCache(URL url) {
|
||||
return new ThreadLocalCache(url);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
threadlocal=org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory
|
||||
lru=org.apache.dubbo.cache.support.lru.LruCacheFactory
|
||||
jcache=org.apache.dubbo.cache.support.jcache.JCacheFactory
|
||||
threadlocal=org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory
|
||||
lru=org.apache.dubbo.cache.support.lru.LruCacheFactory
|
||||
jcache=org.apache.dubbo.cache.support.jcache.JCacheFactory
|
||||
expiring=org.apache.dubbo.cache.support.expiring.ExpiringCacheFactory
|
||||
|
|
@ -19,8 +19,7 @@
|
|||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-filter</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
<version>2.7.7-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>dubbo-filter-validation</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
|
|
|||
|
|
@ -1,39 +1,39 @@
|
|||
/*
|
||||
* 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.validation;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.Adaptive;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
|
||||
import static org.apache.dubbo.common.constants.FilterConstants.VALIDATION_KEY;
|
||||
|
||||
/**
|
||||
* Instance of Validation interface provide instance of {@link Validator} based on the value of <b>validation</b> attribute.
|
||||
*/
|
||||
@SPI("jvalidation")
|
||||
public interface Validation {
|
||||
|
||||
/**
|
||||
* Return the instance of {@link Validator} for a given url.
|
||||
* @param url Invocation url
|
||||
* @return Instance of {@link Validator}
|
||||
*/
|
||||
@Adaptive(VALIDATION_KEY)
|
||||
Validator getValidator(URL url);
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.validation;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.Adaptive;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
|
||||
import static org.apache.dubbo.common.constants.FilterConstants.VALIDATION_KEY;
|
||||
|
||||
/**
|
||||
* Instance of Validation interface provide instance of {@link Validator} based on the value of <b>validation</b> attribute.
|
||||
*/
|
||||
@SPI("jvalidation")
|
||||
public interface Validation {
|
||||
|
||||
/**
|
||||
* Return the instance of {@link Validator} for a given url.
|
||||
* @param url Invocation url
|
||||
* @return Instance of {@link Validator}
|
||||
*/
|
||||
@Adaptive(VALIDATION_KEY)
|
||||
Validator getValidator(URL url);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
/*
|
||||
* 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.validation;
|
||||
|
||||
/**
|
||||
* Instance of validator class is an extension to perform validation on method input parameter before the actual method invocation.
|
||||
*
|
||||
*/
|
||||
public interface Validator {
|
||||
|
||||
void validate(String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Exception;
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.validation;
|
||||
|
||||
/**
|
||||
* Instance of validator class is an extension to perform validation on method input parameter before the actual method invocation.
|
||||
*
|
||||
*/
|
||||
public interface Validator {
|
||||
|
||||
void validate(String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Exception;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,104 +1,104 @@
|
|||
/*
|
||||
* 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.validation.filter;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.utils.ConfigUtils;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.validation.Validation;
|
||||
import org.apache.dubbo.validation.Validator;
|
||||
|
||||
import javax.validation.ValidationException;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
|
||||
import static org.apache.dubbo.common.constants.FilterConstants.VALIDATION_KEY;
|
||||
|
||||
/**
|
||||
* ValidationFilter invoke the validation by finding the right {@link Validator} instance based on the
|
||||
* configured <b>validation</b> attribute value of invoker url before the actual method invocation.
|
||||
*
|
||||
* <pre>
|
||||
* e.g. <dubbo:method name="save" validation="jvalidation" />
|
||||
* In the above configuration a validation has been configured of type jvalidation. On invocation of method <b>save</b>
|
||||
* dubbo will invoke {@link org.apache.dubbo.validation.support.jvalidation.JValidator}
|
||||
* </pre>
|
||||
*
|
||||
* To add a new type of validation
|
||||
* <pre>
|
||||
* e.g. <dubbo:method name="save" validation="special" />
|
||||
* where "special" is representing a validator for special character.
|
||||
* </pre>
|
||||
*
|
||||
* developer needs to do
|
||||
* <br/>
|
||||
* 1)Implement a SpecialValidation.java class (package name xxx.yyy.zzz) either by implementing {@link Validation} or extending {@link org.apache.dubbo.validation.support.AbstractValidation} <br/>
|
||||
* 2)Implement a SpecialValidator.java class (package name xxx.yyy.zzz) <br/>
|
||||
* 3)Add an entry <b>special</b>=<b>xxx.yyy.zzz.SpecialValidation</b> under <b>META-INF folders org.apache.dubbo.validation.Validation file</b>.
|
||||
*
|
||||
* @see Validation
|
||||
* @see Validator
|
||||
* @see Filter
|
||||
* @see org.apache.dubbo.validation.support.AbstractValidation
|
||||
*/
|
||||
@Activate(group = {CONSUMER, PROVIDER}, value = VALIDATION_KEY, order = 10000)
|
||||
public class ValidationFilter implements Filter {
|
||||
|
||||
private Validation validation;
|
||||
|
||||
/**
|
||||
* Sets the validation instance for ValidationFilter
|
||||
* @param validation Validation instance injected by dubbo framework based on "validation" attribute value.
|
||||
*/
|
||||
public void setValidation(Validation validation) {
|
||||
this.validation = validation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the validation of before invoking the actual method based on <b>validation</b> attribute value.
|
||||
* @param invoker service
|
||||
* @param invocation invocation.
|
||||
* @return Method invocation result
|
||||
* @throws RpcException Throws RpcException if validation failed or any other runtime exception occurred.
|
||||
*/
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
if (validation != null && !invocation.getMethodName().startsWith("$")
|
||||
&& ConfigUtils.isNotEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), VALIDATION_KEY))) {
|
||||
try {
|
||||
Validator validator = validation.getValidator(invoker.getUrl());
|
||||
if (validator != null) {
|
||||
validator.validate(invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());
|
||||
}
|
||||
} catch (RpcException e) {
|
||||
throw e;
|
||||
} catch (ValidationException e) {
|
||||
// only use exception's message to avoid potential serialization issue
|
||||
return AsyncRpcResult.newDefaultAsyncResult(new ValidationException(e.getMessage()), invocation);
|
||||
} catch (Throwable t) {
|
||||
return AsyncRpcResult.newDefaultAsyncResult(t, invocation);
|
||||
}
|
||||
}
|
||||
return invoker.invoke(invocation);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.validation.filter;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.utils.ConfigUtils;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.validation.Validation;
|
||||
import org.apache.dubbo.validation.Validator;
|
||||
|
||||
import javax.validation.ValidationException;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
|
||||
import static org.apache.dubbo.common.constants.FilterConstants.VALIDATION_KEY;
|
||||
|
||||
/**
|
||||
* ValidationFilter invoke the validation by finding the right {@link Validator} instance based on the
|
||||
* configured <b>validation</b> attribute value of invoker url before the actual method invocation.
|
||||
*
|
||||
* <pre>
|
||||
* e.g. <dubbo:method name="save" validation="jvalidation" />
|
||||
* In the above configuration a validation has been configured of type jvalidation. On invocation of method <b>save</b>
|
||||
* dubbo will invoke {@link org.apache.dubbo.validation.support.jvalidation.JValidator}
|
||||
* </pre>
|
||||
*
|
||||
* To add a new type of validation
|
||||
* <pre>
|
||||
* e.g. <dubbo:method name="save" validation="special" />
|
||||
* where "special" is representing a validator for special character.
|
||||
* </pre>
|
||||
*
|
||||
* developer needs to do
|
||||
* <br/>
|
||||
* 1)Implement a SpecialValidation.java class (package name xxx.yyy.zzz) either by implementing {@link Validation} or extending {@link org.apache.dubbo.validation.support.AbstractValidation} <br/>
|
||||
* 2)Implement a SpecialValidator.java class (package name xxx.yyy.zzz) <br/>
|
||||
* 3)Add an entry <b>special</b>=<b>xxx.yyy.zzz.SpecialValidation</b> under <b>META-INF folders org.apache.dubbo.validation.Validation file</b>.
|
||||
*
|
||||
* @see Validation
|
||||
* @see Validator
|
||||
* @see Filter
|
||||
* @see org.apache.dubbo.validation.support.AbstractValidation
|
||||
*/
|
||||
@Activate(group = {CONSUMER, PROVIDER}, value = VALIDATION_KEY, order = 10000)
|
||||
public class ValidationFilter implements Filter {
|
||||
|
||||
private Validation validation;
|
||||
|
||||
/**
|
||||
* Sets the validation instance for ValidationFilter
|
||||
* @param validation Validation instance injected by dubbo framework based on "validation" attribute value.
|
||||
*/
|
||||
public void setValidation(Validation validation) {
|
||||
this.validation = validation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the validation of before invoking the actual method based on <b>validation</b> attribute value.
|
||||
* @param invoker service
|
||||
* @param invocation invocation.
|
||||
* @return Method invocation result
|
||||
* @throws RpcException Throws RpcException if validation failed or any other runtime exception occurred.
|
||||
*/
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
if (validation != null && !invocation.getMethodName().startsWith("$")
|
||||
&& ConfigUtils.isNotEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), VALIDATION_KEY))) {
|
||||
try {
|
||||
Validator validator = validation.getValidator(invoker.getUrl());
|
||||
if (validator != null) {
|
||||
validator.validate(invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());
|
||||
}
|
||||
} catch (RpcException e) {
|
||||
throw e;
|
||||
} catch (ValidationException e) {
|
||||
// only use exception's message to avoid potential serialization issue
|
||||
return AsyncRpcResult.newDefaultAsyncResult(new ValidationException(e.getMessage()), invocation);
|
||||
} catch (Throwable t) {
|
||||
return AsyncRpcResult.newDefaultAsyncResult(t, invocation);
|
||||
}
|
||||
}
|
||||
return invoker.invoke(invocation);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,51 +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.validation.support;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.validation.Validation;
|
||||
import org.apache.dubbo.validation.Validator;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* AbstractValidation is abstract class for Validation interface. It helps low level Validation implementation classes
|
||||
* by performing common task e.g. key formation, storing instance of validation class to avoid creation of unnecessary
|
||||
* copy of validation instance and faster execution.
|
||||
*
|
||||
* @see Validation
|
||||
* @see Validator
|
||||
*/
|
||||
public abstract class AbstractValidation implements Validation {
|
||||
|
||||
private final ConcurrentMap<String, Validator> validators = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public Validator getValidator(URL url) {
|
||||
String key = url.toFullString();
|
||||
Validator validator = validators.get(key);
|
||||
if (validator == null) {
|
||||
validators.put(key, createValidator(url));
|
||||
validator = validators.get(key);
|
||||
}
|
||||
return validator;
|
||||
}
|
||||
|
||||
protected abstract Validator createValidator(URL url);
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.validation.support;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.validation.Validation;
|
||||
import org.apache.dubbo.validation.Validator;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* AbstractValidation is abstract class for Validation interface. It helps low level Validation implementation classes
|
||||
* by performing common task e.g. key formation, storing instance of validation class to avoid creation of unnecessary
|
||||
* copy of validation instance and faster execution.
|
||||
*
|
||||
* @see Validation
|
||||
* @see Validator
|
||||
*/
|
||||
public abstract class AbstractValidation implements Validation {
|
||||
|
||||
private final ConcurrentMap<String, Validator> validators = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public Validator getValidator(URL url) {
|
||||
String key = url.toFullString();
|
||||
Validator validator = validators.get(key);
|
||||
if (validator == null) {
|
||||
validators.put(key, createValidator(url));
|
||||
validator = validators.get(key);
|
||||
}
|
||||
return validator;
|
||||
}
|
||||
|
||||
protected abstract Validator createValidator(URL url);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,40 +1,40 @@
|
|||
/*
|
||||
* 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.validation.support.jvalidation;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.validation.Validator;
|
||||
import org.apache.dubbo.validation.support.AbstractValidation;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link Validator} using input argument url.
|
||||
* @see AbstractValidation
|
||||
* @see Validator
|
||||
*/
|
||||
public class JValidation extends AbstractValidation {
|
||||
|
||||
/**
|
||||
* Return new instance of {@link JValidator}
|
||||
* @param url Valid URL instance
|
||||
* @return Instance of JValidator
|
||||
*/
|
||||
@Override
|
||||
protected Validator createValidator(URL url) {
|
||||
return new JValidator(url);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.validation.support.jvalidation;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.validation.Validator;
|
||||
import org.apache.dubbo.validation.support.AbstractValidation;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link Validator} using input argument url.
|
||||
* @see AbstractValidation
|
||||
* @see Validator
|
||||
*/
|
||||
public class JValidation extends AbstractValidation {
|
||||
|
||||
/**
|
||||
* Return new instance of {@link JValidator}
|
||||
* @param url Valid URL instance
|
||||
* @return Instance of JValidator
|
||||
*/
|
||||
@Override
|
||||
protected Validator createValidator(URL url) {
|
||||
return new JValidator(url);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,330 +1,330 @@
|
|||
/*
|
||||
* 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.validation.support.jvalidation;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.bytecode.ClassGenerator;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.utils.ReflectUtils;
|
||||
import org.apache.dubbo.validation.MethodValidated;
|
||||
import org.apache.dubbo.validation.Validator;
|
||||
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtField;
|
||||
import javassist.CtNewConstructor;
|
||||
import javassist.Modifier;
|
||||
import javassist.NotFoundException;
|
||||
import javassist.bytecode.AnnotationsAttribute;
|
||||
import javassist.bytecode.ClassFile;
|
||||
import javassist.bytecode.ConstPool;
|
||||
import javassist.bytecode.annotation.ArrayMemberValue;
|
||||
import javassist.bytecode.annotation.BooleanMemberValue;
|
||||
import javassist.bytecode.annotation.ByteMemberValue;
|
||||
import javassist.bytecode.annotation.CharMemberValue;
|
||||
import javassist.bytecode.annotation.ClassMemberValue;
|
||||
import javassist.bytecode.annotation.DoubleMemberValue;
|
||||
import javassist.bytecode.annotation.EnumMemberValue;
|
||||
import javassist.bytecode.annotation.FloatMemberValue;
|
||||
import javassist.bytecode.annotation.IntegerMemberValue;
|
||||
import javassist.bytecode.annotation.LongMemberValue;
|
||||
import javassist.bytecode.annotation.MemberValue;
|
||||
import javassist.bytecode.annotation.ShortMemberValue;
|
||||
import javassist.bytecode.annotation.StringMemberValue;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.ValidatorFactory;
|
||||
import javax.validation.groups.Default;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Implementation of JValidation. JValidation is invoked if configuration validation attribute value is 'jvalidation'.
|
||||
* <pre>
|
||||
* e.g. <dubbo:method name="save" validation="jvalidation" />
|
||||
* </pre>
|
||||
*/
|
||||
public class JValidator implements Validator {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JValidator.class);
|
||||
|
||||
private final Class<?> clazz;
|
||||
|
||||
private final Map<String, Class> methodClassMap;
|
||||
|
||||
private final javax.validation.Validator validator;
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public JValidator(URL url) {
|
||||
this.clazz = ReflectUtils.forName(url.getServiceInterface());
|
||||
String jvalidation = url.getParameter("jvalidation");
|
||||
ValidatorFactory factory;
|
||||
if (jvalidation != null && jvalidation.length() > 0) {
|
||||
factory = Validation.byProvider((Class) ReflectUtils.forName(jvalidation)).configure().buildValidatorFactory();
|
||||
} else {
|
||||
factory = Validation.buildDefaultValidatorFactory();
|
||||
}
|
||||
this.validator = factory.getValidator();
|
||||
this.methodClassMap = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
private static Object getMethodParameterBean(Class<?> clazz, Method method, Object[] args) {
|
||||
if (!hasConstraintParameter(method)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
String parameterClassName = generateMethodParameterClassName(clazz, method);
|
||||
Class<?> parameterClass;
|
||||
try {
|
||||
parameterClass = Class.forName(parameterClassName, true, clazz.getClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
parameterClass = generateMethodParameterClass(clazz, method, parameterClassName);
|
||||
}
|
||||
Object parameterBean = parameterClass.newInstance();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
Field field = parameterClass.getField(method.getName() + "Argument" + i);
|
||||
field.set(parameterBean, args[i]);
|
||||
}
|
||||
return parameterBean;
|
||||
} catch (Throwable e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* try to generate methodParameterClass.
|
||||
*
|
||||
* @param clazz interface class
|
||||
* @param method invoke method
|
||||
* @param parameterClassName generated parameterClassName
|
||||
* @return Class<?> generated methodParameterClass
|
||||
* @throws Exception
|
||||
*/
|
||||
private static Class<?> generateMethodParameterClass(Class<?> clazz, Method method, String parameterClassName)
|
||||
throws Exception {
|
||||
ClassPool pool = ClassGenerator.getClassPool(clazz.getClassLoader());
|
||||
synchronized (parameterClassName.intern()) {
|
||||
CtClass ctClass = null;
|
||||
try {
|
||||
ctClass = pool.getCtClass(parameterClassName);
|
||||
} catch (NotFoundException ignore) {
|
||||
}
|
||||
|
||||
if (null == ctClass) {
|
||||
ctClass = pool.makeClass(parameterClassName);
|
||||
ClassFile classFile = ctClass.getClassFile();
|
||||
classFile.setVersionToJava5();
|
||||
ctClass.addConstructor(CtNewConstructor.defaultConstructor(pool.getCtClass(parameterClassName)));
|
||||
// parameter fields
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
Class<?> type = parameterTypes[i];
|
||||
Annotation[] annotations = parameterAnnotations[i];
|
||||
AnnotationsAttribute attribute = new AnnotationsAttribute(classFile.getConstPool(), AnnotationsAttribute.visibleTag);
|
||||
for (Annotation annotation : annotations) {
|
||||
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
|
||||
javassist.bytecode.annotation.Annotation ja = new javassist.bytecode.annotation.Annotation(
|
||||
classFile.getConstPool(), pool.getCtClass(annotation.annotationType().getName()));
|
||||
Method[] members = annotation.annotationType().getMethods();
|
||||
for (Method member : members) {
|
||||
if (Modifier.isPublic(member.getModifiers())
|
||||
&& member.getParameterTypes().length == 0
|
||||
&& member.getDeclaringClass() == annotation.annotationType()) {
|
||||
Object value = member.invoke(annotation);
|
||||
if (null != value) {
|
||||
MemberValue memberValue = createMemberValue(
|
||||
classFile.getConstPool(), pool.get(member.getReturnType().getName()), value);
|
||||
ja.addMemberValue(member.getName(), memberValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
attribute.addAnnotation(ja);
|
||||
}
|
||||
}
|
||||
String fieldName = method.getName() + "Argument" + i;
|
||||
CtField ctField = CtField.make("public " + type.getCanonicalName() + " " + fieldName + ";", pool.getCtClass(parameterClassName));
|
||||
ctField.getFieldInfo().addAttribute(attribute);
|
||||
ctClass.addField(ctField);
|
||||
}
|
||||
return ctClass.toClass(clazz.getClassLoader(), null);
|
||||
} else {
|
||||
return Class.forName(parameterClassName, true, clazz.getClassLoader());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateMethodParameterClassName(Class<?> clazz, Method method) {
|
||||
StringBuilder builder = new StringBuilder().append(clazz.getName())
|
||||
.append("_")
|
||||
.append(toUpperMethodName(method.getName()))
|
||||
.append("Parameter");
|
||||
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
for (Class<?> parameterType : parameterTypes) {
|
||||
builder.append("_").append(parameterType.getName());
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static boolean hasConstraintParameter(Method method) {
|
||||
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
|
||||
if (parameterAnnotations != null && parameterAnnotations.length > 0) {
|
||||
for (Annotation[] annotations : parameterAnnotations) {
|
||||
for (Annotation annotation : annotations) {
|
||||
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String toUpperMethodName(String methodName) {
|
||||
return methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
|
||||
}
|
||||
|
||||
// Copy from javassist.bytecode.annotation.Annotation.createMemberValue(ConstPool, CtClass);
|
||||
private static MemberValue createMemberValue(ConstPool cp, CtClass type, Object value) throws NotFoundException {
|
||||
MemberValue memberValue = javassist.bytecode.annotation.Annotation.createMemberValue(cp, type);
|
||||
if (memberValue instanceof BooleanMemberValue) {
|
||||
((BooleanMemberValue) memberValue).setValue((Boolean) value);
|
||||
} else if (memberValue instanceof ByteMemberValue) {
|
||||
((ByteMemberValue) memberValue).setValue((Byte) value);
|
||||
} else if (memberValue instanceof CharMemberValue) {
|
||||
((CharMemberValue) memberValue).setValue((Character) value);
|
||||
} else if (memberValue instanceof ShortMemberValue) {
|
||||
((ShortMemberValue) memberValue).setValue((Short) value);
|
||||
} else if (memberValue instanceof IntegerMemberValue) {
|
||||
((IntegerMemberValue) memberValue).setValue((Integer) value);
|
||||
} else if (memberValue instanceof LongMemberValue) {
|
||||
((LongMemberValue) memberValue).setValue((Long) value);
|
||||
} else if (memberValue instanceof FloatMemberValue) {
|
||||
((FloatMemberValue) memberValue).setValue((Float) value);
|
||||
} else if (memberValue instanceof DoubleMemberValue) {
|
||||
((DoubleMemberValue) memberValue).setValue((Double) value);
|
||||
} else if (memberValue instanceof ClassMemberValue) {
|
||||
((ClassMemberValue) memberValue).setValue(((Class<?>) value).getName());
|
||||
} else if (memberValue instanceof StringMemberValue) {
|
||||
((StringMemberValue) memberValue).setValue((String) value);
|
||||
} else if (memberValue instanceof EnumMemberValue) {
|
||||
((EnumMemberValue) memberValue).setValue(((Enum<?>) value).name());
|
||||
}
|
||||
/* else if (memberValue instanceof AnnotationMemberValue) */
|
||||
else if (memberValue instanceof ArrayMemberValue) {
|
||||
CtClass arrayType = type.getComponentType();
|
||||
int len = Array.getLength(value);
|
||||
MemberValue[] members = new MemberValue[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
members[i] = createMemberValue(cp, arrayType, Array.get(value, i));
|
||||
}
|
||||
((ArrayMemberValue) memberValue).setValue(members);
|
||||
}
|
||||
return memberValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Exception {
|
||||
List<Class<?>> groups = new ArrayList<>();
|
||||
Class<?> methodClass = methodClass(methodName);
|
||||
if (methodClass != null) {
|
||||
groups.add(methodClass);
|
||||
}
|
||||
Set<ConstraintViolation<?>> violations = new HashSet<>();
|
||||
Method method = clazz.getMethod(methodName, parameterTypes);
|
||||
Class<?>[] methodClasses;
|
||||
if (method.isAnnotationPresent(MethodValidated.class)){
|
||||
methodClasses = method.getAnnotation(MethodValidated.class).value();
|
||||
groups.addAll(Arrays.asList(methodClasses));
|
||||
}
|
||||
// add into default group
|
||||
groups.add(0, Default.class);
|
||||
groups.add(1, clazz);
|
||||
|
||||
// convert list to array
|
||||
Class<?>[] classgroups = groups.toArray(new Class[groups.size()]);
|
||||
|
||||
Object parameterBean = getMethodParameterBean(clazz, method, arguments);
|
||||
if (parameterBean != null) {
|
||||
violations.addAll(validator.validate(parameterBean, classgroups ));
|
||||
}
|
||||
|
||||
for (Object arg : arguments) {
|
||||
validate(violations, arg, classgroups);
|
||||
}
|
||||
|
||||
if (!violations.isEmpty()) {
|
||||
logger.error("Failed to validate service: " + clazz.getName() + ", method: " + methodName + ", cause: " + violations);
|
||||
throw new ConstraintViolationException("Failed to validate service: " + clazz.getName() + ", method: " + methodName + ", cause: " + violations, violations);
|
||||
}
|
||||
}
|
||||
|
||||
private Class methodClass(String methodName) {
|
||||
Class<?> methodClass = null;
|
||||
String methodClassName = clazz.getName() + "$" + toUpperMethodName(methodName);
|
||||
Class cached = methodClassMap.get(methodClassName);
|
||||
if (cached != null) {
|
||||
return cached == clazz ? null : cached;
|
||||
}
|
||||
try {
|
||||
methodClass = Class.forName(methodClassName, false, Thread.currentThread().getContextClassLoader());
|
||||
methodClassMap.put(methodClassName, methodClass);
|
||||
} catch (ClassNotFoundException e) {
|
||||
methodClassMap.put(methodClassName, clazz);
|
||||
}
|
||||
return methodClass;
|
||||
}
|
||||
|
||||
private void validate(Set<ConstraintViolation<?>> violations, Object arg, Class<?>... groups) {
|
||||
if (arg != null && !ReflectUtils.isPrimitives(arg.getClass())) {
|
||||
if (arg instanceof Object[]) {
|
||||
for (Object item : (Object[]) arg) {
|
||||
validate(violations, item, groups);
|
||||
}
|
||||
} else if (arg instanceof Collection) {
|
||||
for (Object item : (Collection<?>) arg) {
|
||||
validate(violations, item, groups);
|
||||
}
|
||||
} else if (arg instanceof Map) {
|
||||
for (Map.Entry<?, ?> entry : ((Map<?, ?>) arg).entrySet()) {
|
||||
validate(violations, entry.getKey(), groups);
|
||||
validate(violations, entry.getValue(), groups);
|
||||
}
|
||||
} else {
|
||||
violations.addAll(validator.validate(arg, groups));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.validation.support.jvalidation;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.bytecode.ClassGenerator;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.utils.ReflectUtils;
|
||||
import org.apache.dubbo.validation.MethodValidated;
|
||||
import org.apache.dubbo.validation.Validator;
|
||||
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtField;
|
||||
import javassist.CtNewConstructor;
|
||||
import javassist.Modifier;
|
||||
import javassist.NotFoundException;
|
||||
import javassist.bytecode.AnnotationsAttribute;
|
||||
import javassist.bytecode.ClassFile;
|
||||
import javassist.bytecode.ConstPool;
|
||||
import javassist.bytecode.annotation.ArrayMemberValue;
|
||||
import javassist.bytecode.annotation.BooleanMemberValue;
|
||||
import javassist.bytecode.annotation.ByteMemberValue;
|
||||
import javassist.bytecode.annotation.CharMemberValue;
|
||||
import javassist.bytecode.annotation.ClassMemberValue;
|
||||
import javassist.bytecode.annotation.DoubleMemberValue;
|
||||
import javassist.bytecode.annotation.EnumMemberValue;
|
||||
import javassist.bytecode.annotation.FloatMemberValue;
|
||||
import javassist.bytecode.annotation.IntegerMemberValue;
|
||||
import javassist.bytecode.annotation.LongMemberValue;
|
||||
import javassist.bytecode.annotation.MemberValue;
|
||||
import javassist.bytecode.annotation.ShortMemberValue;
|
||||
import javassist.bytecode.annotation.StringMemberValue;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.ValidatorFactory;
|
||||
import javax.validation.groups.Default;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Implementation of JValidation. JValidation is invoked if configuration validation attribute value is 'jvalidation'.
|
||||
* <pre>
|
||||
* e.g. <dubbo:method name="save" validation="jvalidation" />
|
||||
* </pre>
|
||||
*/
|
||||
public class JValidator implements Validator {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JValidator.class);
|
||||
|
||||
private final Class<?> clazz;
|
||||
|
||||
private final Map<String, Class> methodClassMap;
|
||||
|
||||
private final javax.validation.Validator validator;
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public JValidator(URL url) {
|
||||
this.clazz = ReflectUtils.forName(url.getServiceInterface());
|
||||
String jvalidation = url.getParameter("jvalidation");
|
||||
ValidatorFactory factory;
|
||||
if (jvalidation != null && jvalidation.length() > 0) {
|
||||
factory = Validation.byProvider((Class) ReflectUtils.forName(jvalidation)).configure().buildValidatorFactory();
|
||||
} else {
|
||||
factory = Validation.buildDefaultValidatorFactory();
|
||||
}
|
||||
this.validator = factory.getValidator();
|
||||
this.methodClassMap = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
private static Object getMethodParameterBean(Class<?> clazz, Method method, Object[] args) {
|
||||
if (!hasConstraintParameter(method)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
String parameterClassName = generateMethodParameterClassName(clazz, method);
|
||||
Class<?> parameterClass;
|
||||
try {
|
||||
parameterClass = Class.forName(parameterClassName, true, clazz.getClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
parameterClass = generateMethodParameterClass(clazz, method, parameterClassName);
|
||||
}
|
||||
Object parameterBean = parameterClass.newInstance();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
Field field = parameterClass.getField(method.getName() + "Argument" + i);
|
||||
field.set(parameterBean, args[i]);
|
||||
}
|
||||
return parameterBean;
|
||||
} catch (Throwable e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* try to generate methodParameterClass.
|
||||
*
|
||||
* @param clazz interface class
|
||||
* @param method invoke method
|
||||
* @param parameterClassName generated parameterClassName
|
||||
* @return Class<?> generated methodParameterClass
|
||||
* @throws Exception
|
||||
*/
|
||||
private static Class<?> generateMethodParameterClass(Class<?> clazz, Method method, String parameterClassName)
|
||||
throws Exception {
|
||||
ClassPool pool = ClassGenerator.getClassPool(clazz.getClassLoader());
|
||||
synchronized (parameterClassName.intern()) {
|
||||
CtClass ctClass = null;
|
||||
try {
|
||||
ctClass = pool.getCtClass(parameterClassName);
|
||||
} catch (NotFoundException ignore) {
|
||||
}
|
||||
|
||||
if (null == ctClass) {
|
||||
ctClass = pool.makeClass(parameterClassName);
|
||||
ClassFile classFile = ctClass.getClassFile();
|
||||
classFile.setVersionToJava5();
|
||||
ctClass.addConstructor(CtNewConstructor.defaultConstructor(pool.getCtClass(parameterClassName)));
|
||||
// parameter fields
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
Class<?> type = parameterTypes[i];
|
||||
Annotation[] annotations = parameterAnnotations[i];
|
||||
AnnotationsAttribute attribute = new AnnotationsAttribute(classFile.getConstPool(), AnnotationsAttribute.visibleTag);
|
||||
for (Annotation annotation : annotations) {
|
||||
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
|
||||
javassist.bytecode.annotation.Annotation ja = new javassist.bytecode.annotation.Annotation(
|
||||
classFile.getConstPool(), pool.getCtClass(annotation.annotationType().getName()));
|
||||
Method[] members = annotation.annotationType().getMethods();
|
||||
for (Method member : members) {
|
||||
if (Modifier.isPublic(member.getModifiers())
|
||||
&& member.getParameterTypes().length == 0
|
||||
&& member.getDeclaringClass() == annotation.annotationType()) {
|
||||
Object value = member.invoke(annotation);
|
||||
if (null != value) {
|
||||
MemberValue memberValue = createMemberValue(
|
||||
classFile.getConstPool(), pool.get(member.getReturnType().getName()), value);
|
||||
ja.addMemberValue(member.getName(), memberValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
attribute.addAnnotation(ja);
|
||||
}
|
||||
}
|
||||
String fieldName = method.getName() + "Argument" + i;
|
||||
CtField ctField = CtField.make("public " + type.getCanonicalName() + " " + fieldName + ";", pool.getCtClass(parameterClassName));
|
||||
ctField.getFieldInfo().addAttribute(attribute);
|
||||
ctClass.addField(ctField);
|
||||
}
|
||||
return ctClass.toClass(clazz.getClassLoader(), null);
|
||||
} else {
|
||||
return Class.forName(parameterClassName, true, clazz.getClassLoader());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateMethodParameterClassName(Class<?> clazz, Method method) {
|
||||
StringBuilder builder = new StringBuilder().append(clazz.getName())
|
||||
.append("_")
|
||||
.append(toUpperMethoName(method.getName()))
|
||||
.append("Parameter");
|
||||
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
for (Class<?> parameterType : parameterTypes) {
|
||||
builder.append("_").append(parameterType.getName());
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static boolean hasConstraintParameter(Method method) {
|
||||
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
|
||||
if (parameterAnnotations != null && parameterAnnotations.length > 0) {
|
||||
for (Annotation[] annotations : parameterAnnotations) {
|
||||
for (Annotation annotation : annotations) {
|
||||
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String toUpperMethoName(String methodName) {
|
||||
return methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
|
||||
}
|
||||
|
||||
// Copy from javassist.bytecode.annotation.Annotation.createMemberValue(ConstPool, CtClass);
|
||||
private static MemberValue createMemberValue(ConstPool cp, CtClass type, Object value) throws NotFoundException {
|
||||
MemberValue memberValue = javassist.bytecode.annotation.Annotation.createMemberValue(cp, type);
|
||||
if (memberValue instanceof BooleanMemberValue) {
|
||||
((BooleanMemberValue) memberValue).setValue((Boolean) value);
|
||||
} else if (memberValue instanceof ByteMemberValue) {
|
||||
((ByteMemberValue) memberValue).setValue((Byte) value);
|
||||
} else if (memberValue instanceof CharMemberValue) {
|
||||
((CharMemberValue) memberValue).setValue((Character) value);
|
||||
} else if (memberValue instanceof ShortMemberValue) {
|
||||
((ShortMemberValue) memberValue).setValue((Short) value);
|
||||
} else if (memberValue instanceof IntegerMemberValue) {
|
||||
((IntegerMemberValue) memberValue).setValue((Integer) value);
|
||||
} else if (memberValue instanceof LongMemberValue) {
|
||||
((LongMemberValue) memberValue).setValue((Long) value);
|
||||
} else if (memberValue instanceof FloatMemberValue) {
|
||||
((FloatMemberValue) memberValue).setValue((Float) value);
|
||||
} else if (memberValue instanceof DoubleMemberValue) {
|
||||
((DoubleMemberValue) memberValue).setValue((Double) value);
|
||||
} else if (memberValue instanceof ClassMemberValue) {
|
||||
((ClassMemberValue) memberValue).setValue(((Class<?>) value).getName());
|
||||
} else if (memberValue instanceof StringMemberValue) {
|
||||
((StringMemberValue) memberValue).setValue((String) value);
|
||||
} else if (memberValue instanceof EnumMemberValue) {
|
||||
((EnumMemberValue) memberValue).setValue(((Enum<?>) value).name());
|
||||
}
|
||||
/* else if (memberValue instanceof AnnotationMemberValue) */
|
||||
else if (memberValue instanceof ArrayMemberValue) {
|
||||
CtClass arrayType = type.getComponentType();
|
||||
int len = Array.getLength(value);
|
||||
MemberValue[] members = new MemberValue[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
members[i] = createMemberValue(cp, arrayType, Array.get(value, i));
|
||||
}
|
||||
((ArrayMemberValue) memberValue).setValue(members);
|
||||
}
|
||||
return memberValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Exception {
|
||||
List<Class<?>> groups = new ArrayList<>();
|
||||
Class<?> methodClass = methodClass(methodName);
|
||||
if (methodClass != null) {
|
||||
groups.add(methodClass);
|
||||
}
|
||||
Set<ConstraintViolation<?>> violations = new HashSet<>();
|
||||
Method method = clazz.getMethod(methodName, parameterTypes);
|
||||
Class<?>[] methodClasses;
|
||||
if (method.isAnnotationPresent(MethodValidated.class)){
|
||||
methodClasses = method.getAnnotation(MethodValidated.class).value();
|
||||
groups.addAll(Arrays.asList(methodClasses));
|
||||
}
|
||||
// add into default group
|
||||
groups.add(0, Default.class);
|
||||
groups.add(1, clazz);
|
||||
|
||||
// convert list to array
|
||||
Class<?>[] classgroups = groups.toArray(new Class[groups.size()]);
|
||||
|
||||
Object parameterBean = getMethodParameterBean(clazz, method, arguments);
|
||||
if (parameterBean != null) {
|
||||
violations.addAll(validator.validate(parameterBean, classgroups ));
|
||||
}
|
||||
|
||||
for (Object arg : arguments) {
|
||||
validate(violations, arg, classgroups);
|
||||
}
|
||||
|
||||
if (!violations.isEmpty()) {
|
||||
logger.error("Failed to validate service: " + clazz.getName() + ", method: " + methodName + ", cause: " + violations);
|
||||
throw new ConstraintViolationException("Failed to validate service: " + clazz.getName() + ", method: " + methodName + ", cause: " + violations, violations);
|
||||
}
|
||||
}
|
||||
|
||||
private Class methodClass(String methodName) {
|
||||
Class<?> methodClass = null;
|
||||
String methodClassName = clazz.getName() + "$" + toUpperMethoName(methodName);
|
||||
Class cached = methodClassMap.get(methodClassName);
|
||||
if (cached != null) {
|
||||
return cached == clazz ? null : cached;
|
||||
}
|
||||
try {
|
||||
methodClass = Class.forName(methodClassName, false, Thread.currentThread().getContextClassLoader());
|
||||
methodClassMap.put(methodClassName, methodClass);
|
||||
} catch (ClassNotFoundException e) {
|
||||
methodClassMap.put(methodClassName, clazz);
|
||||
}
|
||||
return methodClass;
|
||||
}
|
||||
|
||||
private void validate(Set<ConstraintViolation<?>> violations, Object arg, Class<?>... groups) {
|
||||
if (arg != null && !ReflectUtils.isPrimitives(arg.getClass())) {
|
||||
if (arg instanceof Object[]) {
|
||||
for (Object item : (Object[]) arg) {
|
||||
validate(violations, item, groups);
|
||||
}
|
||||
} else if (arg instanceof Collection) {
|
||||
for (Object item : (Collection<?>) arg) {
|
||||
validate(violations, item, groups);
|
||||
}
|
||||
} else if (arg instanceof Map) {
|
||||
for (Map.Entry<?, ?> entry : ((Map<?, ?>) arg).entrySet()) {
|
||||
validate(violations, entry.getKey(), groups);
|
||||
validate(violations, entry.getValue(), groups);
|
||||
}
|
||||
} else {
|
||||
violations.addAll(validator.validate(arg, groups));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metadata</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>dubbo-metadata-report-consul</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metadata-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-configcenter-consul</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ecwid.consul</groupId>
|
||||
<artifactId>consul-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
* 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.metadata.store.consul;
|
||||
|
||||
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.StringUtils;
|
||||
import org.apache.dubbo.metadata.report.identifier.BaseMetadataIdentifier;
|
||||
import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum;
|
||||
import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;
|
||||
import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;
|
||||
import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;
|
||||
import org.apache.dubbo.metadata.report.support.AbstractMetadataReport;
|
||||
import org.apache.dubbo.metadata.report.support.ConfigCenterBasedMetadataReport;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.Response;
|
||||
import com.ecwid.consul.v1.kv.model.GetValue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* metadata report impl for consul
|
||||
*
|
||||
* @deprecated 2.7.8 This class will be removed in the future, {@link ConfigCenterBasedMetadataReport} as a substitute.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ConsulMetadataReport extends AbstractMetadataReport {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ConsulMetadataReport.class);
|
||||
private static final int DEFAULT_PORT = 8500;
|
||||
|
||||
private ConsulClient client;
|
||||
|
||||
public ConsulMetadataReport(URL url) {
|
||||
super(url);
|
||||
|
||||
String host = url.getHost();
|
||||
int port = url.getPort() != 0 ? url.getPort() : DEFAULT_PORT;
|
||||
client = new ConsulClient(host, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStoreProviderMetadata(MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) {
|
||||
this.storeMetadata(providerMetadataIdentifier, serviceDefinitions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStoreConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, String value) {
|
||||
this.storeMetadata(consumerMetadataIdentifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSaveMetadata(ServiceMetadataIdentifier serviceMetadataIdentifier, URL url) {
|
||||
this.storeMetadata(serviceMetadataIdentifier, URL.encode(url.toFullString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRemoveMetadata(ServiceMetadataIdentifier serviceMetadataIdentifier) {
|
||||
this.deleteMetadata(serviceMetadataIdentifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> doGetExportedURLs(ServiceMetadataIdentifier metadataIdentifier) {
|
||||
//todo encode and decode
|
||||
String content = getMetadata(metadataIdentifier);
|
||||
if (StringUtils.isEmpty(content)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return new ArrayList<String>(Arrays.asList(URL.decode(content)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSaveSubscriberData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, String urlListStr) {
|
||||
this.storeMetadata(subscriberMetadataIdentifier, urlListStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doGetSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier) {
|
||||
return getMetadata(subscriberMetadataIdentifier);
|
||||
}
|
||||
|
||||
private void storeMetadata(BaseMetadataIdentifier identifier, String v) {
|
||||
try {
|
||||
client.setKVValue(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), v);
|
||||
} catch (Throwable t) {
|
||||
logger.error("Failed to put " + identifier + " to consul " + v + ", cause: " + t.getMessage(), t);
|
||||
throw new RpcException("Failed to put " + identifier + " to consul " + v + ", cause: " + t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteMetadata(BaseMetadataIdentifier identifier) {
|
||||
try {
|
||||
client.deleteKVValue(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY));
|
||||
} catch (Throwable t) {
|
||||
logger.error("Failed to delete " + identifier + " from consul , cause: " + t.getMessage(), t);
|
||||
throw new RpcException("Failed to delete " + identifier + " from consul , cause: " + t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
|
||||
private String getMetadata(BaseMetadataIdentifier identifier) {
|
||||
try {
|
||||
Response<GetValue> value = client.getKVValue(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY));
|
||||
//FIXME CHECK
|
||||
if (value != null && value.getValue() != null) {
|
||||
//todo check decode value and value diff
|
||||
return value.getValue().getValue();
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable t) {
|
||||
logger.error("Failed to get " + identifier + " from consul , cause: " + t.getMessage(), t);
|
||||
throw new RpcException("Failed to get " + identifier + " from consul , cause: " + t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceDefinition(MetadataIdentifier metadataIdentifier) {
|
||||
return getMetadata(metadataIdentifier);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* 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.metadata.store.consul;
|
||||
|
||||
import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum;
|
||||
import org.apache.dubbo.metadata.report.support.ConfigCenterBasedMetadataReportFactory;
|
||||
|
||||
/**
|
||||
* metadata report factory impl for consul
|
||||
*/
|
||||
public class ConsulMetadataReportFactory extends ConfigCenterBasedMetadataReportFactory {
|
||||
|
||||
public ConsulMetadataReportFactory() {
|
||||
super(KeyTypeEnum.UNIQUE_KEY);
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
consul=org.apache.dubbo.metadata.store.consul.ConsulMetadataReportFactory
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metadata</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>dubbo-metadata-report-etcd</artifactId>
|
||||
|
||||
<properties>
|
||||
<skipIntegrationTests>true</skipIntegrationTests>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metadata-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-etcd3</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.etcd</groupId>
|
||||
<artifactId>jetcd-launcher</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skipTests>${skipIntegrationTests}</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.metadata.store.etcd;
|
||||
|
||||
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.StringUtils;
|
||||
import org.apache.dubbo.metadata.report.identifier.BaseMetadataIdentifier;
|
||||
import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum;
|
||||
import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;
|
||||
import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;
|
||||
import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;
|
||||
import org.apache.dubbo.metadata.report.support.AbstractMetadataReport;
|
||||
import org.apache.dubbo.remoting.etcd.jetcd.JEtcdClient;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;
|
||||
|
||||
/**
|
||||
* Report Metadata to Etcd
|
||||
*/
|
||||
public class EtcdMetadataReport extends AbstractMetadataReport {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(EtcdMetadataReport.class);
|
||||
|
||||
private final String root;
|
||||
|
||||
/**
|
||||
* The etcd client
|
||||
*/
|
||||
private final JEtcdClient etcdClient;
|
||||
|
||||
public EtcdMetadataReport(URL url) {
|
||||
super(url);
|
||||
if (url.isAnyHost()) {
|
||||
throw new IllegalStateException("registry address == null");
|
||||
}
|
||||
String group = url.getParameter(GROUP_KEY, DEFAULT_ROOT);
|
||||
if (!group.startsWith(PATH_SEPARATOR)) {
|
||||
group = PATH_SEPARATOR + group;
|
||||
}
|
||||
this.root = group;
|
||||
etcdClient = new JEtcdClient(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStoreProviderMetadata(MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) {
|
||||
storeMetadata(providerMetadataIdentifier, serviceDefinitions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStoreConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, String value) {
|
||||
storeMetadata(consumerMetadataIdentifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSaveMetadata(ServiceMetadataIdentifier serviceMetadataIdentifier, URL url) {
|
||||
String key = getNodeKey(serviceMetadataIdentifier);
|
||||
if (!etcdClient.put(key, URL.encode(url.toFullString()))) {
|
||||
logger.error("Failed to put " + serviceMetadataIdentifier + " to etcd, value: " + url);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRemoveMetadata(ServiceMetadataIdentifier serviceMetadataIdentifier) {
|
||||
etcdClient.delete(getNodeKey(serviceMetadataIdentifier));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> doGetExportedURLs(ServiceMetadataIdentifier metadataIdentifier) {
|
||||
String content = etcdClient.getKVValue(getNodeKey(metadataIdentifier));
|
||||
if (StringUtils.isEmpty(content)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return new ArrayList<String>(Arrays.asList(URL.decode(content)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSaveSubscriberData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, String urlListStr) {
|
||||
String key = getNodeKey(subscriberMetadataIdentifier);
|
||||
if (!etcdClient.put(key, urlListStr)) {
|
||||
logger.error("Failed to put " + subscriberMetadataIdentifier + " to etcd, value: " + urlListStr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doGetSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier) {
|
||||
return etcdClient.getKVValue(getNodeKey(subscriberMetadataIdentifier));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceDefinition(MetadataIdentifier metadataIdentifier) {
|
||||
return etcdClient.getKVValue(getNodeKey(metadataIdentifier));
|
||||
}
|
||||
|
||||
private void storeMetadata(MetadataIdentifier identifier, String v) {
|
||||
String key = getNodeKey(identifier);
|
||||
if (!etcdClient.put(key, v)) {
|
||||
logger.error("Failed to put " + identifier + " to etcd, value: " + v);
|
||||
}
|
||||
}
|
||||
|
||||
String getNodeKey(BaseMetadataIdentifier identifier) {
|
||||
return toRootDir() + identifier.getUniqueKey(KeyTypeEnum.PATH);
|
||||
}
|
||||
|
||||
String toRootDir() {
|
||||
if (root.equals(PATH_SEPARATOR)) {
|
||||
return root;
|
||||
}
|
||||
return root + PATH_SEPARATOR;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.metadata.store.etcd;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.metadata.report.MetadataReport;
|
||||
import org.apache.dubbo.metadata.report.support.AbstractMetadataReportFactory;
|
||||
|
||||
/**
|
||||
* MetadataReportFactory to create an Etcd based {@link MetadataReport}.
|
||||
*/
|
||||
public class EtcdMetadataReportFactory extends AbstractMetadataReportFactory {
|
||||
|
||||
@Override
|
||||
public MetadataReport createMetadataReport(URL url) {
|
||||
return new EtcdMetadataReport(url);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
etcd=org.apache.dubbo.metadata.store.etcd.EtcdMetadataReportFactory
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* 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.metadata.store.etcd;
|
||||
|
||||
/**
|
||||
* Test interface for Etcd metadata report
|
||||
*/
|
||||
public interface EtcdMetadata4TstService {
|
||||
|
||||
int getCounter();
|
||||
|
||||
void printResult(String var);
|
||||
}
|
||||
|
|
@ -1,259 +0,0 @@
|
|||
/*
|
||||
* 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.metadata.store.etcd;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder;
|
||||
import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
|
||||
import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;
|
||||
import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;
|
||||
import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import io.etcd.jetcd.ByteSequence;
|
||||
import io.etcd.jetcd.Client;
|
||||
import io.etcd.jetcd.kv.GetResponse;
|
||||
import io.etcd.jetcd.launcher.EtcdCluster;
|
||||
import io.etcd.jetcd.launcher.EtcdClusterFactory;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
|
||||
|
||||
/**
|
||||
* Unit test for etcd metadata report
|
||||
*/
|
||||
public class EtcdMetadataReportTest {
|
||||
|
||||
private static final String TEST_SERVICE = "org.apache.dubbo.metadata.store.etcd.EtcdMetadata4TstService";
|
||||
|
||||
private EtcdCluster etcdCluster = EtcdClusterFactory.buildCluster(getClass().getSimpleName(), 1, false, false);
|
||||
private Client etcdClientForTest;
|
||||
private EtcdMetadataReport etcdMetadataReport;
|
||||
private URL registryUrl;
|
||||
private EtcdMetadataReportFactory etcdMetadataReportFactory;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
etcdCluster.start();
|
||||
etcdClientForTest = Client.builder().endpoints(etcdCluster.getClientEndpoints()).build();
|
||||
List<URI> clientEndPoints = etcdCluster.getClientEndpoints();
|
||||
this.registryUrl = URL.valueOf("etcd://" + clientEndPoints.get(0).getHost() + ":" + clientEndPoints.get(0).getPort());
|
||||
etcdMetadataReportFactory = new EtcdMetadataReportFactory();
|
||||
this.etcdMetadataReport = (EtcdMetadataReport) etcdMetadataReportFactory.createMetadataReport(registryUrl);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() throws Exception {
|
||||
etcdCluster.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoreProvider() throws Exception {
|
||||
String version = "1.0.0";
|
||||
String group = null;
|
||||
String application = "etcd-metdata-report-test";
|
||||
|
||||
String r = etcdMetadataReport.getServiceDefinition(new MetadataIdentifier(TEST_SERVICE, version, group, "provider", application));
|
||||
Assertions.assertNull(r);
|
||||
MetadataIdentifier providerIdentifier =
|
||||
storeProvider(etcdMetadataReport, TEST_SERVICE, version, group, application);
|
||||
|
||||
CompletableFuture<GetResponse> response = etcdClientForTest.getKVClient().get(ByteSequence.from(
|
||||
etcdMetadataReport.getNodeKey(providerIdentifier), StandardCharsets.UTF_8));
|
||||
String fileContent = response.get().getKvs().get(0).getValue().toString(StandardCharsets.UTF_8);
|
||||
Assertions.assertNotNull(fileContent);
|
||||
|
||||
Gson gson = new Gson();
|
||||
FullServiceDefinition fullServiceDefinition = gson.fromJson(fileContent, FullServiceDefinition.class);
|
||||
Assertions.assertEquals(fullServiceDefinition.getParameters().get("paramTest"), "etcdTest");
|
||||
|
||||
r = etcdMetadataReport.getServiceDefinition(new MetadataIdentifier(TEST_SERVICE, version, group, "provider", application));
|
||||
Assertions.assertNotNull(r);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoreConsumer() throws Exception {
|
||||
String version = "1.0.0";
|
||||
String group = null;
|
||||
String application = "etc-metadata-report-consumer-test";
|
||||
MetadataIdentifier consumerIdentifier = storeConsumer(etcdMetadataReport, TEST_SERVICE, version, group, application);
|
||||
|
||||
CompletableFuture<GetResponse> response = etcdClientForTest.getKVClient().get(ByteSequence.from(
|
||||
etcdMetadataReport.getNodeKey(consumerIdentifier), StandardCharsets.UTF_8));
|
||||
String fileContent = response.get().getKvs().get(0).getValue().toString(StandardCharsets.UTF_8);
|
||||
Assertions.assertNotNull(fileContent);
|
||||
Assertions.assertEquals(fileContent, "{\"paramConsumerTest\":\"etcdConsumer\"}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoSaveMetadata() throws ExecutionException, InterruptedException {
|
||||
String version = "1.0.0";
|
||||
String group = null;
|
||||
String application = "etc-metadata-report-consumer-test";
|
||||
String revision = "90980";
|
||||
String protocol = "xxx";
|
||||
URL url = generateURL(TEST_SERVICE, version, group, application);
|
||||
ServiceMetadataIdentifier serviceMetadataIdentifier = new ServiceMetadataIdentifier(TEST_SERVICE, version,
|
||||
group, "provider", revision, protocol);
|
||||
etcdMetadataReport.doSaveMetadata(serviceMetadataIdentifier, url);
|
||||
|
||||
CompletableFuture<GetResponse> response = etcdClientForTest.getKVClient().get(ByteSequence.from(
|
||||
etcdMetadataReport.getNodeKey(serviceMetadataIdentifier), StandardCharsets.UTF_8));
|
||||
String fileContent = response.get().getKvs().get(0).getValue().toString(StandardCharsets.UTF_8);
|
||||
Assertions.assertNotNull(fileContent);
|
||||
|
||||
Assertions.assertEquals(fileContent, URL.encode(url.toFullString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoRemoveMetadata() throws ExecutionException, InterruptedException {
|
||||
String version = "1.0.0";
|
||||
String group = null;
|
||||
String application = "etc-metadata-report-consumer-test";
|
||||
String revision = "90980";
|
||||
String protocol = "xxx";
|
||||
URL url = generateURL(TEST_SERVICE, version, group, application);
|
||||
ServiceMetadataIdentifier serviceMetadataIdentifier = new ServiceMetadataIdentifier(TEST_SERVICE, version,
|
||||
group, "provider", revision, protocol);
|
||||
etcdMetadataReport.doSaveMetadata(serviceMetadataIdentifier, url);
|
||||
CompletableFuture<GetResponse> response = etcdClientForTest.getKVClient().get(ByteSequence.from(
|
||||
etcdMetadataReport.getNodeKey(serviceMetadataIdentifier), StandardCharsets.UTF_8));
|
||||
String fileContent = response.get().getKvs().get(0).getValue().toString(StandardCharsets.UTF_8);
|
||||
Assertions.assertNotNull(fileContent);
|
||||
|
||||
|
||||
etcdMetadataReport.doRemoveMetadata(serviceMetadataIdentifier);
|
||||
|
||||
response = etcdClientForTest.getKVClient().get(ByteSequence.from(
|
||||
etcdMetadataReport.getNodeKey(serviceMetadataIdentifier), StandardCharsets.UTF_8));
|
||||
Assertions.assertTrue(response.get().getKvs().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoGetExportedURLs() throws ExecutionException, InterruptedException {
|
||||
String version = "1.0.0";
|
||||
String group = null;
|
||||
String application = "etc-metadata-report-consumer-test";
|
||||
String revision = "90980";
|
||||
String protocol = "xxx";
|
||||
URL url = generateURL(TEST_SERVICE, version, group, application);
|
||||
ServiceMetadataIdentifier serviceMetadataIdentifier = new ServiceMetadataIdentifier(TEST_SERVICE, version,
|
||||
group, "provider", revision, protocol);
|
||||
etcdMetadataReport.doSaveMetadata(serviceMetadataIdentifier, url);
|
||||
|
||||
List<String> r = etcdMetadataReport.doGetExportedURLs(serviceMetadataIdentifier);
|
||||
Assertions.assertTrue(r.size() == 1);
|
||||
|
||||
String fileContent = r.get(0);
|
||||
Assertions.assertNotNull(fileContent);
|
||||
|
||||
Assertions.assertEquals(fileContent, url.toFullString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoSaveSubscriberData() throws ExecutionException, InterruptedException {
|
||||
String version = "1.0.0";
|
||||
String group = null;
|
||||
String application = "etc-metadata-report-consumer-test";
|
||||
String revision = "90980";
|
||||
String protocol = "xxx";
|
||||
URL url = generateURL(TEST_SERVICE, version, group, application);
|
||||
SubscriberMetadataIdentifier subscriberMetadataIdentifier = new SubscriberMetadataIdentifier(application, revision);
|
||||
Gson gson = new Gson();
|
||||
String r = gson.toJson(Arrays.asList(url));
|
||||
etcdMetadataReport.doSaveSubscriberData(subscriberMetadataIdentifier, r);
|
||||
|
||||
CompletableFuture<GetResponse> response = etcdClientForTest.getKVClient().get(ByteSequence.from(
|
||||
etcdMetadataReport.getNodeKey(subscriberMetadataIdentifier), StandardCharsets.UTF_8));
|
||||
String fileContent = response.get().getKvs().get(0).getValue().toString(StandardCharsets.UTF_8);
|
||||
Assertions.assertNotNull(fileContent);
|
||||
|
||||
Assertions.assertEquals(fileContent, r);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoGetSubscribedURLs() throws ExecutionException, InterruptedException {
|
||||
String version = "1.0.0";
|
||||
String group = null;
|
||||
String application = "etc-metadata-report-consumer-test";
|
||||
String revision = "90980";
|
||||
String protocol = "xxx";
|
||||
URL url = generateURL(TEST_SERVICE, version, group, application);
|
||||
SubscriberMetadataIdentifier subscriberMetadataIdentifier = new SubscriberMetadataIdentifier(application, revision);
|
||||
Gson gson = new Gson();
|
||||
String r = gson.toJson(Arrays.asList(url));
|
||||
etcdMetadataReport.doSaveSubscriberData(subscriberMetadataIdentifier, r);
|
||||
|
||||
CompletableFuture<GetResponse> response = etcdClientForTest.getKVClient().get(ByteSequence.from(
|
||||
etcdMetadataReport.getNodeKey(subscriberMetadataIdentifier), StandardCharsets.UTF_8));
|
||||
String fileContent = etcdMetadataReport.doGetSubscribedURLs(subscriberMetadataIdentifier);
|
||||
Assertions.assertNotNull(fileContent);
|
||||
|
||||
Assertions.assertEquals(fileContent, r);
|
||||
}
|
||||
|
||||
private MetadataIdentifier storeProvider(EtcdMetadataReport etcdMetadataReport, String interfaceName, String version,
|
||||
String group, String application)
|
||||
throws ClassNotFoundException, InterruptedException {
|
||||
URL url = URL.valueOf("xxx://" + NetUtils.getLocalAddress().getHostName() + ":4444/" + interfaceName +
|
||||
"?paramTest=etcdTest&version=" + version + "&application="
|
||||
+ application + (group == null ? "" : "&group=" + group));
|
||||
|
||||
MetadataIdentifier providerMetadataIdentifier =
|
||||
new MetadataIdentifier(interfaceName, version, group, PROVIDER_SIDE, application);
|
||||
Class interfaceClass = Class.forName(interfaceName);
|
||||
FullServiceDefinition fullServiceDefinition =
|
||||
ServiceDefinitionBuilder.buildFullDefinition(interfaceClass, url.getParameters());
|
||||
|
||||
etcdMetadataReport.storeProviderMetadata(providerMetadataIdentifier, fullServiceDefinition);
|
||||
Thread.sleep(1000);
|
||||
return providerMetadataIdentifier;
|
||||
}
|
||||
|
||||
private URL generateURL(String interfaceName, String version, String group, String application) {
|
||||
URL url = URL.valueOf("xxx://" + NetUtils.getLocalAddress().getHostName() + ":8989/" + interfaceName +
|
||||
"?paramTest=etcdTest&version=" + version + "&application="
|
||||
+ application + (group == null ? "" : "&group=" + group));
|
||||
return url;
|
||||
}
|
||||
|
||||
private MetadataIdentifier storeConsumer(EtcdMetadataReport etcdMetadataReport, String interfaceName,
|
||||
String version, String group, String application) throws InterruptedException {
|
||||
|
||||
MetadataIdentifier consumerIdentifier = new MetadataIdentifier(interfaceName, version, group, CONSUMER_SIDE, application);
|
||||
Map<String, String> tmp = new HashMap<>();
|
||||
tmp.put("paramConsumerTest", "etcdConsumer");
|
||||
etcdMetadataReport.storeConsumerMetadata(consumerIdentifier, tmp);
|
||||
Thread.sleep(1000);
|
||||
return consumerIdentifier;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metadata</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>dubbo-metadata-report-nacos</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metadata-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-configcenter-nacos</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
* 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.metadata.store.nacos;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.metadata.report.identifier.BaseMetadataIdentifier;
|
||||
import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum;
|
||||
import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;
|
||||
import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;
|
||||
import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;
|
||||
import org.apache.dubbo.metadata.report.support.AbstractMetadataReport;
|
||||
import org.apache.dubbo.metadata.report.support.ConfigCenterBasedMetadataReport;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
/**
|
||||
* metadata report impl for nacos
|
||||
*
|
||||
* @deprecated 2.7.8 This class will be removed in the future, {@link ConfigCenterBasedMetadataReport} as a substitute.
|
||||
*/
|
||||
@Deprecated
|
||||
public class NacosMetadataReport extends AbstractMetadataReport {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(NacosMetadataReport.class);
|
||||
|
||||
private final DynamicConfiguration dynamicConfiguration;
|
||||
|
||||
/**
|
||||
* The group used to store metadata in Nacos
|
||||
*/
|
||||
private String group;
|
||||
|
||||
public NacosMetadataReport(URL url, DynamicConfiguration dynamicConfiguration) {
|
||||
super(url);
|
||||
this.dynamicConfiguration = dynamicConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStoreProviderMetadata(MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) {
|
||||
this.storeMetadata(providerMetadataIdentifier, serviceDefinitions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStoreConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, String value) {
|
||||
this.storeMetadata(consumerMetadataIdentifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSaveMetadata(ServiceMetadataIdentifier serviceMetadataIdentifier, URL url) {
|
||||
storeMetadata(serviceMetadataIdentifier, URL.encode(url.toFullString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRemoveMetadata(ServiceMetadataIdentifier serviceMetadataIdentifier) {
|
||||
deleteMetadata(serviceMetadataIdentifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> doGetExportedURLs(ServiceMetadataIdentifier metadataIdentifier) {
|
||||
String content = getConfig(metadataIdentifier);
|
||||
if (StringUtils.isEmpty(content)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return new ArrayList<String>(Arrays.asList(URL.decode(content)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSaveSubscriberData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, String urlListStr) {
|
||||
storeMetadata(subscriberMetadataIdentifier, urlListStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doGetSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier) {
|
||||
return getConfig(subscriberMetadataIdentifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceDefinition(MetadataIdentifier metadataIdentifier) {
|
||||
return getConfig(metadataIdentifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveExportedURLs(String serviceName, String exportedServicesRevision, String exportedURLsContent) {
|
||||
return dynamicConfiguration.publishConfig(serviceName, exportedServicesRevision, exportedURLsContent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportedURLsContent(String serviceName, String exportedServicesRevision) {
|
||||
return dynamicConfiguration.getConfig(serviceName, exportedServicesRevision, SECONDS.toMillis(3));
|
||||
}
|
||||
|
||||
private void storeMetadata(BaseMetadataIdentifier identifier, String value) {
|
||||
try {
|
||||
boolean publishResult = dynamicConfiguration.publishConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), group, value);
|
||||
if (!publishResult) {
|
||||
throw new RuntimeException("publish nacos metadata failed");
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.error("Failed to put " + identifier + " to nacos " + value + ", cause: " + t.getMessage(), t);
|
||||
throw new RpcException("Failed to put " + identifier + " to nacos " + value + ", cause: " + t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteMetadata(BaseMetadataIdentifier identifier) {
|
||||
try {
|
||||
boolean publishResult = dynamicConfiguration.removeConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), group);
|
||||
if (!publishResult) {
|
||||
throw new RuntimeException("remove nacos metadata failed");
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.error("Failed to remove " + identifier + " from nacos , cause: " + t.getMessage(), t);
|
||||
throw new RpcException("Failed to remove " + identifier + " from nacos , cause: " + t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
|
||||
private String getConfig(BaseMetadataIdentifier identifier) {
|
||||
try {
|
||||
return dynamicConfiguration.getConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), group, 300);
|
||||
} catch (Throwable t) {
|
||||
logger.error("Failed to get " + identifier + " from nacos , cause: " + t.getMessage(), t);
|
||||
throw new RpcException("Failed to get " + identifier + " from nacos , cause: " + t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* 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.metadata.store.nacos;
|
||||
|
||||
import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum;
|
||||
import org.apache.dubbo.metadata.report.support.ConfigCenterBasedMetadataReportFactory;
|
||||
|
||||
/**
|
||||
* metadata report factory impl for nacos
|
||||
*/
|
||||
public class NacosMetadataReportFactory extends ConfigCenterBasedMetadataReportFactory {
|
||||
|
||||
public NacosMetadataReportFactory() {
|
||||
super(KeyTypeEnum.UNIQUE_KEY);
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
nacos=org.apache.dubbo.metadata.store.nacos.NacosMetadataReportFactory
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* 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.metadata.store.nacos;
|
||||
|
||||
/**
|
||||
* Test interface for Nacos metadata report
|
||||
*/
|
||||
public interface NacosMetadata4TstService {
|
||||
|
||||
int getCounter();
|
||||
|
||||
void printResult(String var);
|
||||
}
|
||||
|
|
@ -18,8 +18,7 @@
|
|||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metadata</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
<version>2.7.7-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
|||
|
|
@ -29,13 +29,10 @@
|
|||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>dubbo-metadata-api</module>
|
||||
<!-- <module>dubbo-metadata-definition-protobuf</module>-->
|
||||
<module>dubbo-metadata-definition-protobuf</module>
|
||||
<module>dubbo-metadata-processor</module>
|
||||
<module>dubbo-metadata-report-zookeeper</module>
|
||||
<!-- <module>dubbo-metadata-report-redis</module>-->
|
||||
<!-- <module>dubbo-metadata-report-consul</module>-->
|
||||
<!-- <module>dubbo-metadata-report-etcd</module>-->
|
||||
<!-- <module>dubbo-metadata-report-nacos</module>-->
|
||||
<!-- <module>dubbo-metadata-processor</module>-->
|
||||
<module>dubbo-metadata-report-redis</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -1,63 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>dubbo-registry</artifactId>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>dubbo-registry-consul</artifactId>
|
||||
|
||||
<properties>
|
||||
<skipIntegrationTests>true</skipIntegrationTests>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ecwid.consul</groupId>
|
||||
<artifactId>consul-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.pszymczyk.consul</groupId>
|
||||
<artifactId>embedded-consul</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skipTests>${skipIntegrationTests}</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* 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.registry.consul;
|
||||
|
||||
/**
|
||||
* @author cvictory ON 2019-08-02
|
||||
*/
|
||||
public class AbstractConsulRegistry {
|
||||
|
||||
static final String SERVICE_TAG = "dubbo";
|
||||
static final String URL_META_KEY = "url";
|
||||
static final String WATCH_TIMEOUT = "consul-watch-timeout";
|
||||
static final String CHECK_PASS_INTERVAL = "consul-check-pass-interval";
|
||||
static final String DEREGISTER_AFTER = "consul-deregister-critical-service-after";
|
||||
|
||||
static final int DEFAULT_PORT = 8500;
|
||||
// default watch timeout in millisecond
|
||||
static final int DEFAULT_WATCH_TIMEOUT = 60 * 1000;
|
||||
// default time-to-live in millisecond
|
||||
static final long DEFAULT_CHECK_PASS_INTERVAL = 16000L;
|
||||
// default deregister critical server after
|
||||
static final String DEFAULT_DEREGISTER_TIME = "20s";
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,380 +0,0 @@
|
|||
/*
|
||||
* 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.registry.consul;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.URLBuilder;
|
||||
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.common.utils.NamedThreadFactory;
|
||||
import org.apache.dubbo.common.utils.UrlUtils;
|
||||
import org.apache.dubbo.registry.NotifyListener;
|
||||
import org.apache.dubbo.registry.support.FailbackRegistry;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.QueryParams;
|
||||
import com.ecwid.consul.v1.Response;
|
||||
import com.ecwid.consul.v1.agent.model.NewService;
|
||||
import com.ecwid.consul.v1.catalog.CatalogServicesRequest;
|
||||
import com.ecwid.consul.v1.health.HealthServicesRequest;
|
||||
import com.ecwid.consul.v1.health.model.HealthService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.concurrent.Executors.newCachedThreadPool;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
|
||||
import static org.apache.dubbo.registry.Constants.CONSUMER_PROTOCOL;
|
||||
import static org.apache.dubbo.registry.Constants.PROVIDER_PROTOCOL;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.CHECK_PASS_INTERVAL;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEFAULT_CHECK_PASS_INTERVAL;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEFAULT_DEREGISTER_TIME;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEFAULT_PORT;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEFAULT_WATCH_TIMEOUT;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEREGISTER_AFTER;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.SERVICE_TAG;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.URL_META_KEY;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.WATCH_TIMEOUT;
|
||||
import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
|
||||
|
||||
/**
|
||||
* registry center implementation for consul
|
||||
*/
|
||||
public class ConsulRegistry extends FailbackRegistry {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ConsulRegistry.class);
|
||||
|
||||
private ConsulClient client;
|
||||
private long checkPassInterval;
|
||||
private ExecutorService notifierExecutor = newCachedThreadPool(
|
||||
new NamedThreadFactory("dubbo-consul-notifier", true));
|
||||
private ConcurrentMap<URL, ConsulNotifier> notifiers = new ConcurrentHashMap<>();
|
||||
private ScheduledExecutorService ttlConsulCheckExecutor;
|
||||
/**
|
||||
* The ACL token
|
||||
*/
|
||||
private String token;
|
||||
|
||||
|
||||
public ConsulRegistry(URL url) {
|
||||
super(url);
|
||||
token = url.getParameter(TOKEN_KEY, (String) null);
|
||||
String host = url.getHost();
|
||||
int port = url.getPort() != 0 ? url.getPort() : DEFAULT_PORT;
|
||||
client = new ConsulClient(host, port);
|
||||
checkPassInterval = url.getParameter(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL);
|
||||
ttlConsulCheckExecutor = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("Ttl-Consul-Check-Executor", true));
|
||||
ttlConsulCheckExecutor.scheduleAtFixedRate(this::checkPass, checkPassInterval / 8,
|
||||
checkPassInterval / 8, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(URL url) {
|
||||
if (isConsumerSide(url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.register(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRegister(URL url) {
|
||||
if (token == null) {
|
||||
client.agentServiceRegister(buildService(url));
|
||||
} else {
|
||||
client.agentServiceRegister(buildService(url), token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(URL url) {
|
||||
if (isConsumerSide(url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.unregister(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doUnregister(URL url) {
|
||||
if (token == null) {
|
||||
client.agentServiceDeregister(buildId(url));
|
||||
} else {
|
||||
client.agentServiceDeregister(buildId(url), token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(URL url, NotifyListener listener) {
|
||||
if (isProviderSide(url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.subscribe(url, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSubscribe(URL url, NotifyListener listener) {
|
||||
Long index;
|
||||
List<URL> urls;
|
||||
if (ANY_VALUE.equals(url.getServiceInterface())) {
|
||||
Response<Map<String, List<String>>> response = getAllServices(-1, buildWatchTimeout(url));
|
||||
index = response.getConsulIndex();
|
||||
List<HealthService> services = getHealthServices(response.getValue());
|
||||
urls = convert(services, url);
|
||||
} else {
|
||||
String service = url.getServiceInterface();
|
||||
Response<List<HealthService>> response = getHealthServices(service, -1, buildWatchTimeout(url));
|
||||
index = response.getConsulIndex();
|
||||
urls = convert(response.getValue(), url);
|
||||
}
|
||||
|
||||
notify(url, listener, urls);
|
||||
ConsulNotifier notifier = notifiers.computeIfAbsent(url, k -> new ConsulNotifier(url, index));
|
||||
notifierExecutor.submit(notifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribe(URL url, NotifyListener listener) {
|
||||
if (isProviderSide(url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.unsubscribe(url, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doUnsubscribe(URL url, NotifyListener listener) {
|
||||
ConsulNotifier notifier = notifiers.remove(url);
|
||||
notifier.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<URL> lookup(URL url) {
|
||||
if (url == null) {
|
||||
throw new IllegalArgumentException("lookup url == null");
|
||||
}
|
||||
try {
|
||||
String service = url.getServiceKey();
|
||||
Response<List<HealthService>> result = getHealthServices(service, -1, buildWatchTimeout(url));
|
||||
if (result == null || result.getValue() == null || result.getValue().isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
} else {
|
||||
return convert(result.getValue(), url);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new RpcException("Failed to lookup " + url + " from consul " + getUrl() + ", cause: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return client.getAgentSelf() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
notifierExecutor.shutdown();
|
||||
ttlConsulCheckExecutor.shutdown();
|
||||
}
|
||||
|
||||
private void checkPass() {
|
||||
for (URL url : getRegistered()) {
|
||||
String checkId = buildId(url);
|
||||
try {
|
||||
if (token == null) {
|
||||
client.agentCheckPass("service:" + checkId);
|
||||
} else {
|
||||
client.agentCheckPass("service:" + checkId, null, token);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("check pass for url: " + url + " with check id: " + checkId);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.warn("fail to check pass for url: " + url + ", check id is: " + checkId, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Response<List<HealthService>> getHealthServices(String service, long index, int watchTimeout) {
|
||||
HealthServicesRequest request = HealthServicesRequest.newBuilder()
|
||||
.setTag(SERVICE_TAG)
|
||||
.setQueryParams(new QueryParams(watchTimeout, index))
|
||||
.setPassing(true)
|
||||
.setToken(token)
|
||||
.build();
|
||||
return client.getHealthServices(service, request);
|
||||
}
|
||||
|
||||
private Response<Map<String, List<String>>> getAllServices(long index, int watchTimeout) {
|
||||
CatalogServicesRequest request = CatalogServicesRequest.newBuilder()
|
||||
.setQueryParams(new QueryParams(watchTimeout, index))
|
||||
.setToken(token)
|
||||
.build();
|
||||
return client.getCatalogServices(request);
|
||||
}
|
||||
|
||||
private List<HealthService> getHealthServices(Map<String, List<String>> services) {
|
||||
return services.entrySet().stream()
|
||||
.filter(s -> s.getValue().contains(SERVICE_TAG))
|
||||
.map(s -> getHealthServices(s.getKey(), -1, -1).getValue())
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
private boolean isConsumerSide(URL url) {
|
||||
return url.getProtocol().equals(CONSUMER_PROTOCOL);
|
||||
}
|
||||
|
||||
private boolean isProviderSide(URL url) {
|
||||
return url.getProtocol().equals(PROVIDER_PROTOCOL);
|
||||
}
|
||||
|
||||
private List<URL> convert(List<HealthService> services, URL consumerURL) {
|
||||
if (CollectionUtils.isEmpty(services)) {
|
||||
return emptyURL(consumerURL);
|
||||
}
|
||||
return services.stream()
|
||||
.map(HealthService::getService)
|
||||
.filter(Objects::nonNull)
|
||||
.map(HealthService.Service::getMeta)
|
||||
.filter(m -> m != null && m.containsKey(URL_META_KEY))
|
||||
.map(m -> m.get(URL_META_KEY))
|
||||
.map(URL::valueOf)
|
||||
.filter(url -> UrlUtils.isMatch(consumerURL, url))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<URL> emptyURL(URL consumerURL) {
|
||||
// No Category Parameter
|
||||
URL empty = URLBuilder.from(consumerURL)
|
||||
.setProtocol(EMPTY_PROTOCOL)
|
||||
.removeParameter(CATEGORY_KEY)
|
||||
.build();
|
||||
List<URL> result = new ArrayList<URL>();
|
||||
result.add(empty);
|
||||
return result;
|
||||
}
|
||||
|
||||
private NewService buildService(URL url) {
|
||||
NewService service = new NewService();
|
||||
service.setAddress(url.getHost());
|
||||
service.setPort(url.getPort());
|
||||
service.setId(buildId(url));
|
||||
service.setName(url.getServiceInterface());
|
||||
service.setCheck(buildCheck(url));
|
||||
service.setTags(buildTags(url));
|
||||
service.setMeta(Collections.singletonMap(URL_META_KEY, url.toFullString()));
|
||||
return service;
|
||||
}
|
||||
|
||||
private List<String> buildTags(URL url) {
|
||||
Map<String, String> params = url.getParameters();
|
||||
List<String> tags = params.entrySet().stream()
|
||||
.map(k -> k.getKey() + "=" + k.getValue())
|
||||
.collect(Collectors.toList());
|
||||
tags.add(SERVICE_TAG);
|
||||
return tags;
|
||||
}
|
||||
|
||||
private String buildId(URL url) {
|
||||
// let's simply use url's hashcode to generate unique service id for now
|
||||
return Integer.toHexString(url.hashCode());
|
||||
}
|
||||
|
||||
private NewService.Check buildCheck(URL url) {
|
||||
NewService.Check check = new NewService.Check();
|
||||
check.setTtl((checkPassInterval / 1000) + "s");
|
||||
check.setDeregisterCriticalServiceAfter(url.getParameter(DEREGISTER_AFTER, DEFAULT_DEREGISTER_TIME));
|
||||
return check;
|
||||
}
|
||||
|
||||
private int buildWatchTimeout(URL url) {
|
||||
return url.getParameter(WATCH_TIMEOUT, DEFAULT_WATCH_TIMEOUT) / 1000;
|
||||
}
|
||||
|
||||
private class ConsulNotifier implements Runnable {
|
||||
private URL url;
|
||||
private long consulIndex;
|
||||
private boolean running;
|
||||
|
||||
ConsulNotifier(URL url, long consulIndex) {
|
||||
this.url = url;
|
||||
this.consulIndex = consulIndex;
|
||||
this.running = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (this.running) {
|
||||
if (ANY_VALUE.equals(url.getServiceInterface())) {
|
||||
processServices();
|
||||
} else {
|
||||
processService();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processService() {
|
||||
String service = url.getServiceKey();
|
||||
Response<List<HealthService>> response = getHealthServices(service, consulIndex, buildWatchTimeout(url));
|
||||
Long currentIndex = response.getConsulIndex();
|
||||
if (currentIndex != null && currentIndex > consulIndex) {
|
||||
consulIndex = currentIndex;
|
||||
List<HealthService> services = response.getValue();
|
||||
List<URL> urls = convert(services, url);
|
||||
for (NotifyListener listener : getSubscribed().get(url)) {
|
||||
doNotify(url, listener, urls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processServices() {
|
||||
Response<Map<String, List<String>>> response = getAllServices(consulIndex, buildWatchTimeout(url));
|
||||
Long currentIndex = response.getConsulIndex();
|
||||
if (currentIndex != null && currentIndex > consulIndex) {
|
||||
consulIndex = currentIndex;
|
||||
List<HealthService> services = getHealthServices(response.getValue());
|
||||
List<URL> urls = convert(services, url);
|
||||
for (NotifyListener listener : getSubscribed().get(url)) {
|
||||
doNotify(url, listener, urls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stop() {
|
||||
this.running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* 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.registry.consul;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.registry.Registry;
|
||||
import org.apache.dubbo.registry.support.AbstractRegistryFactory;
|
||||
|
||||
/**
|
||||
* registry center factory implementation for consul
|
||||
*/
|
||||
public class ConsulRegistryFactory extends AbstractRegistryFactory {
|
||||
@Override
|
||||
protected Registry createRegistry(URL url) {
|
||||
return new ConsulRegistry(url);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,474 +0,0 @@
|
|||
/*
|
||||
* 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.registry.consul;
|
||||
|
||||
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.common.utils.NamedThreadFactory;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.event.EventListener;
|
||||
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.client.event.ServiceInstancesChangedEvent;
|
||||
import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;
|
||||
|
||||
import com.ecwid.consul.v1.ConsistencyMode;
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.QueryParams;
|
||||
import com.ecwid.consul.v1.Response;
|
||||
import com.ecwid.consul.v1.agent.model.NewService;
|
||||
import com.ecwid.consul.v1.catalog.CatalogServicesRequest;
|
||||
import com.ecwid.consul.v1.health.HealthServicesRequest;
|
||||
import com.ecwid.consul.v1.health.model.HealthService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
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.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.concurrent.Executors.newCachedThreadPool;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR_CHAR;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.SEMICOLON_SPLIT_PATTERN;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.CHECK_PASS_INTERVAL;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEFAULT_CHECK_PASS_INTERVAL;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEFAULT_DEREGISTER_TIME;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEFAULT_PORT;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEFAULT_WATCH_TIMEOUT;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEREGISTER_AFTER;
|
||||
import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.WATCH_TIMEOUT;
|
||||
import static org.apache.dubbo.registry.consul.ConsulParameter.ACL_TOKEN;
|
||||
import static org.apache.dubbo.registry.consul.ConsulParameter.CONSISTENCY_MODE;
|
||||
import static org.apache.dubbo.registry.consul.ConsulParameter.DEFAULT_ZONE_METADATA_NAME;
|
||||
import static org.apache.dubbo.registry.consul.ConsulParameter.INSTANCE_GROUP;
|
||||
import static org.apache.dubbo.registry.consul.ConsulParameter.INSTANCE_ZONE;
|
||||
import static org.apache.dubbo.registry.consul.ConsulParameter.TAGS;
|
||||
|
||||
/**
|
||||
* 2019-07-31
|
||||
*/
|
||||
public class ConsulServiceDiscovery implements ServiceDiscovery, EventListener<ServiceInstancesChangedEvent> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ConsulServiceDiscovery.class);
|
||||
|
||||
private static final String QUERY_TAG = "consul_query_tag";
|
||||
private static final String REGISTER_TAG = "consul_register_tag";
|
||||
|
||||
private List<String> registeringTags = new ArrayList<>();
|
||||
private String tag;
|
||||
private ConsulClient client;
|
||||
private ExecutorService notifierExecutor = newCachedThreadPool(
|
||||
new NamedThreadFactory("dubbo-service-discovery-consul-notifier", true));
|
||||
private ConsulNotifier notifier;
|
||||
private TtlScheduler ttlScheduler;
|
||||
private long checkPassInterval;
|
||||
private URL url;
|
||||
|
||||
private String aclToken;
|
||||
|
||||
private List<String> tags;
|
||||
|
||||
private ConsistencyMode consistencyMode;
|
||||
|
||||
private String defaultZoneMetadataName;
|
||||
|
||||
/**
|
||||
* Service instance zone.
|
||||
*/
|
||||
private String instanceZone;
|
||||
|
||||
/**
|
||||
* Service instance group.
|
||||
*/
|
||||
private String instanceGroup;
|
||||
|
||||
|
||||
@Override
|
||||
public void onEvent(ServiceInstancesChangedEvent event) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(URL registryURL) throws Exception {
|
||||
this.url = registryURL;
|
||||
String host = url.getHost();
|
||||
int port = url.getPort() != 0 ? url.getPort() : DEFAULT_PORT;
|
||||
checkPassInterval = url.getParameter(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL);
|
||||
client = new ConsulClient(host, port);
|
||||
ttlScheduler = new TtlScheduler(checkPassInterval, client);
|
||||
this.tag = registryURL.getParameter(QUERY_TAG);
|
||||
this.registeringTags.addAll(getRegisteringTags(url));
|
||||
this.aclToken = ACL_TOKEN.getValue(registryURL);
|
||||
this.tags = getTags(registryURL);
|
||||
this.consistencyMode = getConsistencyMode(registryURL);
|
||||
this.defaultZoneMetadataName = DEFAULT_ZONE_METADATA_NAME.getValue(registryURL);
|
||||
this.instanceZone = INSTANCE_ZONE.getValue(registryURL);
|
||||
this.instanceGroup = INSTANCE_GROUP.getValue(registryURL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ConsistencyMode}
|
||||
*
|
||||
* @param registryURL the {@link URL} of registry
|
||||
* @return non-null, {@link ConsistencyMode#DEFAULT} as default
|
||||
* @sine 2.7.8
|
||||
*/
|
||||
private ConsistencyMode getConsistencyMode(URL registryURL) {
|
||||
String value = CONSISTENCY_MODE.getValue(registryURL);
|
||||
if (StringUtils.isNotEmpty(value)) {
|
||||
return ConsistencyMode.valueOf(value);
|
||||
}
|
||||
return ConsistencyMode.DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "tags" from the {@link URL} of registry
|
||||
*
|
||||
* @param registryURL the {@link URL} of registry
|
||||
* @return non-null
|
||||
* @sine 2.7.8
|
||||
*/
|
||||
private List<String> getTags(URL registryURL) {
|
||||
String value = TAGS.getValue(registryURL);
|
||||
return StringUtils.splitToList(value, COMMA_SEPARATOR_CHAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
private List<String> getRegisteringTags(URL url) {
|
||||
List<String> tags = new ArrayList<>();
|
||||
String rawTag = url.getParameter(REGISTER_TAG);
|
||||
if (StringUtils.isNotEmpty(rawTag)) {
|
||||
tags.addAll(Arrays.asList(SEMICOLON_SPLIT_PATTERN.split(rawTag)));
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (notifier != null) {
|
||||
notifier.stop();
|
||||
}
|
||||
notifier = null;
|
||||
notifierExecutor.shutdownNow();
|
||||
ttlScheduler.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(ServiceInstance serviceInstance) throws RuntimeException {
|
||||
NewService consulService = buildService(serviceInstance);
|
||||
ttlScheduler.add(consulService.getId());
|
||||
client.agentServiceRegister(consulService, aclToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addServiceInstancesChangedListener(ServiceInstancesChangedListener listener) throws NullPointerException, IllegalArgumentException {
|
||||
if (notifier == null) {
|
||||
String serviceName = listener.getServiceNames();
|
||||
Response<List<HealthService>> response = getHealthServices(serviceName, -1, buildWatchTimeout());
|
||||
Long consulIndex = response.getConsulIndex();
|
||||
notifier = new ConsulNotifier(serviceName, consulIndex);
|
||||
}
|
||||
notifierExecutor.execute(notifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(ServiceInstance serviceInstance) throws RuntimeException {
|
||||
// TODO
|
||||
// client.catalogRegister(buildCatalogService(serviceInstance));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(ServiceInstance serviceInstance) throws RuntimeException {
|
||||
String id = buildId(serviceInstance);
|
||||
ttlScheduler.remove(id);
|
||||
client.agentServiceDeregister(id, aclToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getServices() {
|
||||
CatalogServicesRequest request = CatalogServicesRequest.newBuilder()
|
||||
.setQueryParams(QueryParams.DEFAULT)
|
||||
.setToken(aclToken)
|
||||
.build();
|
||||
return this.client.getCatalogServices(request).getValue().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ServiceInstance> getInstances(String serviceName) throws NullPointerException {
|
||||
Response<List<HealthService>> response = getHealthServices(serviceName, -1, buildWatchTimeout());
|
||||
Long consulIndex = response.getConsulIndex();
|
||||
if (notifier == null) {
|
||||
notifier = new ConsulNotifier(serviceName, consulIndex);
|
||||
}
|
||||
return convert(response.getValue());
|
||||
}
|
||||
|
||||
private List<ServiceInstance> convert(List<HealthService> services) {
|
||||
return services.stream()
|
||||
.map(HealthService::getService)
|
||||
.map(service -> {
|
||||
ServiceInstance instance = new DefaultServiceInstance(
|
||||
service.getId(),
|
||||
service.getService(),
|
||||
service.getAddress(),
|
||||
service.getPort());
|
||||
instance.getMetadata().putAll(getMetadata(service));
|
||||
return instance;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Response<List<HealthService>> getHealthServices(String service, long index, int watchTimeout) {
|
||||
HealthServicesRequest request = HealthServicesRequest.newBuilder()
|
||||
.setTag(tag)
|
||||
.setQueryParams(new QueryParams(watchTimeout, index))
|
||||
.setPassing(true)
|
||||
.build();
|
||||
return client.getHealthServices(service, request);
|
||||
}
|
||||
|
||||
private Map<String, String> getMetadata(HealthService.Service service) {
|
||||
Map<String, String> metadata = service.getMeta();
|
||||
metadata = decodeMetadata(metadata);
|
||||
if (CollectionUtils.isEmptyMap(metadata)) {
|
||||
metadata = getScCompatibleMetadata(service.getTags());
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private Map<String, String> getScCompatibleMetadata(List<String> tags) {
|
||||
LinkedHashMap<String, String> metadata = new LinkedHashMap<>();
|
||||
if (tags != null) {
|
||||
for (String tag : tags) {
|
||||
String[] parts = StringUtils.delimitedListToStringArray(tag, "=");
|
||||
switch (parts.length) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
metadata.put(parts[0], parts[0]);
|
||||
break;
|
||||
case 2:
|
||||
metadata.put(parts[0], parts[1]);
|
||||
break;
|
||||
default:
|
||||
String[] end = Arrays.copyOfRange(parts, 1, parts.length);
|
||||
metadata.put(parts[0], StringUtils.arrayToDelimitedString(end, "="));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private NewService buildService(ServiceInstance serviceInstance) {
|
||||
NewService service = new NewService();
|
||||
service.setAddress(serviceInstance.getHost());
|
||||
service.setPort(serviceInstance.getPort());
|
||||
service.setId(buildId(serviceInstance));
|
||||
service.setName(serviceInstance.getServiceName());
|
||||
service.setCheck(buildCheck(serviceInstance));
|
||||
service.setTags(buildTags(serviceInstance));
|
||||
return service;
|
||||
}
|
||||
|
||||
private String buildId(ServiceInstance serviceInstance) {
|
||||
return Integer.toHexString(serviceInstance.hashCode());
|
||||
}
|
||||
|
||||
private List<String> buildTags(ServiceInstance serviceInstance) {
|
||||
List<String> tags = new LinkedList<>(this.tags);
|
||||
|
||||
if (StringUtils.isNotEmpty(instanceZone)) {
|
||||
tags.add(defaultZoneMetadataName + "=" + instanceZone);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(instanceGroup)) {
|
||||
tags.add("group=" + instanceGroup);
|
||||
}
|
||||
|
||||
Map<String, String> params = serviceInstance.getMetadata();
|
||||
params.keySet().stream()
|
||||
.map(k -> k + "=" + params.get(k))
|
||||
.forEach(tags::add);
|
||||
|
||||
tags.addAll(registeringTags);
|
||||
return tags;
|
||||
}
|
||||
|
||||
private Map<String, String> buildMetadata(ServiceInstance serviceInstance) {
|
||||
Map<String, String> metadata = new LinkedHashMap<>();
|
||||
metadata.putAll(getScCompatibleMetadata(registeringTags));
|
||||
if (CollectionUtils.isNotEmptyMap(serviceInstance.getMetadata())) {
|
||||
metadata.putAll(serviceInstance.getMetadata());
|
||||
}
|
||||
metadata = encodeMetadata(metadata);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private Map<String, String> encodeMetadata(Map<String, String> metadata) {
|
||||
if (metadata == null) {
|
||||
return metadata;
|
||||
}
|
||||
Map<String, String> encoded = new HashMap<>(metadata.size());
|
||||
metadata.forEach((k, v) -> encoded.put(Base64.getEncoder().encodeToString(k.getBytes()), v));
|
||||
return encoded;
|
||||
}
|
||||
|
||||
private Map<String, String> decodeMetadata(Map<String, String> metadata) {
|
||||
if (metadata == null) {
|
||||
return metadata;
|
||||
}
|
||||
Map<String, String> decoded = new HashMap<>(metadata.size());
|
||||
metadata.forEach((k, v) -> decoded.put(new String(Base64.getDecoder().decode(k)), v));
|
||||
return decoded;
|
||||
}
|
||||
|
||||
private NewService.Check buildCheck(ServiceInstance serviceInstance) {
|
||||
NewService.Check check = new NewService.Check();
|
||||
check.setTtl((checkPassInterval / 1000) + "s");
|
||||
String deregister = serviceInstance.getMetadata().get(DEREGISTER_AFTER);
|
||||
check.setDeregisterCriticalServiceAfter(deregister == null ? DEFAULT_DEREGISTER_TIME : deregister);
|
||||
return check;
|
||||
}
|
||||
|
||||
private int buildWatchTimeout() {
|
||||
return url.getParameter(WATCH_TIMEOUT, DEFAULT_WATCH_TIMEOUT) / 1000;
|
||||
}
|
||||
|
||||
private class ConsulNotifier implements Runnable {
|
||||
private String serviceName;
|
||||
private long consulIndex;
|
||||
private boolean running;
|
||||
|
||||
ConsulNotifier(String serviceName, long consulIndex) {
|
||||
this.serviceName = serviceName;
|
||||
this.consulIndex = consulIndex;
|
||||
this.running = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (this.running) {
|
||||
processService();
|
||||
}
|
||||
}
|
||||
|
||||
private void processService() {
|
||||
Response<List<HealthService>> response = getHealthServices(serviceName, consulIndex, Integer.MAX_VALUE);
|
||||
Long currentIndex = response.getConsulIndex();
|
||||
if (currentIndex != null && currentIndex > consulIndex) {
|
||||
consulIndex = currentIndex;
|
||||
List<HealthService> services = response.getValue();
|
||||
List<ServiceInstance> serviceInstances = convert(services);
|
||||
dispatchServiceInstancesChangedEvent(serviceName, serviceInstances);
|
||||
}
|
||||
}
|
||||
|
||||
void stop() {
|
||||
this.running = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class TtlScheduler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TtlScheduler.class);
|
||||
|
||||
private final Map<String, ScheduledFuture> serviceHeartbeats = new ConcurrentHashMap<>();
|
||||
|
||||
private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
private long checkInterval;
|
||||
|
||||
private ConsulClient client;
|
||||
|
||||
public TtlScheduler(long checkInterval, ConsulClient client) {
|
||||
this.checkInterval = checkInterval;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a service to the checks loop.
|
||||
*
|
||||
* @param instanceId instance id
|
||||
*/
|
||||
public void add(String instanceId) {
|
||||
ScheduledFuture task = this.scheduler.scheduleAtFixedRate(
|
||||
new ConsulHeartbeatTask(instanceId),
|
||||
checkInterval / 8,
|
||||
checkInterval / 8,
|
||||
TimeUnit.MILLISECONDS);
|
||||
ScheduledFuture previousTask = this.serviceHeartbeats.put(instanceId, task);
|
||||
if (previousTask != null) {
|
||||
previousTask.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(String instanceId) {
|
||||
ScheduledFuture task = this.serviceHeartbeats.get(instanceId);
|
||||
if (task != null) {
|
||||
task.cancel(true);
|
||||
}
|
||||
this.serviceHeartbeats.remove(instanceId);
|
||||
}
|
||||
|
||||
private class ConsulHeartbeatTask implements Runnable {
|
||||
|
||||
private String checkId;
|
||||
|
||||
ConsulHeartbeatTask(String serviceId) {
|
||||
this.checkId = serviceId;
|
||||
if (!this.checkId.startsWith("service:")) {
|
||||
this.checkId = "service:" + this.checkId;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
TtlScheduler.this.client.agentCheckPass(this.checkId);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Sending consul heartbeat for: " + this.checkId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
scheduler.shutdownNow();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
consul=org.apache.dubbo.registry.consul.ConsulRegistryFactory
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
/*
|
||||
* 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.registry.consul;
|
||||
|
||||
import com.pszymczyk.consul.ConsulProcess;
|
||||
import com.pszymczyk.consul.ConsulStarterBuilder;
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.status.Status;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.registry.NotifyListener;
|
||||
import org.apache.dubbo.registry.Registry;
|
||||
import org.apache.dubbo.registry.status.RegistryStatusChecker;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class ConsulRegistryTest {
|
||||
|
||||
private static ConsulProcess consul;
|
||||
private ConsulRegistry consulRegistry;
|
||||
private String service = "org.apache.dubbo.test.injvmServie";
|
||||
private URL serviceUrl = URL.valueOf("consul://127.0.0.1:" + NetUtils.getAvailablePort() + "/" + service + "?notify=false&methods=test1,test2");
|
||||
private URL registryUrl;
|
||||
private ConsulRegistryFactory consulRegistryFactory;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
this.consul = ConsulStarterBuilder.consulStarter()
|
||||
.build()
|
||||
.start();
|
||||
this.registryUrl = URL.valueOf("consul://localhost:" + consul.getHttpPort());
|
||||
|
||||
consulRegistryFactory = new ConsulRegistryFactory();
|
||||
this.consulRegistry = (ConsulRegistry) consulRegistryFactory.createRegistry(registryUrl);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() throws Exception {
|
||||
consul.close();
|
||||
this.consulRegistry.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegister() {
|
||||
Set<URL> registered;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
consulRegistry.register(serviceUrl);
|
||||
registered = consulRegistry.getRegistered();
|
||||
assertThat(registered.contains(serviceUrl), is(true));
|
||||
}
|
||||
|
||||
registered = consulRegistry.getRegistered();
|
||||
|
||||
assertThat(registered.size(), is(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscribe() {
|
||||
NotifyListener listener = mock(NotifyListener.class);
|
||||
consulRegistry.subscribe(serviceUrl, listener);
|
||||
|
||||
Map<URL, Set<NotifyListener>> subscribed = consulRegistry.getSubscribed();
|
||||
assertThat(subscribed.size(), is(1));
|
||||
assertThat(subscribed.get(serviceUrl).size(), is(1));
|
||||
|
||||
consulRegistry.unsubscribe(serviceUrl, listener);
|
||||
subscribed = consulRegistry.getSubscribed();
|
||||
assertThat(subscribed.size(), is(1));
|
||||
assertThat(subscribed.get(serviceUrl).size(), is(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAvailable() {
|
||||
consulRegistry.register(serviceUrl);
|
||||
assertThat(consulRegistry.isAvailable(), is(true));
|
||||
|
||||
// consulRegistry.destroy();
|
||||
// assertThat(consulRegistry.isAvailable(), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookup() throws InterruptedException {
|
||||
List<URL> lookup = consulRegistry.lookup(serviceUrl);
|
||||
assertThat(lookup.size(), is(0));
|
||||
|
||||
consulRegistry.register(serviceUrl);
|
||||
Thread.sleep(5000);
|
||||
lookup = consulRegistry.lookup(serviceUrl);
|
||||
assertThat(lookup.size(), is(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStatusChecker() {
|
||||
RegistryStatusChecker registryStatusChecker = new RegistryStatusChecker();
|
||||
Status status = registryStatusChecker.check();
|
||||
assertThat(status.getLevel(), is(Status.Level.UNKNOWN));
|
||||
|
||||
Registry registry = consulRegistryFactory.getRegistry(registryUrl);
|
||||
assertThat(registry, not(nullValue()));
|
||||
|
||||
status = registryStatusChecker.check();
|
||||
assertThat(status.getLevel(), is(Status.Level.OK));
|
||||
|
||||
registry.register(serviceUrl);
|
||||
status = registryStatusChecker.check();
|
||||
assertThat(status.getLevel(), is(Status.Level.OK));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
* 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.registry.consul;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.registry.client.DefaultServiceInstance;
|
||||
import org.apache.dubbo.registry.client.ServiceInstance;
|
||||
|
||||
import com.pszymczyk.consul.ConsulProcess;
|
||||
import com.pszymczyk.consul.ConsulStarterBuilder;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static java.lang.String.valueOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class ConsulServiceDiscoveryTest {
|
||||
|
||||
private URL url;
|
||||
private ConsulServiceDiscovery consulServiceDiscovery;
|
||||
private ConsulProcess consul;
|
||||
private static final String SERVICE_NAME = "A";
|
||||
private static final String LOCALHOST = "127.0.0.1";
|
||||
|
||||
@BeforeEach
|
||||
public void init() throws Exception {
|
||||
this.consul = ConsulStarterBuilder.consulStarter()
|
||||
.build()
|
||||
.start();
|
||||
url = URL.valueOf("consul://localhost:" + consul.getHttpPort());
|
||||
consulServiceDiscovery = new ConsulServiceDiscovery();
|
||||
consulServiceDiscovery.initialize(url);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void close() {
|
||||
consulServiceDiscovery.destroy();
|
||||
consul.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistration() throws InterruptedException {
|
||||
DefaultServiceInstance serviceInstance = createServiceInstance(SERVICE_NAME, LOCALHOST, NetUtils.getAvailablePort());
|
||||
consulServiceDiscovery.register(serviceInstance);
|
||||
Thread.sleep(5000);
|
||||
|
||||
List<ServiceInstance> serviceInstances = consulServiceDiscovery.getInstances(SERVICE_NAME);
|
||||
assertEquals(serviceInstances.size(), 1);
|
||||
assertEquals(serviceInstances.get(0).getId(), Integer.toHexString(serviceInstance.hashCode()));
|
||||
assertEquals(serviceInstances.get(0).getHost(), serviceInstance.getHost());
|
||||
assertEquals(serviceInstances.get(0).getServiceName(), serviceInstance.getServiceName());
|
||||
assertEquals(serviceInstances.get(0).getPort(), serviceInstance.getPort());
|
||||
|
||||
consulServiceDiscovery.unregister(serviceInstance);
|
||||
Thread.sleep(5000);
|
||||
serviceInstances = consulServiceDiscovery.getInstances(SERVICE_NAME);
|
||||
System.out.println(serviceInstances.size());
|
||||
assertTrue(serviceInstances.isEmpty());
|
||||
}
|
||||
|
||||
private DefaultServiceInstance createServiceInstance(String serviceName, String host, int port) {
|
||||
return new DefaultServiceInstance(host + ":" + port, serviceName, host, port);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetInstances() throws Exception {
|
||||
String serviceName = "ConsulTest77Service";
|
||||
assertTrue(consulServiceDiscovery.getInstances(serviceName).isEmpty());
|
||||
int portA = NetUtils.getAvailablePort();
|
||||
int portB = NetUtils.getAvailablePort();
|
||||
consulServiceDiscovery.register(new DefaultServiceInstance(valueOf(System.nanoTime()), serviceName, "127.0.0.1", portA));
|
||||
consulServiceDiscovery.register(new DefaultServiceInstance(valueOf(System.nanoTime()), serviceName, "127.0.0.1", portB));
|
||||
Thread.sleep(5000);
|
||||
Assertions.assertFalse(consulServiceDiscovery.getInstances(serviceName).isEmpty());
|
||||
List<String> r = convertToIpPort(consulServiceDiscovery.getInstances(serviceName));
|
||||
assertTrue(r.contains("127.0.0.1:" + portA));
|
||||
assertTrue(r.contains("127.0.0.1:" + portB));
|
||||
}
|
||||
|
||||
private List<String> convertToIpPort(List<ServiceInstance> serviceInstances) {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (ServiceInstance serviceInstance : serviceInstances) {
|
||||
result.add(serviceInstance.getHost() + ":" + serviceInstance.getPort());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>dubbo-registry-default</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>The default registry module of dubbo project</description>
|
||||
<properties>
|
||||
<skip_maven_deploy>false</skip_maven_deploy>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</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-rpc-injvm</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.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
/*
|
||||
* 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.registry.dubbo;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.Version;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.utils.ExecutorUtil;
|
||||
import org.apache.dubbo.common.utils.NamedThreadFactory;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.registry.NotifyListener;
|
||||
import org.apache.dubbo.registry.RegistryService;
|
||||
import org.apache.dubbo.registry.support.FailbackRegistry;
|
||||
import org.apache.dubbo.remoting.Constants;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static org.apache.dubbo.registry.Constants.REGISTRY_RECONNECT_PERIOD_KEY;
|
||||
|
||||
/**
|
||||
* DubboRegistry
|
||||
*/
|
||||
public class DubboRegistry extends FailbackRegistry {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(DubboRegistry.class);
|
||||
|
||||
// Reconnecting detection cycle: 3 seconds (unit:millisecond)
|
||||
private static final int RECONNECT_PERIOD_DEFAULT = 3 * 1000;
|
||||
|
||||
// Scheduled executor service
|
||||
private final ScheduledExecutorService reconnectTimer = Executors.newScheduledThreadPool(1, new NamedThreadFactory("DubboRegistryReconnectTimer", true));
|
||||
|
||||
// Reconnection timer, regular check connection is available. If unavailable, unlimited reconnection.
|
||||
private final ScheduledFuture<?> reconnectFuture;
|
||||
|
||||
// The lock for client acquisition process, lock the creation process of the client instance to prevent repeated clients
|
||||
private final ReentrantLock clientLock = new ReentrantLock();
|
||||
|
||||
private final Invoker<RegistryService> registryInvoker;
|
||||
|
||||
private final RegistryService registryService;
|
||||
|
||||
/**
|
||||
* The time in milliseconds the reconnectTimer will wait
|
||||
*/
|
||||
private final int reconnectPeriod;
|
||||
|
||||
public DubboRegistry(Invoker<RegistryService> registryInvoker, RegistryService registryService) {
|
||||
super(registryInvoker.getUrl());
|
||||
this.registryInvoker = registryInvoker;
|
||||
this.registryService = registryService;
|
||||
// Start reconnection timer
|
||||
this.reconnectPeriod = registryInvoker.getUrl().getParameter(REGISTRY_RECONNECT_PERIOD_KEY, RECONNECT_PERIOD_DEFAULT);
|
||||
reconnectFuture = reconnectTimer.scheduleWithFixedDelay(() -> {
|
||||
// Check and connect to the registry
|
||||
try {
|
||||
connect();
|
||||
} catch (Throwable t) { // Defensive fault tolerance
|
||||
logger.error("Unexpected error occur at reconnect, cause: " + t.getMessage(), t);
|
||||
}
|
||||
}, reconnectPeriod, reconnectPeriod, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
protected final void connect() {
|
||||
try {
|
||||
// Check whether or not it is connected
|
||||
if (isAvailable()) {
|
||||
return;
|
||||
}
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Reconnect to registry " + getUrl());
|
||||
}
|
||||
clientLock.lock();
|
||||
try {
|
||||
// Double check whether or not it is connected
|
||||
if (isAvailable()) {
|
||||
return;
|
||||
}
|
||||
recover();
|
||||
} finally {
|
||||
clientLock.unlock();
|
||||
}
|
||||
} catch (Throwable t) { // Ignore all the exceptions and wait for the next retry
|
||||
if (getUrl().getParameter(Constants.CHECK_KEY, true)) {
|
||||
if (t instanceof RuntimeException) {
|
||||
throw (RuntimeException) t;
|
||||
}
|
||||
throw new RuntimeException(t.getMessage(), t);
|
||||
}
|
||||
logger.error("Failed to connect to registry " + getUrl().getAddress() + " from provider/consumer " + NetUtils.getLocalHost() + " use dubbo " + Version.getVersion() + ", cause: " + t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
if (registryInvoker == null) {
|
||||
return false;
|
||||
}
|
||||
return registryInvoker.isAvailable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
try {
|
||||
// Cancel the reconnection timer
|
||||
ExecutorUtil.cancelScheduledFuture(reconnectFuture);
|
||||
} catch (Throwable t) {
|
||||
logger.warn("Failed to cancel reconnect timer", t);
|
||||
}
|
||||
registryInvoker.destroy();
|
||||
ExecutorUtil.gracefulShutdown(reconnectTimer, reconnectPeriod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRegister(URL url) {
|
||||
registryService.register(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doUnregister(URL url) {
|
||||
registryService.unregister(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSubscribe(URL url, NotifyListener listener) {
|
||||
registryService.subscribe(url, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doUnsubscribe(URL url, NotifyListener listener) {
|
||||
registryService.unsubscribe(url, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<URL> lookup(URL url) {
|
||||
return registryService.lookup(url);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
* 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.registry.dubbo;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.URLBuilder;
|
||||
import org.apache.dubbo.common.bytecode.Wrapper;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.registry.Registry;
|
||||
import org.apache.dubbo.registry.RegistryService;
|
||||
import org.apache.dubbo.registry.integration.RegistryDirectory;
|
||||
import org.apache.dubbo.registry.support.AbstractRegistryFactory;
|
||||
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.RouterChain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.CALLBACK_INSTANCES_LIMIT_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.LAZY_CONNECT_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
|
||||
import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;
|
||||
import static org.apache.dubbo.registry.Constants.CONSUMER_PROTOCOL;
|
||||
import static org.apache.dubbo.remoting.Constants.CONNECT_TIMEOUT_KEY;
|
||||
import static org.apache.dubbo.remoting.Constants.RECONNECT_KEY;
|
||||
import static org.apache.dubbo.rpc.cluster.Constants.CLUSTER_STICKY_KEY;
|
||||
import static org.apache.dubbo.rpc.cluster.Constants.EXPORT_KEY;
|
||||
import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
|
||||
|
||||
/**
|
||||
* DubboRegistryFactory
|
||||
*
|
||||
*/
|
||||
public class DubboRegistryFactory extends AbstractRegistryFactory {
|
||||
|
||||
private Protocol protocol;
|
||||
private ProxyFactory proxyFactory;
|
||||
private Cluster cluster;
|
||||
|
||||
private static URL getRegistryURL(URL url) {
|
||||
return URLBuilder.from(url)
|
||||
.setPath(RegistryService.class.getName())
|
||||
.removeParameter(EXPORT_KEY).removeParameter(REFER_KEY)
|
||||
.addParameter(INTERFACE_KEY, RegistryService.class.getName())
|
||||
.addParameter(CLUSTER_STICKY_KEY, "true")
|
||||
.addParameter(LAZY_CONNECT_KEY, "true")
|
||||
.addParameter(RECONNECT_KEY, "false")
|
||||
.addParameterIfAbsent(TIMEOUT_KEY, "10000")
|
||||
.addParameterIfAbsent(CALLBACK_INSTANCES_LIMIT_KEY, "10000")
|
||||
.addParameterIfAbsent(CONNECT_TIMEOUT_KEY, "10000")
|
||||
.addParameter(METHODS_KEY, StringUtils.join(new HashSet<>(Arrays.asList(Wrapper.getWrapper(RegistryService.class).getDeclaredMethodNames())), ","))
|
||||
//.addParameter(Constants.STUB_KEY, RegistryServiceStub.class.getName())
|
||||
//.addParameter(Constants.STUB_EVENT_KEY, Boolean.TRUE.toString()) //for event dispatch
|
||||
//.addParameter(Constants.ON_DISCONNECT_KEY, "disconnect")
|
||||
.addParameter("subscribe.1.callback", "true")
|
||||
.addParameter("unsubscribe.1.callback", "false")
|
||||
.build();
|
||||
}
|
||||
|
||||
public void setProtocol(Protocol protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public void setProxyFactory(ProxyFactory proxyFactory) {
|
||||
this.proxyFactory = proxyFactory;
|
||||
}
|
||||
|
||||
public void setCluster(Cluster cluster) {
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Registry createRegistry(URL url) {
|
||||
url = getRegistryURL(url);
|
||||
List<URL> urls = new ArrayList<>();
|
||||
urls.add(url.removeParameter(BACKUP_KEY));
|
||||
String backup = url.getParameter(BACKUP_KEY);
|
||||
if (backup != null && backup.length() > 0) {
|
||||
String[] addresses = COMMA_SPLIT_PATTERN.split(backup);
|
||||
for (String address : addresses) {
|
||||
urls.add(url.setAddress(address));
|
||||
}
|
||||
}
|
||||
RegistryDirectory<RegistryService> directory = new RegistryDirectory<>(RegistryService.class, url.addParameter(INTERFACE_KEY, RegistryService.class.getName()).addParameterAndEncoded(REFER_KEY, url.toParameterString()));
|
||||
Invoker<RegistryService> registryInvoker = cluster.join(directory);
|
||||
RegistryService registryService = proxyFactory.getProxy(registryInvoker);
|
||||
DubboRegistry registry = new DubboRegistry(registryInvoker, registryService);
|
||||
directory.setRegistry(registry);
|
||||
directory.setProtocol(protocol);
|
||||
directory.setRouterChain(RouterChain.buildChain(url));
|
||||
directory.notify(urls);
|
||||
directory.subscribe(new URL(CONSUMER_PROTOCOL, NetUtils.getLocalHost(), 0, RegistryService.class.getName(), url.getParameters()));
|
||||
return registry;
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
dubbo=org.apache.dubbo.registry.dubbo.DubboRegistryFactory
|
||||
|
|
@ -1,237 +0,0 @@
|
|||
/*
|
||||
* 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.registry.dubbo;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.registry.NotifyListener;
|
||||
import org.apache.dubbo.registry.RegistryService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* AbstractRegistryService
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractRegistryService implements RegistryService {
|
||||
|
||||
// Log output
|
||||
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
// Registered services
|
||||
// Map<serviceName, Map<url, queryString>>
|
||||
private final ConcurrentMap<String, List<URL>> registered = new ConcurrentHashMap<String, List<URL>>();
|
||||
|
||||
// Subscribed services
|
||||
// Map<serviceName, queryString>
|
||||
private final ConcurrentMap<String, Map<String, String>> subscribed = new ConcurrentHashMap<String, Map<String, String>>();
|
||||
|
||||
// Notified services
|
||||
// Map<serviceName, Map<url, queryString>>
|
||||
private final ConcurrentMap<String, List<URL>> notified = new ConcurrentHashMap<String, List<URL>>();
|
||||
|
||||
// Listeners list for subscribed services
|
||||
// Map<serviceName, List<notificationListener>>
|
||||
private final ConcurrentMap<String, List<NotifyListener>> notifyListeners = new ConcurrentHashMap<String, List<NotifyListener>>();
|
||||
|
||||
@Override
|
||||
public void register(URL url) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Register service: " + url.getServiceKey() + ",url:" + url);
|
||||
}
|
||||
register(url.getServiceKey(), url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(URL url) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Unregister service: " + url.getServiceKey() + ",url:" + url);
|
||||
}
|
||||
unregister(url.getServiceKey(), url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(URL url, NotifyListener listener) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Subscribe service: " + url.getServiceKey() + ",url:" + url);
|
||||
}
|
||||
subscribe(url.getServiceKey(), url, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribe(URL url, NotifyListener listener) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Unsubscribe service: " + url.getServiceKey() + ",url:" + url);
|
||||
}
|
||||
unsubscribe(url.getServiceKey(), url, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<URL> lookup(URL url) {
|
||||
return getRegistered(url.getServiceKey());
|
||||
}
|
||||
|
||||
public void register(String service, URL url) {
|
||||
if (service == null) {
|
||||
throw new IllegalArgumentException("service == null");
|
||||
}
|
||||
if (url == null) {
|
||||
throw new IllegalArgumentException("url == null");
|
||||
}
|
||||
List<URL> urls = registered.computeIfAbsent(service, k -> new CopyOnWriteArrayList<>());
|
||||
if (!urls.contains(url)) {
|
||||
urls.add(url);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregister(String service, URL url) {
|
||||
if (service == null) {
|
||||
throw new IllegalArgumentException("service == null");
|
||||
}
|
||||
if (url == null) {
|
||||
throw new IllegalArgumentException("url == null");
|
||||
}
|
||||
List<URL> urls = registered.get(service);
|
||||
if (urls != null) {
|
||||
URL deleteURL = null;
|
||||
for (URL u : urls) {
|
||||
if (u.toIdentityString().equals(url.toIdentityString())) {
|
||||
deleteURL = u;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (deleteURL != null) {
|
||||
urls.remove(deleteURL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void subscribe(String service, URL url, NotifyListener listener) {
|
||||
if (service == null) {
|
||||
throw new IllegalArgumentException("service == null");
|
||||
}
|
||||
if (url == null) {
|
||||
throw new IllegalArgumentException("parameters == null");
|
||||
}
|
||||
if (listener == null) {
|
||||
throw new IllegalArgumentException("listener == null");
|
||||
}
|
||||
subscribed.put(service, url.getParameters());
|
||||
addListener(service, listener);
|
||||
}
|
||||
|
||||
public void unsubscribe(String service, URL url, NotifyListener listener) {
|
||||
if (service == null) {
|
||||
throw new IllegalArgumentException("service == null");
|
||||
}
|
||||
if (url == null) {
|
||||
throw new IllegalArgumentException("parameters == null");
|
||||
}
|
||||
if (listener == null) {
|
||||
throw new IllegalArgumentException("listener == null");
|
||||
}
|
||||
subscribed.remove(service);
|
||||
removeListener(service, listener);
|
||||
}
|
||||
|
||||
//The listener of the consumer and the provider can be stored together, all based on the service name
|
||||
private void addListener(final String service, final NotifyListener listener) {
|
||||
if (listener == null) {
|
||||
return;
|
||||
}
|
||||
List<NotifyListener> listeners = notifyListeners.computeIfAbsent(service, k -> new CopyOnWriteArrayList<>());
|
||||
if (!listeners.contains(listener)) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeListener(final String service, final NotifyListener listener) {
|
||||
if (listener == null) {
|
||||
return;
|
||||
}
|
||||
List<NotifyListener> listeners = notifyListeners.get(service);
|
||||
if (listeners != null) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
private void doNotify(String service, List<URL> urls) {
|
||||
notified.put(service, urls);
|
||||
List<NotifyListener> listeners = notifyListeners.get(service);
|
||||
if (listeners != null) {
|
||||
for (NotifyListener listener : listeners) {
|
||||
try {
|
||||
notify(service, urls, listener);
|
||||
} catch (Throwable t) {
|
||||
logger.error("Failed to notify registry event, service: " + service + ", urls: " + urls + ", cause: " + t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void notify(String service, List<URL> urls, NotifyListener listener) {
|
||||
listener.notify(urls);
|
||||
}
|
||||
|
||||
protected final void forbid(String service) {
|
||||
doNotify(service, new ArrayList<URL>(0));
|
||||
}
|
||||
|
||||
protected final void notify(String service, List<URL> urls) {
|
||||
if (service == null || service.length() == 0
|
||||
|| urls == null || urls.size() == 0) {
|
||||
return;
|
||||
}
|
||||
doNotify(service, urls);
|
||||
}
|
||||
|
||||
public Map<String, List<URL>> getRegistered() {
|
||||
return Collections.unmodifiableMap(registered);
|
||||
}
|
||||
|
||||
public List<URL> getRegistered(String service) {
|
||||
return Collections.unmodifiableList(registered.get(service));
|
||||
}
|
||||
|
||||
public Map<String, Map<String, String>> getSubscribed() {
|
||||
return Collections.unmodifiableMap(subscribed);
|
||||
}
|
||||
|
||||
public Map<String, String> getSubscribed(String service) {
|
||||
return subscribed.get(service);
|
||||
}
|
||||
|
||||
public Map<String, List<URL>> getNotified() {
|
||||
return Collections.unmodifiableMap(notified);
|
||||
}
|
||||
|
||||
public List<URL> getNotified(String service) {
|
||||
return Collections.unmodifiableList(notified.get(service));
|
||||
}
|
||||
|
||||
public Map<String, List<NotifyListener>> getListeners() {
|
||||
return Collections.unmodifiableMap(notifyListeners);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* 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.registry.dubbo;
|
||||
|
||||
/**
|
||||
* <code>TestService</code>
|
||||
*/
|
||||
|
||||
public interface DemoService {
|
||||
void sayHello(String name);
|
||||
|
||||
int plus(int a, int b);
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* 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.registry.dubbo;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class DemoServiceImpl implements DemoService {
|
||||
@Override
|
||||
public void sayHello(String name) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int plus(int a, int b) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
/*
|
||||
* 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.registry.dubbo;
|
||||
|
||||
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.NetUtils;
|
||||
import org.apache.dubbo.registry.NotifyListener;
|
||||
import org.apache.dubbo.registry.RegistryService;
|
||||
import org.apache.dubbo.registry.support.FailbackRegistry;
|
||||
import org.apache.dubbo.remoting.Constants;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.mock;
|
||||
|
||||
public class DubboRegistryTest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DubboRegistryTest.class);
|
||||
|
||||
private DubboRegistry dubboRegistry;
|
||||
|
||||
private URL registryURL;
|
||||
|
||||
private URL serviceURL;
|
||||
|
||||
private NotifyListener notifyListener;
|
||||
|
||||
private Invoker<RegistryService> invoker;
|
||||
|
||||
private RegistryService registryService;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
registryURL = new URL(REGISTRY_PROTOCOL, NetUtils.getLocalHost(), NetUtils.getAvailablePort())
|
||||
.addParameter(Constants.CHECK_KEY, false)
|
||||
.setServiceInterface(RegistryService.class.getName());
|
||||
serviceURL = new URL(DubboProtocol.NAME, NetUtils.getLocalHost(), NetUtils.getAvailablePort())
|
||||
.addParameter(Constants.CHECK_KEY, false)
|
||||
.setServiceInterface(RegistryService.class.getName());
|
||||
|
||||
registryService = new MockDubboRegistry(registryURL);
|
||||
|
||||
invoker = mock(Invoker.class);
|
||||
given(invoker.getUrl()).willReturn(serviceURL);
|
||||
given(invoker.getInterface()).willReturn(RegistryService.class);
|
||||
given(invoker.invoke(new RpcInvocation())).willReturn(null);
|
||||
|
||||
dubboRegistry = new DubboRegistry(invoker, registryService);
|
||||
notifyListener = mock(NotifyListener.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegister() {
|
||||
dubboRegistry.register(serviceURL);
|
||||
assertEquals(1, getRegisteredSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnRegister() {
|
||||
assertEquals(0, getRegisteredSize());
|
||||
dubboRegistry.register(serviceURL);
|
||||
assertEquals(1, getRegisteredSize());
|
||||
dubboRegistry.unregister(serviceURL);
|
||||
assertEquals(0, getRegisteredSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscribe() {
|
||||
dubboRegistry.register(serviceURL);
|
||||
assertEquals(1, getRegisteredSize());
|
||||
dubboRegistry.subscribe(serviceURL, notifyListener);
|
||||
assertEquals(1, getSubscribedSize());
|
||||
assertEquals(1, getNotifiedListeners());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribe() {
|
||||
dubboRegistry.subscribe(serviceURL, notifyListener);
|
||||
assertEquals(1, getSubscribedSize());
|
||||
assertEquals(1, getNotifiedListeners());
|
||||
dubboRegistry.unsubscribe(serviceURL, notifyListener);
|
||||
assertEquals(0, getNotifiedListeners());
|
||||
}
|
||||
|
||||
private class MockDubboRegistry extends FailbackRegistry {
|
||||
|
||||
private volatile boolean isAvailable = false;
|
||||
|
||||
public MockDubboRegistry(URL url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRegister(URL url) {
|
||||
logger.info("Begin to register: " + url);
|
||||
isAvailable = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doUnregister(URL url) {
|
||||
logger.info("Begin to ungister: " + url);
|
||||
isAvailable = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSubscribe(URL url, NotifyListener listener) {
|
||||
logger.info("Begin to subscribe: " + url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doUnsubscribe(URL url, NotifyListener listener) {
|
||||
logger.info("Begin to unSubscribe: " + url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return isAvailable;
|
||||
}
|
||||
}
|
||||
|
||||
private int getNotifiedListeners() {
|
||||
return dubboRegistry.getSubscribed().get(serviceURL).size();
|
||||
}
|
||||
|
||||
private int getRegisteredSize() {
|
||||
return dubboRegistry.getRegistered().size();
|
||||
}
|
||||
|
||||
private int getSubscribedSize() {
|
||||
return dubboRegistry.getSubscribed().size();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
/*
|
||||
* 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.registry.dubbo;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.remoting.ChannelHandler;
|
||||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeChannel;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeHandler;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class MockChannel implements ExchangeChannel {
|
||||
|
||||
public static boolean closed = false;
|
||||
public static boolean closing = true;
|
||||
final InetSocketAddress localAddress;
|
||||
final InetSocketAddress remoteAddress;
|
||||
|
||||
public MockChannel(String localHostname, int localPort, String remoteHostName, int remotePort) {
|
||||
localAddress = new InetSocketAddress(localHostname, localPort);
|
||||
remoteAddress = new InetSocketAddress(remoteHostName, remotePort);
|
||||
closed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getLocalAddress() {
|
||||
return localAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getRemoteAddress() {
|
||||
return remoteAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Object message) throws RemotingException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(int timeout) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startClose() {
|
||||
closing = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUrl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public CompletableFuture<Object> send(Object request, int timeout) throws RemotingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelHandler getChannelHandler() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public CompletableFuture<Object> request(Object request) throws RemotingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public CompletableFuture<Object> request(Object request, int timeout) throws RemotingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ExchangeHandler getExchangeHandler() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String key, Object value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAttribute(String key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String key) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Object message, boolean sent) throws RemotingException {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,298 +0,0 @@
|
|||
/*
|
||||
* 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.registry.dubbo;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.remoting.Channel;
|
||||
import org.apache.dubbo.remoting.ChannelHandler;
|
||||
import org.apache.dubbo.remoting.Codec;
|
||||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeClient;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeHandler;
|
||||
import org.apache.dubbo.remoting.exchange.support.Replier;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* MockedClient
|
||||
*
|
||||
*/
|
||||
public class MockedClient implements ExchangeClient {
|
||||
|
||||
//private String host;
|
||||
|
||||
//private int port;
|
||||
|
||||
private boolean connected;
|
||||
|
||||
private Object received;
|
||||
|
||||
private Object sent;
|
||||
|
||||
private Object invoked;
|
||||
|
||||
private Replier<?> handler;
|
||||
|
||||
private InetSocketAddress address;
|
||||
|
||||
private boolean closed = false;
|
||||
|
||||
//private ChannelListener listener;
|
||||
|
||||
public MockedClient(String host, int port, boolean connected) {
|
||||
this(host, port, connected, null);
|
||||
}
|
||||
|
||||
public MockedClient(String host, int port, boolean connected, Object received) {
|
||||
this.address = new InetSocketAddress(host, port);
|
||||
this.connected = connected;
|
||||
this.received = received;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Object msg) throws RemotingException {
|
||||
this.sent = msg;
|
||||
}
|
||||
|
||||
public CompletableFuture<Object> request(Object msg) throws RemotingException {
|
||||
return request(msg, null);
|
||||
}
|
||||
|
||||
public CompletableFuture<Object> request(Object msg, int timeout) throws RemotingException {
|
||||
return this.request(msg, timeout, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object msg, ExecutorService executor) throws RemotingException {
|
||||
return this.request(msg, 0, executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object msg, int timeout, ExecutorService executor) throws RemotingException {
|
||||
this.invoked = msg;
|
||||
return new CompletableFuture<Object>() {
|
||||
public Object get() throws InterruptedException, ExecutionException {
|
||||
return received;
|
||||
}
|
||||
|
||||
public Object get(int timeoutInMillis) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
return received;
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void registerHandler(Replier<?> handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public void unregisterHandler(Replier<?> handler) {
|
||||
//this.handler = null;
|
||||
}
|
||||
|
||||
public void addChannelListener(ChannelHandler listener) {
|
||||
//this.listener = listener;
|
||||
}
|
||||
|
||||
public void removeChannelListener(ChannelHandler listener) {
|
||||
//this.listener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param connected the connected to set
|
||||
*/
|
||||
public void setConnected(boolean connected) {
|
||||
this.connected = connected;
|
||||
}
|
||||
|
||||
public Object getSent() {
|
||||
return sent;
|
||||
}
|
||||
|
||||
public Replier<?> getHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public Object getInvoked() {
|
||||
return invoked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getRemoteAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "mocked";
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getLocalAddress() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getTimeout() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setTimeout(int timeout) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(int timeout) {
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startClose() {
|
||||
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
public Codec getCodec() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setCodec(Codec codec) {
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
}
|
||||
|
||||
public int getThreadCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setThreadCount(int threadCount) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUrl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Replier<?> getReceiver() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelHandler getChannelHandler() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void reset(Map<String, String> parameters) {
|
||||
}
|
||||
|
||||
public Channel getChannel() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExchangeHandler getExchangeHandler() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconnect() throws RemotingException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String key, Object value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAttribute(String key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String key) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the received
|
||||
*/
|
||||
public Object getReceived() {
|
||||
return received;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param received the received to set
|
||||
*/
|
||||
public void setReceived(Object received) {
|
||||
this.received = received;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Object message, boolean sent) throws RemotingException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(URL url) {
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void reset(org.apache.dubbo.common.Parameters parameters) {
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,232 +0,0 @@
|
|||
/*
|
||||
* 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.registry.dubbo;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.config.ConfigurationUtils;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.registry.NotifyListener;
|
||||
import org.apache.dubbo.registry.RegistryFactory;
|
||||
import org.apache.dubbo.registry.RegistryService;
|
||||
import org.apache.dubbo.registry.integration.RegistryProtocol;
|
||||
import org.apache.dubbo.registry.support.AbstractRegistry;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeClient;
|
||||
import org.apache.dubbo.rpc.Exporter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Protocol;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.model.ServiceDescriptor;
|
||||
import org.apache.dubbo.rpc.protocol.AbstractInvoker;
|
||||
import org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker;
|
||||
import org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.dubbo.registry.integration.RegistryProtocol.DEFAULT_REGISTER_PROVIDER_KEYS;
|
||||
import static org.apache.dubbo.rpc.cluster.Constants.EXPORT_KEY;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* RegistryProtocolTest
|
||||
*/
|
||||
public class RegistryProtocolTest {
|
||||
|
||||
static {
|
||||
SimpleRegistryExporter.exportIfAbsent(9090);
|
||||
}
|
||||
|
||||
final String service = DemoService.class.getName() + ":1.0.0";
|
||||
final String serviceUrl = "dubbo://127.0.0.1:9453/" + service + "?notify=true&methods=test1,test2&side=con&side=consumer";
|
||||
final URL registryUrl = URL.valueOf("registry://127.0.0.1:9090/");
|
||||
final private Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
|
||||
|
||||
public static RegistryProtocol getRegistryProtocol() {
|
||||
return RegistryProtocol.getRegistryProtocol();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
ApplicationModel.setApplication("RegistryProtocolTest");
|
||||
ApplicationModel.getServiceRepository().registerService(RegistryService.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultPort() {
|
||||
RegistryProtocol registryProtocol = getRegistryProtocol();
|
||||
assertEquals(9090, registryProtocol.getDefaultPort());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExportUrlNull() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||
RegistryProtocol registryProtocol = getRegistryProtocol();
|
||||
// registryProtocol.setCluster(new FailfastCluster());
|
||||
|
||||
Protocol dubboProtocol = DubboProtocol.getDubboProtocol();
|
||||
registryProtocol.setProtocol(dubboProtocol);
|
||||
Invoker<DemoService> invoker = new DubboInvoker<DemoService>(DemoService.class,
|
||||
registryUrl, new ExchangeClient[]{new MockedClient("10.20.20.20", 2222, true)});
|
||||
registryProtocol.export(invoker);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExport() {
|
||||
RegistryProtocol registryProtocol = getRegistryProtocol();
|
||||
// registryProtocol.setCluster(new FailfastCluster());
|
||||
registryProtocol.setRegistryFactory(ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension());
|
||||
|
||||
Protocol dubboProtocol = DubboProtocol.getDubboProtocol();
|
||||
registryProtocol.setProtocol(dubboProtocol);
|
||||
URL newRegistryUrl = registryUrl.addParameter(EXPORT_KEY, serviceUrl);
|
||||
DubboInvoker<DemoService> invoker = new DubboInvoker<DemoService>(DemoService.class,
|
||||
newRegistryUrl, new ExchangeClient[]{new MockedClient("10.20.20.20", 2222, true)});
|
||||
Exporter<DemoService> exporter = registryProtocol.export(invoker);
|
||||
Exporter<DemoService> exporter2 = registryProtocol.export(invoker);
|
||||
//The same invoker, exporter that multiple exported are different
|
||||
Assertions.assertNotSame(exporter, exporter2);
|
||||
exporter.unexport();
|
||||
exporter2.unexport();
|
||||
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void testNotifyOverride() throws Exception {
|
||||
// URL newRegistryUrl = registryUrl.addParameter(EXPORT_KEY, serviceUrl);
|
||||
// Invoker<RegistryProtocolTest> invoker = new MockInvoker<RegistryProtocolTest>(RegistryProtocolTest.class, newRegistryUrl);
|
||||
//
|
||||
// ServiceDescriptor descriptor = ApplicationModel.getServiceRepository().registerService(DemoService.class);
|
||||
// ApplicationModel.getServiceRepository().registerProvider(service, new DemoServiceImpl(), descriptor, null, null);
|
||||
//
|
||||
// Exporter<?> exporter = protocol.export(invoker);
|
||||
// RegistryProtocol rprotocol = getRegistryProtocol();
|
||||
// NotifyListener listener = getListener(rprotocol);
|
||||
// List<URL> urls = new ArrayList<URL>();
|
||||
// urls.add(URL.valueOf("override://0.0.0.0/?timeout=1000"));
|
||||
// urls.add(URL.valueOf("override://0.0.0.0/" + service + "?timeout=100"));
|
||||
// urls.add(URL.valueOf("override://0.0.0.0/" + service + "?x=y"));
|
||||
// listener.notify(urls);
|
||||
//
|
||||
// assertTrue(exporter.getInvoker().isAvailable());
|
||||
// assertEquals("100", exporter.getInvoker().getUrl().getParameter("timeout"));
|
||||
// assertEquals("y", exporter.getInvoker().getUrl().getParameter("x"));
|
||||
//
|
||||
// exporter.unexport();
|
||||
//// int timeout = ConfigUtils.getServerShutdownTimeout();
|
||||
//// Thread.sleep(timeout + 1000);
|
||||
//// assertEquals(false, exporter.getInvoker().isAvailable());
|
||||
// destroyRegistryProtocol();
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* The name of the service does not match and can't override invoker
|
||||
* Service name matching, service version number mismatch
|
||||
*/
|
||||
@Test
|
||||
public void testNotifyOverride_notmatch() throws Exception {
|
||||
URL newRegistryUrl = registryUrl.addParameter(EXPORT_KEY, serviceUrl);
|
||||
Invoker<RegistryProtocolTest> invoker = new MockInvoker<RegistryProtocolTest>(RegistryProtocolTest.class, newRegistryUrl);
|
||||
|
||||
ServiceDescriptor descriptor = ApplicationModel.getServiceRepository().registerService(DemoService.class);
|
||||
ApplicationModel.getServiceRepository().registerProvider(service, new DemoServiceImpl(), descriptor, null, null);
|
||||
|
||||
Exporter<?> exporter = protocol.export(invoker);
|
||||
RegistryProtocol rprotocol = getRegistryProtocol();
|
||||
NotifyListener listener = getListener(rprotocol);
|
||||
List<URL> urls = new ArrayList<URL>();
|
||||
urls.add(URL.valueOf("override://0.0.0.0/org.apache.dubbo.registry.protocol.HackService?timeout=100"));
|
||||
listener.notify(urls);
|
||||
assertTrue(exporter.getInvoker().isAvailable());
|
||||
assertNull(exporter.getInvoker().getUrl().getParameter("timeout"));
|
||||
exporter.unexport();
|
||||
destroyRegistryProtocol();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test destory registry, exporter can be normal by destroyed
|
||||
*/
|
||||
@Test
|
||||
public void testDestoryRegistry() {
|
||||
URL newRegistryUrl = registryUrl.addParameter(EXPORT_KEY, serviceUrl);
|
||||
Invoker<RegistryProtocolTest> invoker = new MockInvoker<RegistryProtocolTest>(RegistryProtocolTest.class, newRegistryUrl);
|
||||
Exporter<?> exporter = protocol.export(invoker);
|
||||
destroyRegistryProtocol();
|
||||
try {
|
||||
Thread.sleep(ConfigurationUtils.getServerShutdownTimeout() + 100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
assertFalse(exporter.getInvoker().isAvailable());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetParamsToRegistry() {
|
||||
RegistryProtocol registryProtocol = getRegistryProtocol();
|
||||
String[] additionalParams = new String[]{"key1", "key2"};
|
||||
String[] registryParams = registryProtocol.getParamsToRegistry(DEFAULT_REGISTER_PROVIDER_KEYS, additionalParams);
|
||||
String[] expectParams = ArrayUtils.addAll(DEFAULT_REGISTER_PROVIDER_KEYS, additionalParams);
|
||||
Assertions.assertArrayEquals(expectParams, registryParams);
|
||||
}
|
||||
|
||||
private void destroyRegistryProtocol() {
|
||||
Protocol registry = getRegistryProtocol();
|
||||
registry.destroy();
|
||||
}
|
||||
|
||||
private NotifyListener getListener(RegistryProtocol protocol) throws Exception {
|
||||
return protocol.getOverrideListeners().values().iterator().next();
|
||||
}
|
||||
|
||||
static class MockInvoker<T> extends AbstractInvoker<T> {
|
||||
public MockInvoker(Class<T> type, URL url) {
|
||||
super(type, url);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result doInvoke(Invocation invocation) throws Throwable {
|
||||
//do nothing
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class MockRegistry extends AbstractRegistry {
|
||||
|
||||
public MockRegistry(URL url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* 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.registry.dubbo;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.common.status.Status;
|
||||
import org.apache.dubbo.registry.RegistryFactory;
|
||||
import org.apache.dubbo.registry.RegistryService;
|
||||
import org.apache.dubbo.registry.status.RegistryStatusChecker;
|
||||
import org.apache.dubbo.registry.support.AbstractRegistryFactory;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* StatusTest
|
||||
*
|
||||
*/
|
||||
public class RegistryStatusCheckerTest {
|
||||
|
||||
static {
|
||||
SimpleRegistryExporter.exportIfAbsent(9090);
|
||||
SimpleRegistryExporter.exportIfAbsent(9091);
|
||||
}
|
||||
|
||||
URL registryUrl = URL.valueOf("dubbo://cat:cat@127.0.0.1:9090/");
|
||||
URL registryUrl2 = URL.valueOf("dubbo://cat:cat@127.0.0.1:9091");
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
AbstractRegistryFactory.clearRegistryNotDestroy();
|
||||
ApplicationModel.getServiceRepository().registerService(RegistryService.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckUnknown() {
|
||||
assertEquals(Status.Level.UNKNOWN, new RegistryStatusChecker().check().getLevel());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckOK() {
|
||||
ApplicationModel.setApplication("testCheckOK");
|
||||
ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension().getRegistry(registryUrl);
|
||||
ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension().getRegistry(registryUrl2);
|
||||
assertEquals(Status.Level.OK, new RegistryStatusChecker().check().getLevel());
|
||||
String message = new RegistryStatusChecker().check().getMessage();
|
||||
Assertions.assertTrue(message.contains(registryUrl.getAddress() + "(connected)"));
|
||||
Assertions.assertTrue(message.contains(registryUrl2.getAddress() + "(connected)"));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* 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.registry.dubbo;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.URLBuilder;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.registry.RegistryService;
|
||||
import org.apache.dubbo.rpc.Exporter;
|
||||
import org.apache.dubbo.rpc.Protocol;
|
||||
import org.apache.dubbo.rpc.ProxyFactory;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.model.ServiceDescriptor;
|
||||
import org.apache.dubbo.rpc.model.ServiceRepository;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.CALLBACK_INSTANCES_LIMIT_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
|
||||
import static org.apache.dubbo.rpc.cluster.Constants.CLUSTER_STICKY_KEY;
|
||||
|
||||
/**
|
||||
* SimpleRegistryExporter
|
||||
*
|
||||
*/
|
||||
public class SimpleRegistryExporter {
|
||||
|
||||
private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
|
||||
|
||||
private static final ProxyFactory PROXY_FACTORY = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
|
||||
|
||||
public synchronized static Exporter<RegistryService> exportIfAbsent(int port) {
|
||||
try {
|
||||
new ServerSocket(port).close();
|
||||
return export(port);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Exporter<RegistryService> export(int port) {
|
||||
return export(port, new SimpleRegistryService());
|
||||
}
|
||||
|
||||
public static Exporter<RegistryService> export(int port, RegistryService registryService) {
|
||||
return protocol.export(PROXY_FACTORY.getInvoker(registryService, RegistryService.class,
|
||||
new URLBuilder(DUBBO_PROTOCOL, NetUtils.getLocalHost(), port, RegistryService.class.getName())
|
||||
.setPath(RegistryService.class.getName())
|
||||
.addParameter(INTERFACE_KEY, RegistryService.class.getName())
|
||||
.addParameter(CLUSTER_STICKY_KEY, "true")
|
||||
.addParameter(CALLBACK_INSTANCES_LIMIT_KEY, "1000")
|
||||
.addParameter("ondisconnect", "disconnect")
|
||||
.addParameter("subscribe.1.callback", "true")
|
||||
.addParameter("unsubscribe.1.callback", "false")
|
||||
.build()));
|
||||
}
|
||||
|
||||
private void registerProvider(URL url, RegistryService registryService) {
|
||||
ServiceRepository repository = ApplicationModel.getServiceRepository();
|
||||
ServiceDescriptor serviceDescriptor = repository.registerService(RegistryService.class);
|
||||
repository.registerProvider(
|
||||
url.getServiceKey(),
|
||||
registryService,
|
||||
serviceDescriptor,
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
/*
|
||||
* 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.registry.dubbo;
|
||||
|
||||
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.NetUtils;
|
||||
import org.apache.dubbo.common.utils.UrlUtils;
|
||||
import org.apache.dubbo.registry.NotifyListener;
|
||||
import org.apache.dubbo.registry.RegistryService;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* SimpleRegistryService
|
||||
*
|
||||
*/
|
||||
public class SimpleRegistryService extends AbstractRegistryService {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(SimpleRegistryService.class);
|
||||
private final ConcurrentMap<String, ConcurrentMap<String, URL>> remoteRegistered = new ConcurrentHashMap<String, ConcurrentMap<String, URL>>();
|
||||
private final ConcurrentMap<String, ConcurrentMap<String, NotifyListener>> remoteListeners = new ConcurrentHashMap<String, ConcurrentMap<String, NotifyListener>>();
|
||||
private List<String> registries;
|
||||
|
||||
public SimpleRegistryService() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(String service, URL url) {
|
||||
super.register(service, url);
|
||||
String client = RpcContext.getContext().getRemoteAddressString();
|
||||
Map<String, URL> urls = remoteRegistered.computeIfAbsent(client, k -> new ConcurrentHashMap<>());
|
||||
urls.put(service, url);
|
||||
notify(service, getRegistered().get(service));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(String service, URL url) {
|
||||
super.unregister(service, url);
|
||||
String client = RpcContext.getContext().getRemoteAddressString();
|
||||
Map<String, URL> urls = remoteRegistered.get(client);
|
||||
if (urls != null && urls.size() > 0) {
|
||||
urls.remove(service);
|
||||
}
|
||||
notify(service, getRegistered().get(service));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(String service, URL url, NotifyListener listener) {
|
||||
String client = RpcContext.getContext().getRemoteAddressString();
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("[subscribe] service: " + service + ",client:" + client);
|
||||
}
|
||||
List<URL> urls = getRegistered().get(service);
|
||||
if ((RegistryService.class.getName() + ":0.0.0").equals(service)
|
||||
&& (urls == null || urls.size() == 0)) {
|
||||
register(service, new URL("dubbo",
|
||||
NetUtils.getLocalHost(),
|
||||
RpcContext.getContext().getLocalPort(),
|
||||
org.apache.dubbo.registry.RegistryService.class.getName(),
|
||||
url.getParameters()));
|
||||
List<String> rs = registries;
|
||||
if (rs != null && rs.size() > 0) {
|
||||
for (String registry : rs) {
|
||||
register(service, UrlUtils.parseURL(registry, url.getParameters()));
|
||||
}
|
||||
}
|
||||
}
|
||||
super.subscribe(service, url, listener);
|
||||
|
||||
Map<String, NotifyListener> listeners = remoteListeners.computeIfAbsent(client, k -> new ConcurrentHashMap<>());
|
||||
listeners.put(service, listener);
|
||||
urls = getRegistered().get(service);
|
||||
if (urls != null && urls.size() > 0) {
|
||||
listener.notify(urls);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribe(String service, URL url, NotifyListener listener) {
|
||||
super.unsubscribe(service, url, listener);
|
||||
String client = RpcContext.getContext().getRemoteAddressString();
|
||||
Map<String, NotifyListener> listeners = remoteListeners.get(client);
|
||||
if (listeners != null && listeners.size() > 0) {
|
||||
listeners.remove(service);
|
||||
}
|
||||
List<URL> urls = getRegistered().get(service);
|
||||
if (urls != null && urls.size() > 0) {
|
||||
listener.notify(urls);
|
||||
}
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
String client = RpcContext.getContext().getRemoteAddressString();
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Disconnected " + client);
|
||||
}
|
||||
ConcurrentMap<String, URL> urls = remoteRegistered.get(client);
|
||||
if (urls != null && urls.size() > 0) {
|
||||
for (Map.Entry<String, URL> entry : urls.entrySet()) {
|
||||
super.unregister(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
Map<String, NotifyListener> listeners = remoteListeners.get(client);
|
||||
if (listeners != null && listeners.size() > 0) {
|
||||
for (Map.Entry<String, NotifyListener> entry : listeners.entrySet()) {
|
||||
String service = entry.getKey();
|
||||
super.unsubscribe(service, new URL("subscribe",
|
||||
RpcContext.getContext().getRemoteHost(),
|
||||
RpcContext.getContext().getRemotePort(),
|
||||
org.apache.dubbo.registry.RegistryService.class.getName(), getSubscribed(service)), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getRegistries() {
|
||||
return registries;
|
||||
}
|
||||
|
||||
public void setRegistries(List<String> registries) {
|
||||
this.registries = registries;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
|
||||
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
|
||||
<!-- ===================================================================== -->
|
||||
<!-- The following is the definition of appender -->
|
||||
<!-- ===================================================================== -->
|
||||
<appender name="dubbo" class="org.apache.dubbo.common.utils.DubboAppender">
|
||||
<param name="File" value="../../dubbo.log"/>
|
||||
<param name="encoding" value="GBK"/>
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<param name="ConversionPattern" value="%d %p [%c:%M] - %m%n"/>
|
||||
</layout>
|
||||
<!-- <filter class="org.apache.log4j.varia.LevelRangeFilter">
|
||||
<param name="LevelMin" value="DEBUG" />
|
||||
<param name="LevelMax" value="DEBUG" />
|
||||
</filter> -->
|
||||
</appender>
|
||||
<root>
|
||||
<level value="INFO"/>
|
||||
<appender-ref ref="dubbo"/>
|
||||
</root>
|
||||
</log4j:configuration>
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>dubbo-registry</artifactId>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>dubbo-registry-etcd3</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>The etcd3 registry module of Dubbo project</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-common</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-etcd3</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
|
|
@ -1,359 +0,0 @@
|
|||
/*
|
||||
* 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.registry.etcd;
|
||||
|
||||
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.ConcurrentHashSet;
|
||||
import org.apache.dubbo.common.utils.UrlUtils;
|
||||
import org.apache.dubbo.registry.NotifyListener;
|
||||
import org.apache.dubbo.registry.support.FailbackRegistry;
|
||||
import org.apache.dubbo.remoting.etcd.ChildListener;
|
||||
import org.apache.dubbo.remoting.etcd.Constants;
|
||||
import org.apache.dubbo.remoting.etcd.EtcdClient;
|
||||
import org.apache.dubbo.remoting.etcd.EtcdTransporter;
|
||||
import org.apache.dubbo.remoting.etcd.StateListener;
|
||||
import org.apache.dubbo.remoting.etcd.option.OptionUtil;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;
|
||||
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.CONSUMERS_CATEGORY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;
|
||||
import static org.apache.dubbo.remoting.Constants.CHECK_KEY;
|
||||
|
||||
|
||||
/**
|
||||
* Support for ectd3 registry.
|
||||
*/
|
||||
public class EtcdRegistry extends FailbackRegistry {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(EtcdRegistry.class);
|
||||
|
||||
private final static int DEFAULT_ETCD_PORT = 2379;
|
||||
|
||||
private final static String DEFAULT_ROOT = "dubbo";
|
||||
|
||||
private final String root;
|
||||
|
||||
private final Set<String> anyServices = new ConcurrentHashSet<>();
|
||||
|
||||
private final ConcurrentMap<URL, ConcurrentMap<NotifyListener, ChildListener>> etcdListeners = new ConcurrentHashMap<>();
|
||||
private final EtcdClient etcdClient;
|
||||
|
||||
public EtcdRegistry(URL url, EtcdTransporter etcdTransporter) {
|
||||
super(url);
|
||||
if (url.isAnyHost()) {
|
||||
throw new IllegalStateException("registry address is invalid, actual: '" + url.getHost() + "'");
|
||||
}
|
||||
String group = url.getParameter(GROUP_KEY, DEFAULT_ROOT);
|
||||
if (!group.startsWith(PATH_SEPARATOR)) {
|
||||
group = PATH_SEPARATOR + group;
|
||||
}
|
||||
this.root = group;
|
||||
etcdClient = etcdTransporter.connect(url);
|
||||
|
||||
etcdClient.addStateListener(state -> {
|
||||
if (state == StateListener.CONNECTED) {
|
||||
try {
|
||||
recover();
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected static String appendDefaultPort(String address) {
|
||||
if (address != null && address.length() > 0) {
|
||||
int i = address.indexOf(':');
|
||||
if (i < 0) {
|
||||
return address + ":" + DEFAULT_ETCD_PORT;
|
||||
} else if (Integer.parseInt(address.substring(i + 1)) == 0) {
|
||||
return address.substring(0, i + 1) + DEFAULT_ETCD_PORT;
|
||||
}
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRegister(URL url) {
|
||||
try {
|
||||
String path = toUrlPath(url);
|
||||
if (url.getParameter(DYNAMIC_KEY, true)) {
|
||||
etcdClient.createEphemeral(path);
|
||||
return;
|
||||
}
|
||||
etcdClient.create(path);
|
||||
} catch (Throwable e) {
|
||||
throw new RpcException("Failed to register " + url + " to etcd " + getUrl()
|
||||
+ ", cause: " + (OptionUtil.isProtocolError(e)
|
||||
? "etcd3 registry may not be supported yet or etcd3 registry is not available."
|
||||
: e.getMessage()), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doUnregister(URL url) {
|
||||
try {
|
||||
String path = toUrlPath(url);
|
||||
etcdClient.delete(path);
|
||||
} catch (Throwable e) {
|
||||
throw new RpcException("Failed to unregister " + url + " to etcd " + getUrl() + ", cause: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSubscribe(URL url, NotifyListener listener) {
|
||||
try {
|
||||
if (ANY_VALUE.equals(url.getServiceInterface())) {
|
||||
String root = toRootPath();
|
||||
|
||||
/*
|
||||
* if we are interested in all interfaces,
|
||||
* find out the current container or create one for the url, put or get only once.
|
||||
*/
|
||||
ConcurrentMap<NotifyListener, ChildListener> listeners =
|
||||
Optional.ofNullable(etcdListeners.get(url))
|
||||
.orElseGet(() -> {
|
||||
ConcurrentMap<NotifyListener, ChildListener> container, prev;
|
||||
prev = etcdListeners.putIfAbsent(url, container = new ConcurrentHashMap<>());
|
||||
return prev != null ? prev : container;
|
||||
});
|
||||
|
||||
/*
|
||||
* if we have no interface watcher listener,
|
||||
* find the current listener or create one for the current root, put or get only once.
|
||||
*/
|
||||
ChildListener interfaceListener =
|
||||
Optional.ofNullable(listeners.get(listener))
|
||||
.orElseGet(() -> {
|
||||
ChildListener childListener, prev;
|
||||
prev = listeners.putIfAbsent(listener, childListener = (parentPath, currentChildren) -> {
|
||||
/*
|
||||
* because etcd3 does not support direct children watch events,
|
||||
* we should filter not interface events. if we watch /dubbo
|
||||
* and /dubbo/interface, when we put a key-value pair {/dubbo/interface/hello hello},
|
||||
* we will got events in watching path /dubbo.
|
||||
*/
|
||||
for (String child : currentChildren) {
|
||||
child = URL.decode(child);
|
||||
if (!anyServices.contains(child)) {
|
||||
anyServices.add(child);
|
||||
/*
|
||||
* if new interface event arrived, we watch their direct children,
|
||||
* eg: /dubbo/interface, /dubbo/interface and so on.
|
||||
*/
|
||||
subscribe(url.setPath(child).addParameters(INTERFACE_KEY, child,
|
||||
CHECK_KEY, String.valueOf(false)), listener);
|
||||
}
|
||||
}
|
||||
});
|
||||
return prev != null ? prev : childListener;
|
||||
});
|
||||
|
||||
etcdClient.create(root);
|
||||
/*
|
||||
* at the first time, we want to pull already interface and then watch their direct children,
|
||||
* eg: /dubbo/interface, /dubbo/interface and so on.
|
||||
*/
|
||||
List<String> services = etcdClient.addChildListener(root, interfaceListener);
|
||||
for (String service : services) {
|
||||
service = URL.decode(service);
|
||||
anyServices.add(service);
|
||||
subscribe(url.setPath(service).addParameters(INTERFACE_KEY, service,
|
||||
CHECK_KEY, String.valueOf(false)), listener);
|
||||
}
|
||||
} else {
|
||||
List<URL> urls = new ArrayList<>();
|
||||
for (String path : toCategoriesPath(url)) {
|
||||
|
||||
/*
|
||||
* if we are interested in special categories (providers, consumers, routers and so on),
|
||||
* we find out the current container or create one for the url, put or get only once.
|
||||
*/
|
||||
ConcurrentMap<NotifyListener, ChildListener> listeners =
|
||||
Optional.ofNullable(etcdListeners.get(url))
|
||||
.orElseGet(() -> {
|
||||
ConcurrentMap<NotifyListener, ChildListener> container, prev;
|
||||
prev = etcdListeners.putIfAbsent(url,
|
||||
container = new ConcurrentHashMap<>());
|
||||
return prev != null ? prev : container;
|
||||
});
|
||||
|
||||
/*
|
||||
* if we have no category watcher listener,
|
||||
* we find out the current listener or create one for the current category, put or get only once.
|
||||
*/
|
||||
ChildListener childListener =
|
||||
Optional.ofNullable(listeners.get(listener))
|
||||
.orElseGet(() -> {
|
||||
ChildListener watchListener, prev;
|
||||
prev = listeners.putIfAbsent(listener, watchListener = (parentPath, currentChildren) -> EtcdRegistry.this.notify(url, listener,
|
||||
toUrlsWithEmpty(url, parentPath, currentChildren)));
|
||||
return prev != null ? prev : watchListener;
|
||||
});
|
||||
|
||||
etcdClient.create(path);
|
||||
/*
|
||||
* at the first time, we want to pull already category and then watch their direct children,
|
||||
* eg: /dubbo/interface/providers, /dubbo/interface/consumers and so on.
|
||||
*/
|
||||
List<String> children = etcdClient.addChildListener(path, childListener);
|
||||
if (children != null) {
|
||||
urls.addAll(toUrlsWithEmpty(url, path, children));
|
||||
}
|
||||
}
|
||||
notify(url, listener, urls);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new RpcException("Failed to subscribe " + url + " to etcd " + getUrl()
|
||||
+ ", cause: " + (OptionUtil.isProtocolError(e)
|
||||
? "etcd3 registry may not be supported yet or etcd3 registry is not available."
|
||||
: e.getMessage()), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doUnsubscribe(URL url, NotifyListener listener) {
|
||||
ConcurrentMap<NotifyListener, ChildListener> listeners = etcdListeners.get(url);
|
||||
if (listeners != null) {
|
||||
ChildListener etcdListener = listeners.get(listener);
|
||||
if (etcdListener != null) {
|
||||
// maybe url has many subscribed paths
|
||||
for (String path : toUnsubscribedPath(url)) {
|
||||
etcdClient.removeChildListener(path, etcdListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return etcdClient.isConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
try {
|
||||
etcdClient.close();
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to close etcd client " + getUrl() + ", cause: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
protected String toRootDir() {
|
||||
if (root.startsWith(PATH_SEPARATOR)) {
|
||||
return root;
|
||||
}
|
||||
return PATH_SEPARATOR + root;
|
||||
}
|
||||
|
||||
protected String toRootPath() {
|
||||
return root;
|
||||
}
|
||||
|
||||
protected String toServicePath(URL url) {
|
||||
String name = url.getServiceInterface();
|
||||
if (ANY_VALUE.equals(name)) {
|
||||
return toRootPath();
|
||||
}
|
||||
return toRootDir() + PATH_SEPARATOR + URL.encode(name);
|
||||
}
|
||||
|
||||
protected String[] toCategoriesPath(URL url) {
|
||||
String[] categories;
|
||||
if (ANY_VALUE.equals(url.getParameter(CATEGORY_KEY))) {
|
||||
categories = new String[]{PROVIDERS_CATEGORY, CONSUMERS_CATEGORY, ROUTERS_CATEGORY, CONFIGURATORS_CATEGORY};
|
||||
} else {
|
||||
categories = url.getParameter(CATEGORY_KEY, new String[]{DEFAULT_CATEGORY});
|
||||
}
|
||||
String[] paths = new String[categories.length];
|
||||
for (int i = 0; i < categories.length; i++) {
|
||||
paths[i] = toServicePath(url) + PATH_SEPARATOR + categories[i];
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
protected String toCategoryPath(URL url) {
|
||||
return toServicePath(url) + PATH_SEPARATOR + url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);
|
||||
}
|
||||
|
||||
protected String toUrlPath(URL url) {
|
||||
return toCategoryPath(url) + PATH_SEPARATOR + URL.encode(url.toFullString());
|
||||
}
|
||||
|
||||
protected List<String> toUnsubscribedPath(URL url) {
|
||||
List<String> categories = new ArrayList<>();
|
||||
if (ANY_VALUE.equals(url.getServiceInterface())) {
|
||||
String group = url.getParameter(GROUP_KEY, DEFAULT_ROOT);
|
||||
if (!group.startsWith(PATH_SEPARATOR)) {
|
||||
group = PATH_SEPARATOR + group;
|
||||
}
|
||||
categories.add(group);
|
||||
return categories;
|
||||
} else {
|
||||
categories.addAll(Arrays.asList(toCategoriesPath(url)));
|
||||
}
|
||||
return categories;
|
||||
}
|
||||
|
||||
protected List<URL> toUrlsWithoutEmpty(URL consumer, List<String> providers) {
|
||||
List<URL> urls = new ArrayList<>();
|
||||
if (providers != null && providers.size() > 0) {
|
||||
for (String provider : providers) {
|
||||
provider = URL.decode(provider);
|
||||
if (provider.contains(Constants.HTTP_SUBFIX_KEY)) {
|
||||
URL url = URL.valueOf(provider);
|
||||
if (UrlUtils.isMatch(consumer, url)) {
|
||||
urls.add(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
protected List<URL> toUrlsWithEmpty(URL consumer, String path, List<String> providers) {
|
||||
List<URL> urls = toUrlsWithoutEmpty(consumer, providers);
|
||||
if (urls == null || urls.isEmpty()) {
|
||||
int i = path.lastIndexOf('/');
|
||||
String category = i < 0 ? path : path.substring(i + 1);
|
||||
URL empty = consumer.setProtocol(EMPTY_PROTOCOL).addParameter(CATEGORY_KEY, category);
|
||||
urls.add(empty);
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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.registry.etcd;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.registry.Registry;
|
||||
import org.apache.dubbo.registry.support.AbstractRegistryFactory;
|
||||
import org.apache.dubbo.remoting.etcd.EtcdTransporter;
|
||||
|
||||
public class EtcdRegistryFactory extends AbstractRegistryFactory {
|
||||
|
||||
private EtcdTransporter etcdTransporter;
|
||||
|
||||
@Override
|
||||
protected Registry createRegistry(URL url) {
|
||||
return new EtcdRegistry(url, etcdTransporter);
|
||||
}
|
||||
|
||||
public void setEtcdTransporter(EtcdTransporter etcdTransporter) {
|
||||
this.etcdTransporter = etcdTransporter;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,208 +0,0 @@
|
|||
/*
|
||||
* 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.registry.etcd;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
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.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.common.utils.ConcurrentHashSet;
|
||||
import org.apache.dubbo.event.EventDispatcher;
|
||||
import org.apache.dubbo.event.EventListener;
|
||||
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.client.event.ServiceInstancesChangedEvent;
|
||||
import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;
|
||||
import org.apache.dubbo.remoting.etcd.ChildListener;
|
||||
import org.apache.dubbo.remoting.etcd.EtcdClient;
|
||||
import org.apache.dubbo.remoting.etcd.EtcdTransporter;
|
||||
import org.apache.dubbo.remoting.etcd.StateListener;
|
||||
import org.apache.dubbo.remoting.etcd.option.OptionUtil;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 2019-07-08
|
||||
*/
|
||||
public class EtcdServiceDiscovery implements ServiceDiscovery, EventListener<ServiceInstancesChangedEvent> {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(EtcdServiceDiscovery.class);
|
||||
|
||||
private final String root = "/services";
|
||||
|
||||
private final Set<String> services = new ConcurrentHashSet<>();
|
||||
private final Map<String, ChildListener> childListenerMap = new ConcurrentHashMap<>();
|
||||
|
||||
EtcdClient etcdClient;
|
||||
EventDispatcher dispatcher;
|
||||
ServiceInstance serviceInstance;
|
||||
|
||||
@Override
|
||||
public void onEvent(ServiceInstancesChangedEvent event) {
|
||||
registerServiceWatcher(event.getServiceName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(URL registryURL) throws Exception {
|
||||
|
||||
EtcdTransporter etcdTransporter = ExtensionLoader.getExtensionLoader(EtcdTransporter.class).getAdaptiveExtension();
|
||||
|
||||
if (registryURL.isAnyHost()) {
|
||||
throw new IllegalStateException("Service discovery address is invalid, actual: '" + registryURL.getHost() + "'");
|
||||
}
|
||||
|
||||
etcdClient = etcdTransporter.connect(registryURL);
|
||||
|
||||
etcdClient.addStateListener(state -> {
|
||||
if (state == StateListener.CONNECTED) {
|
||||
try {
|
||||
recover();
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.dispatcher = EventDispatcher.getDefaultExtension();
|
||||
this.dispatcher.addEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (etcdClient != null && etcdClient.isConnected()) {
|
||||
etcdClient.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(ServiceInstance serviceInstance) throws RuntimeException {
|
||||
try {
|
||||
this.serviceInstance = serviceInstance;
|
||||
String path = toPath(serviceInstance);
|
||||
// etcdClient.createEphemeral(path);
|
||||
etcdClient.putEphemeral(path, new Gson().toJson(serviceInstance));
|
||||
services.add(serviceInstance.getServiceName());
|
||||
} catch (Throwable e) {
|
||||
throw new RpcException("Failed to register " + serviceInstance + " to etcd " + etcdClient.getUrl()
|
||||
+ ", cause: " + (OptionUtil.isProtocolError(e)
|
||||
? "etcd3 registry may not be supported yet or etcd3 registry is not available."
|
||||
: e.getMessage()), e);
|
||||
}
|
||||
}
|
||||
|
||||
String toPath(ServiceInstance serviceInstance) {
|
||||
return root + File.separator + serviceInstance.getServiceName() + File.separator + serviceInstance.getHost()
|
||||
+ ":" + serviceInstance.getPort();
|
||||
}
|
||||
|
||||
String toParentPath(String serviceName) {
|
||||
return root + File.separator + serviceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(ServiceInstance serviceInstance) throws RuntimeException {
|
||||
try {
|
||||
String path = toPath(serviceInstance);
|
||||
etcdClient.putEphemeral(path, new Gson().toJson(serviceInstance));
|
||||
services.add(serviceInstance.getServiceName());
|
||||
} catch (Throwable e) {
|
||||
throw new RpcException("Failed to register " + serviceInstance + " to etcd " + etcdClient.getUrl()
|
||||
+ ", cause: " + (OptionUtil.isProtocolError(e)
|
||||
? "etcd3 registry may not be supported yet or etcd3 registry is not available."
|
||||
: e.getMessage()), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(ServiceInstance serviceInstance) throws RuntimeException {
|
||||
try {
|
||||
String path = toPath(serviceInstance);
|
||||
etcdClient.delete(path);
|
||||
services.remove(serviceInstance.getServiceName());
|
||||
this.serviceInstance = null;
|
||||
} catch (Throwable e) {
|
||||
throw new RpcException("Failed to unregister " + serviceInstance + " to etcd " + etcdClient.getUrl() + ", cause: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getServices() {
|
||||
return Collections.unmodifiableSet(services);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addServiceInstancesChangedListener(ServiceInstancesChangedListener listener) throws NullPointerException, IllegalArgumentException {
|
||||
registerServiceWatcher(listener.getServiceNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ServiceInstance> getInstances(String serviceName) {
|
||||
List<String> children = etcdClient.getChildren(toParentPath(serviceName));
|
||||
if (CollectionUtils.isEmpty(children)) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
List<ServiceInstance> list = new ArrayList<>(children.size());
|
||||
for (String child : children) {
|
||||
ServiceInstance serviceInstance = new Gson().fromJson(etcdClient.getKVValue(child), DefaultServiceInstance.class);
|
||||
list.add(serviceInstance);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
protected void registerServiceWatcher(String serviceName) {
|
||||
String path = root + File.separator + serviceName;
|
||||
/*
|
||||
* if we have no category watcher listener,
|
||||
* we find out the current listener or create one for the current category, put or get only once.
|
||||
*/
|
||||
ChildListener childListener =
|
||||
Optional.ofNullable(childListenerMap.get(serviceName))
|
||||
.orElseGet(() -> {
|
||||
ChildListener watchListener, prev;
|
||||
prev = childListenerMap.putIfAbsent(serviceName, watchListener = (parentPath, currentChildren) ->
|
||||
dispatchServiceInstancesChangedEvent(serviceName));
|
||||
return prev != null ? prev : watchListener;
|
||||
});
|
||||
|
||||
etcdClient.create(path);
|
||||
|
||||
etcdClient.addChildListener(path, childListener);
|
||||
}
|
||||
|
||||
private void recover() throws Exception {
|
||||
// register
|
||||
if (serviceInstance != null) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Recover application register: " + serviceInstance);
|
||||
}
|
||||
register(serviceInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
etcd3=org.apache.dubbo.registry.etcd.EtcdRegistryFactory
|
||||
|
|
@ -1 +0,0 @@
|
|||
etcd3=org.apache.dubbo.registry.etcd.EtcdServiceDiscovery
|
||||
|
|
@ -1,327 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.registry.etcd;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.registry.NotifyListener;
|
||||
import org.apache.dubbo.registry.RegistryFactory;
|
||||
import org.apache.dubbo.registry.support.AbstractRegistryFactory;
|
||||
import org.apache.dubbo.remoting.Constants;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
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.ENABLED_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_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.CONSUMERS_CATEGORY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;
|
||||
import static org.apache.dubbo.registry.Constants.ADMIN_PROTOCOL;
|
||||
|
||||
@Disabled
|
||||
public class EtcdRegistryTest {
|
||||
|
||||
String service = "org.apache.dubbo.internal.test.DemoServie";
|
||||
String outerService = "org.apache.dubbo.outer.test.OuterDemoServie";
|
||||
URL serviceUrl = URL.valueOf("dubbo://" + NetUtils.getLocalHost() + "/" + service + "?methods=test1,test2");
|
||||
URL serviceUrl2 = URL.valueOf("dubbo://" + NetUtils.getLocalHost() + "/" + service + "?methods=test1,test2,test3");
|
||||
URL serviceUrl3 = URL.valueOf("dubbo://" + NetUtils.getLocalHost() + "/" + outerService + "?methods=test1,test2");
|
||||
URL registryUrl = URL.valueOf("etcd3://127.0.0.1:2379/org.apache.dubbo.registry.RegistryService");
|
||||
URL consumerUrl = URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":2018" + "/" + service + "?methods=test1,test2");
|
||||
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
|
||||
EtcdRegistry registry;
|
||||
URL subscribe = new URL(
|
||||
ADMIN_PROTOCOL, NetUtils.getLocalHost(), 0, "",
|
||||
INTERFACE_KEY, ANY_VALUE,
|
||||
GROUP_KEY, ANY_VALUE,
|
||||
VERSION_KEY, ANY_VALUE,
|
||||
CLASSIFIER_KEY, ANY_VALUE,
|
||||
CATEGORY_KEY, PROVIDERS_CATEGORY + "," + CONSUMERS_CATEGORY + "," + ROUTERS_CATEGORY + "," + CONFIGURATORS_CATEGORY,
|
||||
ENABLED_KEY, ANY_VALUE,
|
||||
Constants.CHECK_KEY, String.valueOf(false));
|
||||
|
||||
@Test
|
||||
public void test_register() {
|
||||
|
||||
registry.register(serviceUrl);
|
||||
Set<URL> registered = registry.getRegistered();
|
||||
Assertions.assertEquals(1, registered.size());
|
||||
Assertions.assertTrue(registered.contains(serviceUrl));
|
||||
|
||||
registry.unregister(serviceUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_unregister() {
|
||||
|
||||
registry.register(serviceUrl);
|
||||
Set<URL> registered = registry.getRegistered();
|
||||
Assertions.assertEquals(1, registered.size());
|
||||
Assertions.assertTrue(registered.contains(serviceUrl));
|
||||
|
||||
registry.unregister(serviceUrl);
|
||||
|
||||
registered = registry.getRegistered();
|
||||
Assertions.assertEquals(0, registered.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_subscribe() {
|
||||
|
||||
registry.register(serviceUrl);
|
||||
|
||||
final AtomicReference<URL> notifiedUrl = new AtomicReference<URL>();
|
||||
registry.subscribe(consumerUrl, new NotifyListener() {
|
||||
public void notify(List<URL> urls) {
|
||||
notifiedUrl.set(urls.get(0));
|
||||
}
|
||||
});
|
||||
Assertions.assertEquals(serviceUrl.toFullString(), notifiedUrl.get().toFullString());
|
||||
Map<URL, Set<NotifyListener>> arg = registry.getSubscribed();
|
||||
Assertions.assertEquals(consumerUrl, arg.keySet().iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_subscribe_when_register() throws InterruptedException {
|
||||
|
||||
Assertions.assertEquals(0, registry.getRegistered().size());
|
||||
Assertions.assertEquals(0, registry.getSubscribed().size());
|
||||
|
||||
CountDownLatch notNotified = new CountDownLatch(2);
|
||||
|
||||
final AtomicReference<URL> notifiedUrl = new AtomicReference<URL>();
|
||||
registry.subscribe(consumerUrl, new NotifyListener() {
|
||||
public void notify(List<URL> urls) {
|
||||
notifiedUrl.set(urls.get(0));
|
||||
notNotified.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
registry.register(serviceUrl);
|
||||
|
||||
Assertions.assertTrue(notNotified.await(15, TimeUnit.SECONDS));
|
||||
|
||||
Assertions.assertEquals(serviceUrl.toFullString(), notifiedUrl.get().toFullString());
|
||||
Map<URL, Set<NotifyListener>> subscribed = registry.getSubscribed();
|
||||
Assertions.assertEquals(consumerUrl, subscribed.keySet().iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_subscribe_when_register0() throws InterruptedException {
|
||||
|
||||
Assertions.assertEquals(0, registry.getRegistered().size());
|
||||
Assertions.assertEquals(0, registry.getSubscribed().size());
|
||||
|
||||
CountDownLatch notNotified = new CountDownLatch(3);
|
||||
ConcurrentHashMap<URL, Boolean> notifiedUrls = new ConcurrentHashMap<>();
|
||||
registry.subscribe(consumerUrl, new NotifyListener() {
|
||||
public void notify(List<URL> urls) {
|
||||
if (urls != null && urls.size() > 0) {
|
||||
if (!urls.get(0).getProtocol().equals("empty")) {
|
||||
for (Iterator<URL> iterator = urls.iterator(); iterator.hasNext(); ) {
|
||||
notifiedUrls.put(iterator.next(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
notNotified.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
registry.register(serviceUrl);
|
||||
registry.register(serviceUrl2);
|
||||
|
||||
Assertions.assertTrue(notNotified.await(15, TimeUnit.SECONDS));
|
||||
|
||||
Assertions.assertTrue(notifiedUrls.containsKey(serviceUrl));
|
||||
Assertions.assertTrue(notifiedUrls.containsKey(serviceUrl2));
|
||||
Map<URL, Set<NotifyListener>> subscribed = registry.getSubscribed();
|
||||
Assertions.assertEquals(consumerUrl, subscribed.keySet().iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_subscribe_when_register1() throws InterruptedException {
|
||||
|
||||
Assertions.assertEquals(0, registry.getRegistered().size());
|
||||
Assertions.assertEquals(0, registry.getSubscribed().size());
|
||||
|
||||
CountDownLatch notNotified = new CountDownLatch(2);
|
||||
|
||||
final AtomicReference<URL> notifiedUrls = new AtomicReference<URL>();
|
||||
registry.subscribe(consumerUrl, new NotifyListener() {
|
||||
public void notify(List<URL> urls) {
|
||||
notifiedUrls.set(urls.get(0));
|
||||
notNotified.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
registry.register(serviceUrl);
|
||||
// register service3 should not trigger notify
|
||||
registry.register(serviceUrl3);
|
||||
|
||||
Assertions.assertTrue(notNotified.await(15, TimeUnit.SECONDS));
|
||||
|
||||
Assertions.assertEquals(serviceUrl, notifiedUrls.get());
|
||||
Map<URL, Set<NotifyListener>> subscribed = registry.getSubscribed();
|
||||
Assertions.assertEquals(consumerUrl, subscribed.keySet().iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_subscribe_when_register2() throws InterruptedException {
|
||||
|
||||
Assertions.assertEquals(0, registry.getRegistered().size());
|
||||
Assertions.assertEquals(0, registry.getSubscribed().size());
|
||||
|
||||
CountDownLatch notNotified = new CountDownLatch(3);
|
||||
|
||||
ConcurrentHashMap<URL, Boolean> notifiedUrls = new ConcurrentHashMap<>();
|
||||
|
||||
registry.subscribe(subscribe, new NotifyListener() {
|
||||
public void notify(List<URL> urls) {
|
||||
if (urls != null && urls.size() > 0) {
|
||||
if (!urls.get(0).getProtocol().equals("empty")) {
|
||||
for (Iterator<URL> iterator = urls.iterator(); iterator.hasNext(); ) {
|
||||
notifiedUrls.put(iterator.next(), true);
|
||||
}
|
||||
notNotified.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
registry.register(serviceUrl);
|
||||
registry.register(serviceUrl2);
|
||||
// service3 interface is not equals server2
|
||||
registry.register(serviceUrl3);
|
||||
|
||||
Assertions.assertTrue(notNotified.await(15, TimeUnit.SECONDS));
|
||||
Assertions.assertEquals(3, notifiedUrls.size());
|
||||
Assertions.assertTrue(notifiedUrls.containsKey(serviceUrl));
|
||||
Assertions.assertTrue(notifiedUrls.containsKey(serviceUrl2));
|
||||
Assertions.assertTrue(notifiedUrls.containsKey(serviceUrl3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_unsubscribe() throws InterruptedException {
|
||||
|
||||
Assertions.assertEquals(0, registry.getRegistered().size());
|
||||
Assertions.assertEquals(0, registry.getSubscribed().size());
|
||||
|
||||
CountDownLatch notNotified = new CountDownLatch(2);
|
||||
|
||||
final AtomicReference<URL> notifiedUrl = new AtomicReference<URL>();
|
||||
|
||||
NotifyListener listener = new NotifyListener() {
|
||||
public void notify(List<URL> urls) {
|
||||
if (urls != null) {
|
||||
for (Iterator<URL> iterator = urls.iterator(); iterator.hasNext(); ) {
|
||||
URL url = iterator.next();
|
||||
if (!url.getProtocol().equals("empty")) {
|
||||
notifiedUrl.set(url);
|
||||
notNotified.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
registry.subscribe(consumerUrl, listener);
|
||||
registry.unsubscribe(consumerUrl, listener);
|
||||
|
||||
registry.register(serviceUrl);
|
||||
|
||||
Assertions.assertFalse(notNotified.await(2, TimeUnit.SECONDS));
|
||||
// expect nothing happen
|
||||
Assertions.assertNull(notifiedUrl.get());
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
registry = (EtcdRegistry) registryFactory.getRegistry(registryUrl);
|
||||
Assertions.assertNotNull(registry);
|
||||
if (!registry.isAvailable()) {
|
||||
AbstractRegistryFactory.destroyAll();
|
||||
registry = (EtcdRegistry) registryFactory.getRegistry(registryUrl);
|
||||
}
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
|
||||
registry.unregister(serviceUrl);
|
||||
registry.unregister(serviceUrl2);
|
||||
registry.unregister(serviceUrl3);
|
||||
registry.unregister(subscribe);
|
||||
|
||||
registry.destroy();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
* 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.registry.etcd;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.registry.client.DefaultServiceInstance;
|
||||
import org.apache.dubbo.registry.client.ServiceInstance;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static java.lang.String.valueOf;
|
||||
|
||||
/**
|
||||
* 2019-08-30
|
||||
* <p>
|
||||
* There is no embedded server. so it works depend on etcd local server.
|
||||
*/
|
||||
@Disabled
|
||||
public class EtcdServiceDiscoveryTest {
|
||||
|
||||
static EtcdServiceDiscovery etcdServiceDiscovery;
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp() throws Exception {
|
||||
URL url = URL.valueOf("etcd3://127.0.0.1:2379/org.apache.dubbo.registry.RegistryService");
|
||||
etcdServiceDiscovery = new EtcdServiceDiscovery();
|
||||
Assertions.assertNull(etcdServiceDiscovery.etcdClient);
|
||||
etcdServiceDiscovery.initialize(url);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void destroy() throws Exception {
|
||||
// etcdServiceDiscovery.destroy();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLifecycle() throws Exception {
|
||||
URL url = URL.valueOf("etcd3://127.0.0.1:2233/org.apache.dubbo.registry.RegistryService");
|
||||
EtcdServiceDiscovery etcdServiceDiscoveryTmp = new EtcdServiceDiscovery();
|
||||
Assertions.assertNull(etcdServiceDiscoveryTmp.etcdClient);
|
||||
etcdServiceDiscoveryTmp.initialize(url);
|
||||
Assertions.assertNotNull(etcdServiceDiscoveryTmp.etcdClient);
|
||||
Assertions.assertTrue(etcdServiceDiscoveryTmp.etcdClient.isConnected());
|
||||
etcdServiceDiscoveryTmp.destroy();
|
||||
Assertions.assertFalse(etcdServiceDiscoveryTmp.etcdClient.isConnected());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistry() throws Exception {
|
||||
ServiceInstance serviceInstance = new DefaultServiceInstance(valueOf(System.nanoTime()), "EtcdTestService", "127.0.0.1", 8080);
|
||||
Assertions.assertNull(etcdServiceDiscovery.etcdClient.getKVValue(etcdServiceDiscovery.toPath(serviceInstance)));
|
||||
etcdServiceDiscovery.register(serviceInstance);
|
||||
Assertions.assertNotNull(etcdServiceDiscovery.etcdClient.getKVValue(etcdServiceDiscovery.toPath(serviceInstance)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnRegistry() throws Exception {
|
||||
ServiceInstance serviceInstance = new DefaultServiceInstance(valueOf(System.nanoTime()), "EtcdTest2Service", "127.0.0.1", 8080);
|
||||
Assertions.assertNull(etcdServiceDiscovery.etcdClient.getKVValue(etcdServiceDiscovery.toPath(serviceInstance)));
|
||||
etcdServiceDiscovery.register(serviceInstance);
|
||||
Assertions.assertNotNull(etcdServiceDiscovery.etcdClient.getKVValue(etcdServiceDiscovery.toPath(serviceInstance)));
|
||||
etcdServiceDiscovery.unregister(serviceInstance);
|
||||
Assertions.assertNull(etcdServiceDiscovery.etcdClient.getKVValue(etcdServiceDiscovery.toPath(serviceInstance)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate() throws Exception {
|
||||
DefaultServiceInstance serviceInstance = new DefaultServiceInstance(valueOf(System.nanoTime()), "EtcdTest34Service", "127.0.0.1", 8080);
|
||||
Assertions.assertNull(etcdServiceDiscovery.etcdClient.getKVValue(etcdServiceDiscovery.toPath(serviceInstance)));
|
||||
etcdServiceDiscovery.register(serviceInstance);
|
||||
Assertions.assertNotNull(etcdServiceDiscovery.etcdClient.getKVValue(etcdServiceDiscovery.toPath(serviceInstance)));
|
||||
Assertions.assertEquals(etcdServiceDiscovery.etcdClient.getKVValue(etcdServiceDiscovery.toPath(serviceInstance)),
|
||||
new Gson().toJson(serviceInstance));
|
||||
serviceInstance.setPort(9999);
|
||||
etcdServiceDiscovery.update(serviceInstance);
|
||||
Assertions.assertNotNull(etcdServiceDiscovery.etcdClient.getKVValue(etcdServiceDiscovery.toPath(serviceInstance)));
|
||||
Assertions.assertEquals(etcdServiceDiscovery.etcdClient.getKVValue(etcdServiceDiscovery.toPath(serviceInstance)),
|
||||
new Gson().toJson(serviceInstance));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetInstances() throws Exception {
|
||||
String serviceName = "EtcdTest77Service";
|
||||
Assertions.assertTrue(etcdServiceDiscovery.getInstances(serviceName).isEmpty());
|
||||
etcdServiceDiscovery.register(new DefaultServiceInstance(valueOf(System.nanoTime()), serviceName, "127.0.0.1", 8080));
|
||||
etcdServiceDiscovery.register(new DefaultServiceInstance(valueOf(System.nanoTime()), serviceName, "127.0.0.1", 9809));
|
||||
Assertions.assertFalse(etcdServiceDiscovery.getInstances(serviceName).isEmpty());
|
||||
List<String> r = convertToIpPort(etcdServiceDiscovery.getInstances(serviceName));
|
||||
Assertions.assertTrue(r.contains("127.0.0.1:8080"));
|
||||
Assertions.assertTrue(r.contains("127.0.0.1:9809"));
|
||||
}
|
||||
|
||||
private List<String> convertToIpPort(List<ServiceInstance> serviceInstances) {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (ServiceInstance serviceInstance : serviceInstances) {
|
||||
result.add(serviceInstance.getHost() + ":" + serviceInstance.getPort());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>dubbo-registry-eureka</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>The Eureka registry module of Dubbo project</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Eureka -->
|
||||
<dependency>
|
||||
<groupId>com.netflix.eureka</groupId>
|
||||
<artifactId>eureka-client</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>javax.ws.rs</groupId>
|
||||
<artifactId>jsr311-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>javax.ws.rs</groupId>-->
|
||||
<!-- <artifactId>javax.ws.rs-api</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
<version>1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.eureka</groupId>
|
||||
<artifactId>eureka-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Eureka core deps that are now optional -->
|
||||
<dependency>
|
||||
<groupId>com.thoughtworks.xstream</groupId>
|
||||
<artifactId>xstream</artifactId>
|
||||
<version>1.4.10</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.contribs</groupId>
|
||||
<artifactId>jersey-apache-client4</artifactId>
|
||||
<version>1.19.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.archaius</groupId>
|
||||
<artifactId>archaius-core</artifactId>
|
||||
<version>0.7.6</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue