diff --git a/.travis.yml b/.travis.yml index 6db1bd99291..9764b2b5df2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,4 @@ jdk: - oraclejdk8 - openjdk7 -script: mvn -DskipTests=true clean package +script: mvn clean package diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000000..dd9ba965c18 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,25 @@ + +## Contributing to dubbo +Dubbo is released under the non-restrictive Apache 2.0 license, and follows a very standard Github development process, using Github tracker for issues and merging pull requests into master. If you want to contribute even something trivial please do not hesitate, but follow the guidelines below. +### Sign the Contributor License Agreement +Before we accept a non-trivial patch or pull request we will need you to sign the Contributor License Agreement. Signing the contributor’s agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. Active contributors might be asked to join the core team, and given the ability to merge pull requests. +### Code Conventions +Our code style is almost in line with the standard java conventions(Popular IDE's default setting satisfy this), only changed the following two restricts: +1. Classes under 'com.alibaba.*' and 'com.taobao.*' package are grouped separately, and put on top of all other 'imports'. +2. If there are more than 120 characters in current line, start a new line. + +We provide a template file [dubbo_codestyle_for_idea.xml](https://github.com/alibaba/dubbo/tree/master/codestyle/dubbo_codestyle_for_idea.xml) for IntelliJ idea, you can import it to you IDE. If you use Eclipse you can config manually by referencing the same file. + +* Make sure all new .java files to have a simple Javadoc class comment with at least an @author tag identifying you, and a @date tag identifying birth, and preferably at least a paragraph on what the class is for. + +* Add the ASF license header comment to all new .java files (copy from existing files in the project) + +* Add yourself as an @author to the .java files that you modify substantially (more than cosmetic changes). + +* Add some Javadocs and, if you change the namespace, some XSD doc elements. + +* A few unit tests should be added for a new feature or an important bugfix. + +* If no-one else is using your branch, please rebase it against the current master (or other target branch in the main project). + +* When writing a commit message please follow these conventions, if you are fixing an existing issue please add Fixes #XXX at the end of the commit message (where XXX is the issue number). diff --git a/dubbo-admin/pom.xml b/dubbo-admin/pom.xml index 1349216a681..0222ff7974b 100644 --- a/dubbo-admin/pom.xml +++ b/dubbo-admin/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-parent - 2.5.6 + 2.5.7 dubbo-admin war @@ -170,6 +170,10 @@ javax.cache cache-api + + org.apache.velocity + velocity + diff --git a/dubbo-admin/src/main/java/com/alibaba/dubbo/governance/service/impl/OverrideServiceImpl.java b/dubbo-admin/src/main/java/com/alibaba/dubbo/governance/service/impl/OverrideServiceImpl.java index e7bb310f58f..6140d52d8c6 100644 --- a/dubbo-admin/src/main/java/com/alibaba/dubbo/governance/service/impl/OverrideServiceImpl.java +++ b/dubbo-admin/src/main/java/com/alibaba/dubbo/governance/service/impl/OverrideServiceImpl.java @@ -75,7 +75,7 @@ public void enableOverride(Long id) { return; } - URL newOverride = oldOverride.addParameter("enabled", "enabled"); + URL newOverride = oldOverride.addParameter("enabled", true); registryService.unregister(oldOverride); registryService.register(newOverride); diff --git a/dubbo-cluster/pom.xml b/dubbo-cluster/pom.xml index 00e9c835358..e3e58429b06 100644 --- a/dubbo-cluster/pom.xml +++ b/dubbo-cluster/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-parent - 2.5.6 + 2.5.7 dubbo-cluster jar diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ClusterUtils.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ClusterUtils.java index 47bc39e9683..6867d3cab72 100644 --- a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ClusterUtils.java +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ClusterUtils.java @@ -57,6 +57,9 @@ public static URL mergeUrl(URL remoteUrl, Map localMap) { map.remove(Constants.ALIVE_KEY); map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.ALIVE_KEY); + + map.remove(Constants.TRANSPORTER_KEY); + map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.TRANSPORTER_KEY); } if (localMap != null && localMap.size() > 0) { @@ -81,7 +84,10 @@ public static URL mergeUrl(URL remoteUrl, Map localMap) { map.put(Constants.METHODS_KEY, methods); } // 保留provider的启动timestamp - map.put(Constants.REMOTE_TIMESTAMP_KEY, remoteMap.get(Constants.TIMESTAMP_KEY)); + String remoteTimestamp = remoteMap.get(Constants.TIMESTAMP_KEY); + if (remoteTimestamp != null && remoteTimestamp.length() > 0) { + map.put(Constants.REMOTE_TIMESTAMP_KEY, remoteMap.get(Constants.TIMESTAMP_KEY)); + } // 合并filter和listener String remoteFilter = remoteMap.get(Constants.REFERENCE_FILTER_KEY); String localFilter = localMap.get(Constants.REFERENCE_FILTER_KEY); diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorTest.java index cfbf565ee62..9eaf912aba2 100644 --- a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorTest.java +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorTest.java @@ -16,6 +16,7 @@ package com.alibaba.dubbo.rpc.cluster.configurator.absent; import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; import junit.framework.Assert; import org.junit.Test; @@ -31,33 +32,35 @@ public class AbsentConfiguratorTest { public void testOverride_Application() { AbsentConfigurator configurator = new AbsentConfigurator(URL.valueOf("override://foo@0.0.0.0/com.foo.BarService?timeout=200")); - URL url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo")); + URL url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo&side=consumer")); Assert.assertEquals("200", url.getParameter("timeout")); - url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo&timeout=1000")); + url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo&timeout=1000&side=consumer")); Assert.assertEquals("1000", url.getParameter("timeout")); - url = configurator.configure(URL.valueOf("dubbo://10.20.153.11:20880/com.foo.BarService?application=bar")); + url = configurator.configure(URL.valueOf("dubbo://10.20.153.11:20880/com.foo.BarService?application=bar&side=consumer")); Assert.assertNull(url.getParameter("timeout")); - url = configurator.configure(URL.valueOf("dubbo://10.20.153.11:20880/com.foo.BarService?application=bar&timeout=1000")); + url = configurator.configure(URL.valueOf("dubbo://10.20.153.11:20880/com.foo.BarService?application=bar&timeout=1000&side=consumer")); Assert.assertEquals("1000", url.getParameter("timeout")); } @Test public void testOverride_Host() { - AbsentConfigurator configurator = new AbsentConfigurator(URL.valueOf("override://10.20.153.10/com.foo.BarService?timeout=200")); + AbsentConfigurator configurator = new AbsentConfigurator(URL.valueOf("override://" + NetUtils.getLocalHost() + "/com.foo.BarService?timeout=200")); - URL url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo")); + URL url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo&side=consumer")); Assert.assertEquals("200", url.getParameter("timeout")); - url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo&timeout=1000")); + url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo&timeout=1000&side=consumer")); Assert.assertEquals("1000", url.getParameter("timeout")); - url = configurator.configure(URL.valueOf("dubbo://10.20.153.11:20880/com.foo.BarService?application=bar")); + AbsentConfigurator configurator1 = new AbsentConfigurator(URL.valueOf("override://10.20.153.10/com.foo.BarService?timeout=200")); + + url = configurator1.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=bar&side=consumer")); Assert.assertNull(url.getParameter("timeout")); - url = configurator.configure(URL.valueOf("dubbo://10.20.153.11:20880/com.foo.BarService?application=bar&timeout=1000")); + url = configurator1.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=bar&timeout=1000&side=consumer")); Assert.assertEquals("1000", url.getParameter("timeout")); } diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorTest.java index 670a97ec9c0..4f7f90773f6 100644 --- a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorTest.java +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorTest.java @@ -16,6 +16,8 @@ package com.alibaba.dubbo.rpc.cluster.configurator.override; import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.rpc.cluster.configurator.absent.AbsentConfigurator; import junit.framework.Assert; import org.junit.Test; @@ -31,33 +33,35 @@ public class OverrideConfiguratorTest { public void testOverride_Application() { OverrideConfigurator configurator = new OverrideConfigurator(URL.valueOf("override://foo@0.0.0.0/com.foo.BarService?timeout=200")); - URL url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo")); + URL url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo&side=consumer")); Assert.assertEquals("200", url.getParameter("timeout")); - url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo&timeout=1000")); + url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo&timeout=1000&side=consumer")); Assert.assertEquals("200", url.getParameter("timeout")); - url = configurator.configure(URL.valueOf("dubbo://10.20.153.11:20880/com.foo.BarService?application=bar")); + url = configurator.configure(URL.valueOf("dubbo://10.20.153.11:20880/com.foo.BarService?application=bar&side=consumer")); Assert.assertNull(url.getParameter("timeout")); - url = configurator.configure(URL.valueOf("dubbo://10.20.153.11:20880/com.foo.BarService?application=bar&timeout=1000")); + url = configurator.configure(URL.valueOf("dubbo://10.20.153.11:20880/com.foo.BarService?application=bar&timeout=1000&side=consumer")); Assert.assertEquals("1000", url.getParameter("timeout")); } @Test public void testOverride_Host() { - OverrideConfigurator configurator = new OverrideConfigurator(URL.valueOf("override://10.20.153.10/com.foo.BarService?timeout=200")); + OverrideConfigurator configurator = new OverrideConfigurator(URL.valueOf("override://" + NetUtils.getLocalHost() + "/com.foo.BarService?timeout=200")); - URL url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo")); + URL url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo&side=consumer")); Assert.assertEquals("200", url.getParameter("timeout")); - url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo&timeout=1000")); + url = configurator.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=foo&timeout=1000&side=consumer")); Assert.assertEquals("200", url.getParameter("timeout")); - url = configurator.configure(URL.valueOf("dubbo://10.20.153.11:20880/com.foo.BarService?application=bar")); + AbsentConfigurator configurator1 = new AbsentConfigurator(URL.valueOf("override://10.20.153.10/com.foo.BarService?timeout=200")); + + url = configurator1.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=bar&side=consumer")); Assert.assertNull(url.getParameter("timeout")); - url = configurator.configure(URL.valueOf("dubbo://10.20.153.11:20880/com.foo.BarService?application=bar&timeout=1000")); + url = configurator1.configure(URL.valueOf("dubbo://10.20.153.10:20880/com.foo.BarService?application=bar&timeout=1000&side=consumer")); Assert.assertEquals("1000", url.getParameter("timeout")); } diff --git a/dubbo-common/pom.xml b/dubbo-common/pom.xml index 4ec939b68da..6ab4d4d5e1f 100644 --- a/dubbo-common/pom.xml +++ b/dubbo-common/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-parent - 2.5.6 + 2.5.7 dubbo-common jar @@ -54,7 +54,6 @@ com.alibaba fastjson - provided org.jvnet.sorcerer diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java index b12c632039c..53c4b48649f 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java @@ -582,6 +582,20 @@ public class Constants { public static final String GENERIC_SERIALIZATION_BEAN = "bean"; + public static final String DUBBO_IP_TO_REGISTRY = "DUBBO_IP_TO_REGISTRY"; + + public static final String DUBBO_PORT_TO_REGISTRY = "DUBBO_PORT_TO_REGISTRY"; + + public static final String DUBBO_IP_TO_BIND = "DUBBO_IP_TO_BIND"; + + public static final String DUBBO_PORT_TO_BIND = "DUBBO_PORT_TO_BIND"; + + public static final String BIND_IP_KEY = "bind.ip"; + + public static final String BIND_PORT_KEY = "bind.port"; + + public static final String REGISTER_IP_KEY = "register.ip"; + /* * private Constants(){ } */ diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/concurrent/ExecutionList.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/concurrent/ExecutionList.java new file mode 100644 index 00000000000..5a1448581dd --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/concurrent/ExecutionList.java @@ -0,0 +1,168 @@ +package com.alibaba.dubbo.common.concurrent; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; + +import java.util.concurrent.Executor; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + *

A list of listeners, each with an associated {@code Executor}, that + * guarantees that every {@code Runnable} that is {@linkplain #add added} will + * be executed after {@link #execute()} is called. Any {@code Runnable} added + * after the call to {@code execute} is still guaranteed to execute. There is no + * guarantee, however, that listeners will be executed in the order that they + * are added. + *

+ *

Exceptions thrown by a listener will be propagated up to the executor. + * Any exception thrown during {@code Executor.execute} (e.g., a {@code + * RejectedExecutionException} or an exception thrown by {@linkplain + * MoreExecutors#sameThreadExecutor inline execution}) will be caught and + * logged. + * + * @author Nishant Thakkar + * @author Sven Mawson + * @since 1.0 + */ +public final class ExecutionList { + // Logger to log exceptions caught when running runnables. + static final Logger logger = LoggerFactory.getLogger(ExecutionList.class.getName()); + + /** + * The runnable, executor pairs to execute. This acts as a stack threaded through the + * {@link RunnableExecutorPair#next} field. + */ + private RunnableExecutorPair runnables; + + private boolean executed; + + private static final Executor DEFAULT_EXECUTOR = new ThreadPoolExecutor(1, 10, 60000L, TimeUnit.MILLISECONDS, new SynchronousQueue(), new NamedThreadFactory("DubboFutureCallbackDefault", true)); + + /** + * Creates a new, empty {@link ExecutionList}. + */ + public ExecutionList() { + } + + /** + * Adds the {@code Runnable} and accompanying {@code Executor} to the list of + * listeners to execute. If execution has already begun, the listener is + * executed immediately. + *

+ *

Note: For fast, lightweight listeners that would be safe to execute in + * any thread, consider {@link MoreExecutors#sameThreadExecutor}. For heavier + * listeners, {@code sameThreadExecutor()} carries some caveats: First, the + * thread that the listener runs in depends on whether the {@code + * ExecutionList} has been executed at the time it is added. In particular, + * listeners may run in the thread that calls {@code add}. Second, the thread + * that calls {@link #execute} may be an internal implementation thread, such + * as an RPC network thread, and {@code sameThreadExecutor()} listeners may + * run in this thread. Finally, during the execution of a {@code + * sameThreadExecutor} listener, all other registered but unexecuted + * listeners are prevented from running, even if those listeners are to run + * in other executors. + */ + public void add(Runnable runnable, Executor executor) { + // Fail fast on a null. We throw NPE here because the contract of + // Executor states that it throws NPE on null listener, so we propagate + // that contract up into the add method as well. + if (runnable == null) { + throw new NullPointerException("Runnable can not be null!"); + } + if (executor == null) { + logger.info("Executor for listenablefuture is null, will use default executor!"); + executor = DEFAULT_EXECUTOR; + } + // Lock while we check state. We must maintain the lock while adding the + // new pair so that another thread can't run the list out from under us. + // We only add to the list if we have not yet started execution. + synchronized (this) { + if (!executed) { + runnables = new RunnableExecutorPair(runnable, executor, runnables); + return; + } + } + // Execute the runnable immediately. Because of scheduling this may end up + // getting called before some of the previously added runnables, but we're + // OK with that. If we want to change the contract to guarantee ordering + // among runnables we'd have to modify the logic here to allow it. + executeListener(runnable, executor); + } + + /** + * Runs this execution list, executing all existing pairs in the order they + * were added. However, note that listeners added after this point may be + * executed before those previously added, and note that the execution order + * of all listeners is ultimately chosen by the implementations of the + * supplied executors. + *

+ *

This method is idempotent. Calling it several times in parallel is + * semantically equivalent to calling it exactly once. + * + * @since 10.0 (present in 1.0 as {@code run}) + */ + public void execute() { + // Lock while we update our state so the add method above will finish adding + // any listeners before we start to run them. + RunnableExecutorPair list; + synchronized (this) { + if (executed) { + return; + } + executed = true; + list = runnables; + runnables = null; // allow GC to free listeners even if this stays around for a while. + } + // If we succeeded then list holds all the runnables we to execute. The pairs in the stack are + // in the opposite order from how they were added so we need to reverse the list to fulfill our + // contract. + // This is somewhat annoying, but turns out to be very fast in practice. Alternatively, we + // could drop the contract on the method that enforces this queue like behavior since depending + // on it is likely to be a bug anyway. + + // N.B. All writes to the list and the next pointers must have happened before the above + // synchronized block, so we can iterate the list without the lock held here. + RunnableExecutorPair reversedList = null; + while (list != null) { + RunnableExecutorPair tmp = list; + list = list.next; + tmp.next = reversedList; + reversedList = tmp; + } + while (reversedList != null) { + executeListener(reversedList.runnable, reversedList.executor); + reversedList = reversedList.next; + } + } + + /** + * Submits the given runnable to the given {@link Executor} catching and logging all + * {@linkplain RuntimeException runtime exceptions} thrown by the executor. + */ + private static void executeListener(Runnable runnable, Executor executor) { + try { + executor.execute(runnable); + } catch (RuntimeException e) { + // Log it and keep going, bad runnable and/or executor. Don't + // punish the other runnables if we're given a bad one. We only + // catch RuntimeException because we want Errors to propagate up. + logger.error("RuntimeException while executing runnable " + + runnable + " with executor " + executor, e); + } + } + + private static final class RunnableExecutorPair { + final Runnable runnable; + final Executor executor; + RunnableExecutorPair next; + + RunnableExecutorPair(Runnable runnable, Executor executor, RunnableExecutorPair next) { + this.runnable = runnable; + this.executor = executor; + this.next = next; + } + } +} diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/concurrent/ListenableFuture.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/concurrent/ListenableFuture.java new file mode 100644 index 00000000000..1600b300798 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/concurrent/ListenableFuture.java @@ -0,0 +1,121 @@ +package com.alibaba.dubbo.common.concurrent; + +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.RejectedExecutionException; + +/** + * A {@link Future} that accepts completion listeners. Each listener has an + * associated executor, and it is invoked using this executor once the future's + * computation is {@linkplain Future#isDone() complete}. If the computation has + * already completed when the listener is added, the listener will execute + * immediately. + *

+ *

See the Guava User Guide article on + * {@code ListenableFuture}. + *

+ *

Purpose

+ *

+ *

Most commonly, {@code ListenableFuture} is used as an input to another + * derived {@code Future}, as in {@link Futures#allAsList(Iterable) + * Futures.allAsList}. Many such methods are impossible to implement efficiently + * without listener support. + *

+ *

It is possible to call {@link #addListener addListener} directly, but this + * is uncommon because the {@code Runnable} interface does not provide direct + * access to the {@code Future} result. (Users who want such access may prefer + * {@link Futures#addCallback Futures.addCallback}.) Still, direct {@code + * addListener} calls are occasionally useful:

   {@code
+ *   final String name = ...;
+ *   inFlight.add(name);
+ *   ListenableFuture future = service.query(name);
+ *   future.addListener(new Runnable() {
+ *     public void run() {
+ *       processedCount.incrementAndGet();
+ *       inFlight.remove(name);
+ *       lastProcessed.set(name);
+ *       logger.info("Done with {0}", name);
+ *     }
+ *   }, executor);}
+ *

+ *

How to get an instance

+ *

+ *

Developers are encouraged to return {@code ListenableFuture} from their + * methods so that users can take advantages of the utilities built atop the + * class. The way that they will create {@code ListenableFuture} instances + * depends on how they currently create {@code Future} instances: + *

    + *
  • If they are returned from an {@code ExecutorService}, convert that + * service to a {@link ListeningExecutorService}, usually by calling {@link + * MoreExecutors#listeningDecorator(ExecutorService) + * MoreExecutors.listeningDecorator}. (Custom executors may find it more + * convenient to use {@link ListenableFutureTask} directly.) + *
  • If they are manually filled in by a call to {@link FutureTask#set} or a + * similar method, create a {@link SettableFuture} instead. (Users with more + * complex needs may prefer {@link AbstractFuture}.) + *
+ *

+ *

Occasionally, an API will return a plain {@code Future} and it will be + * impossible to change the return type. For this case, we provide a more + * expensive workaround in {@code JdkFutureAdapters}. However, when possible, it + * is more efficient and reliable to create a {@code ListenableFuture} directly. + * + * @author Sven Mawson + * @author Nishant Thakkar + * @since 1.0 + */ +public interface ListenableFuture extends Future { + /** + * Registers a listener to be {@linkplain Executor#execute(Runnable) run} on + * the given executor. The listener will run when the {@code Future}'s + * computation is {@linkplain Future#isDone() complete} or, if the computation + * is already complete, immediately. + *

+ *

There is no guaranteed ordering of execution of listeners, but any + * listener added through this method is guaranteed to be called once the + * computation is complete. + *

+ *

Exceptions thrown by a listener will be propagated up to the executor. + * Any exception thrown during {@code Executor.execute} (e.g., a {@code + * RejectedExecutionException} or an exception thrown by {@linkplain + * MoreExecutors#sameThreadExecutor inline execution}) will be caught and + * logged. + *

+ *

Note: For fast, lightweight listeners that would be safe to execute in + * any thread, consider {@link MoreExecutors#sameThreadExecutor}. For heavier + * listeners, {@code sameThreadExecutor()} carries some caveats. For + * example, the listener may run on an unpredictable or undesirable thread: + *

+ *

    + *
  • If this {@code Future} is done at the time {@code addListener} is + * called, {@code addListener} will execute the listener inline. + *
  • If this {@code Future} is not yet done, {@code addListener} will + * schedule the listener to be run by the thread that completes this {@code + * Future}, which may be an internal system thread such as an RPC network + * thread. + *
+ *

+ *

Also note that, regardless of which thread executes the + * {@code sameThreadExecutor()} listener, all other registered but unexecuted + * listeners are prevented from running during its execution, even if those + * listeners are to run in other executors. + *

+ *

This is the most general listener interface. For common operations + * performed using listeners, see {@link + * com.google.common.util.concurrent.Futures}. For a simplified but general + * listener interface, see {@link + * com.google.common.util.concurrent.Futures#addCallback addCallback()}. + * + * @param listener the listener to run when the computation is complete + * @param executor the executor to run the listener in + * @throws NullPointerException if the executor or listener was null + * @throws RejectedExecutionException if we tried to execute the listener + * immediately but the executor rejected it. + */ + void addListener(Runnable listener, Executor executor); + + void addListener(Runnable listener); +} diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/concurrent/ListenableFutureTask.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/concurrent/ListenableFutureTask.java new file mode 100644 index 00000000000..538d05c983e --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/concurrent/ListenableFutureTask.java @@ -0,0 +1,80 @@ +package com.alibaba.dubbo.common.concurrent; + +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.FutureTask; + +/** + * A {@link FutureTask} that also implements the {@link ListenableFuture} + * interface. Unlike {@code FutureTask}, {@code ListenableFutureTask} does not + * provide an overrideable {@link FutureTask#done() done()} method. For similar + * functionality, call {@link #addListener}. + *

+ *

+ * + * @author Sven Mawson + * @since 1.0 + */ +public class ListenableFutureTask extends FutureTask + implements ListenableFuture { + // TODO(cpovirk): explore ways of making ListenableFutureTask final. There are + // some valid reasons such as BoundedQueueExecutorService to allow extends but it + // would be nice to make it final to avoid unintended usage. + + // The execution list to hold our listeners. + private final ExecutionList executionList = new ExecutionList(); + + /** + * Creates a {@code ListenableFutureTask} that will upon running, execute the + * given {@code Callable}. + * + * @param callable the callable task + * @since 10.0 + */ + public static ListenableFutureTask create(Callable callable) { + return new ListenableFutureTask(callable); + } + + /** + * Creates a {@code ListenableFutureTask} that will upon running, execute the + * given {@code Runnable}, and arrange that {@code get} will return the + * given result on successful completion. + * + * @param runnable the runnable task + * @param result the result to return on successful completion. If you don't + * need a particular result, consider using constructions of the form: + * {@code ListenableFuture f = ListenableFutureTask.create(runnable, + * null)} + * @since 10.0 + */ + public static ListenableFutureTask create( + Runnable runnable, V result) { + return new ListenableFutureTask(runnable, result); + } + + ListenableFutureTask(Callable callable) { + super(callable); + } + + ListenableFutureTask(Runnable runnable, V result) { + super(runnable, result); + } + + @Override + public void addListener(Runnable listener, Executor exec) { + executionList.add(listener, exec); + } + + @Override + public void addListener(Runnable listener) { + executionList.add(listener, null); + } + + /** + * Internal implementation detail used to invoke the listeners. + */ + @Override + protected void done() { + executionList.execute(); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/GenericJSONConverter.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/GenericJSONConverter.java index f0cb594b05d..35542ceb277 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/GenericJSONConverter.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/GenericJSONConverter.java @@ -31,6 +31,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +@Deprecated public class GenericJSONConverter implements JSONConverter { private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; private static final Map, Encoder> GlobalEncoderMap = new HashMap, Encoder>(); diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/J2oVisitor.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/J2oVisitor.java index 2f27395271f..d2b352a9e4b 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/J2oVisitor.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/J2oVisitor.java @@ -36,7 +36,7 @@ * * @author qian.lei. */ - +@Deprecated class J2oVisitor implements JSONVisitor { public static final boolean[] EMPTY_BOOL_ARRAY = new boolean[0]; diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSON.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSON.java index e54f4bad5fc..0cba4a250a3 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSON.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSON.java @@ -29,7 +29,7 @@ * * @author qian.lei */ - +@Deprecated public class JSON { public static final char LBRACE = '{', RBRACE = '}'; diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONArray.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONArray.java index 1fc645d23ca..8b96ff1d2c5 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONArray.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONArray.java @@ -25,7 +25,7 @@ * * @author qian.lei */ - +@Deprecated public class JSONArray implements JSONNode { private List mArray = new ArrayList(); diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONConverter.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONConverter.java index e550c3235e8..c29fcf8e096 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONConverter.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONConverter.java @@ -22,7 +22,7 @@ * * @author qianlei */ - +@Deprecated public interface JSONConverter { /** * write object. diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONNode.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONNode.java index 4d546e45fee..aa8531e119f 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONNode.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONNode.java @@ -22,7 +22,7 @@ * * @author qian.lei */ - +@Deprecated interface JSONNode { /** * write json string. diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONObject.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONObject.java index 6b2defde016..680b965171e 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONObject.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONObject.java @@ -25,7 +25,7 @@ * * @author qian.lei */ - +@Deprecated public class JSONObject implements JSONNode { private Map mMap = new HashMap(); diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONReader.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONReader.java index 4e1728e2993..ae760ebf229 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONReader.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONReader.java @@ -26,7 +26,7 @@ * * @author qian.lei */ - +@Deprecated public class JSONReader { private static ThreadLocal LOCAL_LEXER = new ThreadLocal() { }; diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONToken.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONToken.java index 4154b37dcae..bfdab9cf76b 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONToken.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONToken.java @@ -20,7 +20,7 @@ * * @author qian.lei */ - +@Deprecated public class JSONToken { // token type public static final int ANY = 0, IDENT = 0x01, LBRACE = 0x02, LSQUARE = 0x03, RBRACE = 0x04, RSQUARE = 0x05, COMMA = 0x06, COLON = 0x07; diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONVisitor.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONVisitor.java index 337ecceb642..7c27bd1d1c8 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONVisitor.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONVisitor.java @@ -20,7 +20,7 @@ * * @author qian.lei */ - +@Deprecated public interface JSONVisitor { public static final String CLASS_PROPERTY = "class"; diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONWriter.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONWriter.java index ced85f9707a..c62fb09a5b9 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONWriter.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONWriter.java @@ -30,7 +30,7 @@ * * @author qian.lei */ - +@Deprecated public class JSONWriter { private static final byte UNKNOWN = 0, ARRAY = 1, OBJECT = 2, OBJECT_VALUE = 3; private static final String[] CONTROL_CHAR_MAP = new String[]{ diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/ParseException.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/ParseException.java index 64e009cfeb9..6785721550b 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/ParseException.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/ParseException.java @@ -20,7 +20,7 @@ * * @author qian.lei */ - +@Deprecated public class ParseException extends Exception { private static final long serialVersionUID = 8611884051738966316L; diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/Yylex.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/Yylex.java index 36992aee561..7471a2a83d7 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/Yylex.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/Yylex.java @@ -21,6 +21,7 @@ * on 7/3/10 3:12 AM from the specification file * /Users/qianlei/dev/proj/dubbo-1.1/dubbo.common/src/main/java/com/alibaba/dubbo/common/json/json.flex */ +@Deprecated public class Yylex { /** diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonObjectInput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonObjectInput.java index b2b5c89157a..a250e0dba2b 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonObjectInput.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonObjectInput.java @@ -35,6 +35,7 @@ * @author william.liangf * @author ding.lid */ +@Deprecated public class JsonObjectInput implements ObjectInput { private final BufferedReader reader; diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonObjectOutput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonObjectOutput.java index eeb35b63eec..fb9710ed588 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonObjectOutput.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonObjectOutput.java @@ -29,6 +29,7 @@ * * @author william.liangf */ +@Deprecated public class JsonObjectOutput implements ObjectOutput { private final PrintWriter writer; diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonSerialization.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonSerialization.java index 7243d9e27a3..585bf50040d 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonSerialization.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonSerialization.java @@ -29,6 +29,7 @@ * * @author william.liangf */ +@Deprecated public class JsonSerialization implements Serialization { public byte getContentTypeId() { diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/support/AbortPolicyWithReport.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/support/AbortPolicyWithReport.java index 14ec9d2ee75..295872de5db 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/support/AbortPolicyWithReport.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/support/AbortPolicyWithReport.java @@ -83,7 +83,18 @@ private void dumpJStack() { @Override public void run() { String dumpPath = url.getParameter(Constants.DUMP_DIRECTORY, System.getProperty("user.home")); - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss"); + + SimpleDateFormat sdf; + + String OS = System.getProperty("os.name").toLowerCase(); + + // window system don't support ":" in file name + if(OS.contains("win")){ + sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); + }else { + sdf = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss"); + } + String dateStr = sdf.format(new Date()); FileOutputStream jstackStream = null; try { diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Assert.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Assert.java index bda7c4b60cc..333f3e7d7d8 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Assert.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Assert.java @@ -30,4 +30,10 @@ public static void notNull(Object obj, String message) { } } + public static void notNull(Object obj, RuntimeException exeception) { + if (obj == null) { + throw exeception; + } + } + } diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ConfigUtils.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ConfigUtils.java index 5febdb82f0d..145a7cb5807 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ConfigUtils.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ConfigUtils.java @@ -186,6 +186,20 @@ public static String getProperty(String key, String defaultValue) { return replaceProperty(properties.getProperty(key, defaultValue), (Map) properties); } + /** + *  系统环境变量 -> java命令参数-D + * + * @param key + * @return + */ + public static String getSystemProperty(String key) { + String value = System.getenv(key); + if (value == null || value.length() == 0) { + value = System.getProperty(key); + } + return value; + } + public static Properties loadProperties(String fileName) { return loadProperties(fileName, false, false); } diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/DubboAppender.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/DubboAppender.java index 797e69da9e8..87ab12fda06 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/DubboAppender.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/DubboAppender.java @@ -41,7 +41,7 @@ public static void clear() { public void append(LoggingEvent event) { super.append(event); - if (available == true) { + if (available) { Log temp = parseLog(event); logList.add(temp); } @@ -56,4 +56,4 @@ private Log parseLog(LoggingEvent event) { return log; } -} \ No newline at end of file +} diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/PojoUtils.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/PojoUtils.java index 2a277413932..a02ca949891 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/PojoUtils.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/PojoUtils.java @@ -412,12 +412,16 @@ private static Object realize0(Object pojo, Class type, Type genericType, fin Class keyClazz; if (keyType instanceof Class) { keyClazz = (Class) keyType; + } else if (keyType instanceof ParameterizedType) { + keyClazz = (Class) ((ParameterizedType) keyType).getRawType(); } else { keyClazz = entry.getKey() == null ? null : entry.getKey().getClass(); } Class valueClazz; if (valueType instanceof Class) { valueClazz = (Class) valueType; + } else if (valueType instanceof ParameterizedType) { + valueClazz = (Class) ((ParameterizedType) valueType).getRawType(); } else { valueClazz = entry.getValue() == null ? null : entry.getValue().getClass(); } diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/StringUtils.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/StringUtils.java index f4f4436dde8..2926db712f0 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/StringUtils.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/StringUtils.java @@ -17,11 +17,10 @@ import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.io.UnsafeStringWriter; -import com.alibaba.dubbo.common.json.JSON; +import com.alibaba.fastjson.JSON; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; -import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; @@ -420,8 +419,8 @@ public static String toArgumentString(Object[] args) { buf.append(arg); } else { try { - buf.append(JSON.json(arg)); - } catch (IOException e) { + buf.append(JSON.toJSONString(arg)); + } catch (Exception e) { logger.warn(e.getMessage(), e); buf.append(arg); } diff --git a/dubbo-common/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.common.serialize.Serialization b/dubbo-common/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.common.serialize.Serialization index ca493e45799..01fb3035124 100644 --- a/dubbo-common/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.common.serialize.Serialization +++ b/dubbo-common/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.common.serialize.Serialization @@ -2,6 +2,5 @@ dubbo=com.alibaba.dubbo.common.serialize.support.dubbo.DubboSerialization hessian2=com.alibaba.dubbo.common.serialize.support.hessian.Hessian2Serialization java=com.alibaba.dubbo.common.serialize.support.java.JavaSerialization compactedjava=com.alibaba.dubbo.common.serialize.support.java.CompactedJavaSerialization -json=com.alibaba.dubbo.common.serialize.support.json.JsonSerialization fastjson=com.alibaba.dubbo.common.serialize.support.json.FastJsonSerialization nativejava=com.alibaba.dubbo.common.serialize.support.nativejava.NativeJavaSerialization \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/JSONTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/JSONTest.java index 1099c9d151d..eb846ea3f34 100644 --- a/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/JSONTest.java +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/JSONTest.java @@ -27,6 +27,7 @@ import static org.junit.Assert.assertEquals; +@Deprecated public class JSONTest { static byte[] DEFAULT_BYTES = {3, 12, 14, 41, 12, 2, 3, 12, 4, 67, 23}; static int DEFAULT_$$ = 152; diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/ConfigUtilsTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/ConfigUtilsTest.java index 67169af3d0d..14bd4af501a 100644 --- a/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/ConfigUtilsTest.java +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/ConfigUtilsTest.java @@ -48,8 +48,8 @@ public static List toArray(T... args) { @Test public void testMergeValues() { List merged = ConfigUtils.mergeValues(Serialization.class, "aaa,bbb,default.cunstom", - toArray("dubbo", "default.hessian2", "json")); - Assert.assertEquals(toArray("dubbo", "json", "aaa", "bbb", "default.cunstom"), merged); + toArray("dubbo", "default.hessian2", "fastjson")); + Assert.assertEquals(toArray("dubbo", "fastjson", "aaa", "bbb", "default.cunstom"), merged); } /** @@ -58,8 +58,8 @@ public void testMergeValues() { @Test public void testMergeValues_addDefault() { List merged = ConfigUtils.mergeValues(Serialization.class, "aaa,bbb,default,zzz", - toArray("dubbo", "default.hessian2", "json")); - Assert.assertEquals(toArray("aaa", "bbb", "dubbo", "json", "zzz"), merged); + toArray("dubbo", "default.hessian2", "fastjson")); + Assert.assertEquals(toArray("aaa", "bbb", "dubbo", "fastjson", "zzz"), merged); } /** @@ -85,8 +85,8 @@ public void testMergeValuesDeleteDefault_2() { */ @Test public void testMergeValuesDelete() { - List merged = ConfigUtils.mergeValues(Serialization.class, "-dubbo,aaa", toArray("dubbo", "default.hessian2", "json")); - Assert.assertEquals(toArray("json", "aaa"), merged); + List merged = ConfigUtils.mergeValues(Serialization.class, "-dubbo,aaa", toArray("dubbo", "default.hessian2", "fastjson")); + Assert.assertEquals(toArray("fastjson", "aaa"), merged); } @Test diff --git a/dubbo-config/dubbo-config-api/pom.xml b/dubbo-config/dubbo-config-api/pom.xml index a29ed87c31d..733686cd0e7 100644 --- a/dubbo-config/dubbo-config-api/pom.xml +++ b/dubbo-config/dubbo-config-api/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-config - 2.5.6 + 2.5.7 dubbo-config-api jar diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractConfig.java index 5e449ff7580..015af60c1f2 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractConfig.java @@ -108,7 +108,7 @@ protected static void appendProperties(AbstractConfig config) { String name = method.getName(); if (name.length() > 3 && name.startsWith("set") && Modifier.isPublic(method.getModifiers()) && method.getParameterTypes().length == 1 && isPrimitive(method.getParameterTypes()[0])) { - String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), "-"); + String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), "."); String value = null; if (config.getId() != null && config.getId().length() > 0) { diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractInterfaceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractInterfaceConfig.java index 7338a1a7850..f2335dce643 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractInterfaceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractInterfaceConfig.java @@ -201,12 +201,17 @@ protected URL loadMonitor(URL registryURL) { if (monitor == null) { String monitorAddress = ConfigUtils.getProperty("dubbo.monitor.address"); String monitorProtocol = ConfigUtils.getProperty("dubbo.monitor.protocol"); - if (monitorAddress != null && monitorAddress.length() > 0 - || monitorProtocol != null && monitorProtocol.length() > 0) { - monitor = new MonitorConfig(); - } else { + if ((monitorAddress == null || monitorAddress.length() == 0) && (monitorProtocol == null || monitorProtocol.length() == 0)) { return null; } + + monitor = new MonitorConfig(); + if (monitorAddress != null && monitorAddress.length() > 0) { + monitor.setAddress(monitorAddress); + } + if (monitorProtocol != null && monitorProtocol.length() > 0) { + monitor.setProtocol(monitorProtocol); + } } appendProperties(monitor); Map map = new HashMap(); @@ -272,23 +277,23 @@ protected void checkStubAndMock(Class interfaceClass) { if (ConfigUtils.isNotEmpty(local)) { Class localClass = ConfigUtils.isDefault(local) ? ReflectUtils.forName(interfaceClass.getName() + "Local") : ReflectUtils.forName(local); if (!interfaceClass.isAssignableFrom(localClass)) { - throw new IllegalStateException("The local implemention class " + localClass.getName() + " not implement interface " + interfaceClass.getName()); + throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceClass.getName()); } try { ReflectUtils.findConstructor(localClass, interfaceClass); } catch (NoSuchMethodException e) { - throw new IllegalStateException("No such constructor \"public " + localClass.getSimpleName() + "(" + interfaceClass.getName() + ")\" in local implemention class " + localClass.getName()); + throw new IllegalStateException("No such constructor \"public " + localClass.getSimpleName() + "(" + interfaceClass.getName() + ")\" in local implementation class " + localClass.getName()); } } if (ConfigUtils.isNotEmpty(stub)) { Class localClass = ConfigUtils.isDefault(stub) ? ReflectUtils.forName(interfaceClass.getName() + "Stub") : ReflectUtils.forName(stub); if (!interfaceClass.isAssignableFrom(localClass)) { - throw new IllegalStateException("The local implemention class " + localClass.getName() + " not implement interface " + interfaceClass.getName()); + throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceClass.getName()); } try { ReflectUtils.findConstructor(localClass, interfaceClass); } catch (NoSuchMethodException e) { - throw new IllegalStateException("No such constructor \"public " + localClass.getSimpleName() + "(" + interfaceClass.getName() + ")\" in local implemention class " + localClass.getName()); + throw new IllegalStateException("No such constructor \"public " + localClass.getSimpleName() + "(" + interfaceClass.getName() + ")\" in local implementation class " + localClass.getName()); } } if (ConfigUtils.isNotEmpty(mock)) { @@ -302,12 +307,12 @@ protected void checkStubAndMock(Class interfaceClass) { } else { Class mockClass = ConfigUtils.isDefault(mock) ? ReflectUtils.forName(interfaceClass.getName() + "Mock") : ReflectUtils.forName(mock); if (!interfaceClass.isAssignableFrom(mockClass)) { - throw new IllegalStateException("The mock implemention class " + mockClass.getName() + " not implement interface " + interfaceClass.getName()); + throw new IllegalStateException("The mock implementation class " + mockClass.getName() + " not implement interface " + interfaceClass.getName()); } try { mockClass.getConstructor(new Class[0]); } catch (NoSuchMethodException e) { - throw new IllegalStateException("No such empty constructor \"public " + mockClass.getSimpleName() + "()\" in mock implemention class " + mockClass.getName()); + throw new IllegalStateException("No such empty constructor \"public " + mockClass.getSimpleName() + "()\" in mock implementation class " + mockClass.getName()); } } } diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractServiceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractServiceConfig.java index 583dc43ba10..36317844ebd 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractServiceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractServiceConfig.java @@ -67,6 +67,9 @@ public abstract class AbstractServiceConfig extends AbstractInterfaceConfig { // 是否注册 private Boolean register; + // 预热时间 + private Integer warmup; + public String getVersion() { return version; } @@ -122,6 +125,11 @@ public String getToken() { return token; } + public void setToken(String token) { + checkName("token", token); + this.token = token; + } + public void setToken(Boolean token) { if (token == null) { setToken((String) null); @@ -130,11 +138,6 @@ public void setToken(Boolean token) { } } - public void setToken(String token) { - checkName("token", token); - this.token = token; - } - public Boolean isDeprecated() { return deprecated; } @@ -172,6 +175,10 @@ public String getAccesslog() { return accesslog; } + public void setAccesslog(String accesslog) { + this.accesslog = accesslog; + } + public void setAccesslog(Boolean accesslog) { if (accesslog == null) { setAccesslog((String) null); @@ -180,10 +187,6 @@ public void setAccesslog(Boolean accesslog) { } } - public void setAccesslog(String accesslog) { - this.accesslog = accesslog; - } - public Integer getExecutes() { return executes; } @@ -218,4 +221,12 @@ public void setRegister(Boolean register) { setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); } } + + public Integer getWarmup() { + return warmup; + } + + public void setWarmup(Integer warmup) { + this.warmup = warmup; + } } \ No newline at end of file diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ApplicationConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ApplicationConfig.java index b36f4768c08..6fa319bd2d7 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ApplicationConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ApplicationConfig.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; /** @@ -67,6 +68,12 @@ public class ApplicationConfig extends AbstractConfig { // 是否为缺省 private Boolean isDefault; + // thread stack存储路径 + private String dumpDirectory; + + // 自定义参数 + private Map parameters; + public ApplicationConfig() { } @@ -160,14 +167,14 @@ public MonitorConfig getMonitor() { return monitor; } - public void setMonitor(String monitor) { - this.monitor = new MonitorConfig(monitor); - } - public void setMonitor(MonitorConfig monitor) { this.monitor = monitor; } + public void setMonitor(String monitor) { + this.monitor = new MonitorConfig(monitor); + } + public String getCompiler() { return compiler; } @@ -194,4 +201,21 @@ public void setDefault(Boolean isDefault) { this.isDefault = isDefault; } + @Parameter(key = "dump.directory") + public String getDumpDirectory() { + return dumpDirectory; + } + + public void setDumpDirectory(String dumpDirectory) { + this.dumpDirectory = dumpDirectory; + } + + public Map getParameters() { + return parameters; + } + + public void setParameters(Map parameters) { + checkParameterName(parameters); + this.parameters = parameters; + } } \ No newline at end of file diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ConsumerConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ConsumerConfig.java index 489e1f23006..a3fbdae68a1 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ConsumerConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ConsumerConfig.java @@ -28,6 +28,9 @@ public class ConsumerConfig extends AbstractReferenceConfig { // 是否为缺省 private Boolean isDefault; + // 网络通信框架的客户端类型: netty mina ... + private String client; + @Override public void setTimeout(Integer timeout) { super.setTimeout(timeout); @@ -46,4 +49,11 @@ public void setDefault(Boolean isDefault) { this.isDefault = isDefault; } + public String getClient() { + return client; + } + + public void setClient(String client) { + this.client = client; + } } \ No newline at end of file diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java index 43127c857c9..bb13b621b60 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java @@ -50,6 +50,8 @@ import java.util.Map; import java.util.Properties; +import static com.alibaba.dubbo.common.utils.NetUtils.isInvalidLocalHost; + /** * ReferenceConfig * @@ -315,6 +317,16 @@ private void init() { checkAndConvertImplicitConfig(method, map, attributes); } } + + // + String hostToRegistry = ConfigUtils.getSystemProperty(Constants.DUBBO_IP_TO_REGISTRY); + if (hostToRegistry == null || hostToRegistry.length() == 0) { + hostToRegistry = NetUtils.getLocalHost(); + } else if (isInvalidLocalHost(hostToRegistry)) { + throw new IllegalArgumentException("Specified invalid registry ip from property:" + Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry); + } + map.put(Constants.REGISTER_IP_KEY, hostToRegistry); + //attributes通过系统context进行存储. StaticContext.getSystemContext().putAll(attributes); ref = createProxy(map); diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java index 1d855b0c53f..77ea210facf 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java @@ -1,12 +1,12 @@ /* * Copyright 1999-2011 Alibaba Group. - * + * * Licensed 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. @@ -23,7 +23,6 @@ import com.alibaba.dubbo.common.utils.ClassHelper; import com.alibaba.dubbo.common.utils.ConfigUtils; import com.alibaba.dubbo.common.utils.NamedThreadFactory; -import com.alibaba.dubbo.common.utils.NetUtils; import com.alibaba.dubbo.common.utils.StringUtils; import com.alibaba.dubbo.config.annotation.Service; import com.alibaba.dubbo.config.support.Parameter; @@ -52,6 +51,12 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import static com.alibaba.dubbo.common.utils.NetUtils.LOCALHOST; +import static com.alibaba.dubbo.common.utils.NetUtils.getAvailablePort; +import static com.alibaba.dubbo.common.utils.NetUtils.getLocalHost; +import static com.alibaba.dubbo.common.utils.NetUtils.isInvalidLocalHost; +import static com.alibaba.dubbo.common.utils.NetUtils.isInvalidPort; + /** * ServiceConfig * @@ -279,7 +284,7 @@ protected synchronized void doExport() { throw new IllegalStateException(e.getMessage(), e); } if (!interfaceClass.isAssignableFrom(localClass)) { - throw new IllegalStateException("The local implemention class " + localClass.getName() + " not implement interface " + interfaceName); + throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName); } } if (stub != null) { @@ -293,7 +298,7 @@ protected synchronized void doExport() { throw new IllegalStateException(e.getMessage(), e); } if (!interfaceClass.isAssignableFrom(stubClass)) { - throw new IllegalStateException("The stub implemention class " + stubClass.getName() + " not implement interface " + interfaceName); + throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName); } } checkApplication(); @@ -353,66 +358,7 @@ private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List r name = "dubbo"; } - String host = protocolConfig.getHost(); - if (provider != null && (host == null || host.length() == 0)) { - host = provider.getHost(); - } - boolean anyhost = false; - if (NetUtils.isInvalidLocalHost(host)) { - anyhost = true; - try { - host = InetAddress.getLocalHost().getHostAddress(); - } catch (UnknownHostException e) { - logger.warn(e.getMessage(), e); - } - if (NetUtils.isInvalidLocalHost(host)) { - if (registryURLs != null && registryURLs.size() > 0) { - for (URL registryURL : registryURLs) { - try { - Socket socket = new Socket(); - try { - SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort()); - socket.connect(addr, 1000); - host = socket.getLocalAddress().getHostAddress(); - break; - } finally { - try { - socket.close(); - } catch (Throwable e) { - } - } - } catch (Exception e) { - logger.warn(e.getMessage(), e); - } - } - } - if (NetUtils.isInvalidLocalHost(host)) { - host = NetUtils.getLocalHost(); - } - } - } - - Integer port = protocolConfig.getPort(); - if (provider != null && (port == null || port == 0)) { - port = provider.getPort(); - } - final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort(); - if (port == null || port == 0) { - port = defaultPort; - } - if (port == null || port <= 0) { - port = getRandomPort(name); - if (port == null || port < 0) { - port = NetUtils.getAvailablePort(defaultPort); - putRandomPort(name, port); - } - logger.warn("Use random available port(" + port + ") for protocol " + name); - } - Map map = new HashMap(); - if (anyhost) { - map.put(Constants.ANYHOST_KEY, "true"); - } map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE); map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion()); map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); @@ -513,6 +459,9 @@ private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List r if ((contextPath == null || contextPath.length() == 0) && provider != null) { contextPath = provider.getContextpath(); } + + String host = this.findConfigedHosts(protocolConfig, registryURLs, map); + Integer port = this.findConfigedPorts(protocolConfig, name, map); URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map); if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class) @@ -566,7 +515,7 @@ private void exportLocal(URL url) { if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) { URL local = URL.valueOf(url.toFullString()) .setProtocol(Constants.LOCAL_PROTOCOL) - .setHost(NetUtils.LOCALHOST) + .setHost(LOCALHOST) .setPort(0); Exporter exporter = protocol.export( proxyFactory.getInvoker(ref, (Class) interfaceClass, local)); @@ -575,6 +524,154 @@ private void exportLocal(URL url) { } } + + /** + * provider注册&监听ip地址,注册与监听ip可独立配置 + * 配置优先级:系统环境变量 -> java命令参数-D -> 配置文件host属性 -> /etc/hosts中hostname-ip映射关系 -> 默认联通注册中心地址的网卡地址 -> 第一个可用的网卡地址 + * + * @param protocolConfig + * @param registryURLs + * @param map + * @return + */ + private String findConfigedHosts(ProtocolConfig protocolConfig, List registryURLs, Map map) { + boolean anyhost = false; + + String hostToBind = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_BIND); + if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) { + throw new IllegalArgumentException("Specified invalid bind ip from property:" + Constants.DUBBO_IP_TO_BIND + ", value:" + hostToBind); + } + + // 如果没通过环境变量设置bind ip,则继续按优先级查找 + if (hostToBind == null || hostToBind.length() == 0) { + hostToBind = protocolConfig.getHost(); + if (provider != null && (hostToBind == null || hostToBind.length() == 0)) { + hostToBind = provider.getHost(); + } + if (isInvalidLocalHost(hostToBind)) { + anyhost = true; + try { + hostToBind = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + logger.warn(e.getMessage(), e); + } + if (isInvalidLocalHost(hostToBind)) { + if (registryURLs != null && registryURLs.size() > 0) { + for (URL registryURL : registryURLs) { + try { + Socket socket = new Socket(); + try { + SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort()); + socket.connect(addr, 1000); + hostToBind = socket.getLocalAddress().getHostAddress(); + break; + } finally { + try { + socket.close(); + } catch (Throwable e) { + } + } + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + } + } + if (isInvalidLocalHost(hostToBind)) { + hostToBind = getLocalHost(); + } + } + } + } + + map.put(Constants.BIND_IP_KEY, hostToBind); + + // registry ip,默认不作为bind ip + String hostToRegistry = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_REGISTRY); + if (hostToRegistry != null && hostToRegistry.length() > 0 && isInvalidLocalHost(hostToRegistry)) { + throw new IllegalArgumentException("Specified invalid registry ip from property:" + Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry); + } else if (hostToRegistry == null || hostToRegistry.length() == 0) { + // bind ip默认作为registry ip + hostToRegistry = hostToBind; + } + + map.put(Constants.ANYHOST_KEY, String.valueOf(anyhost)); + + return hostToRegistry; + } + + /** + * provider注册&监听端口,注册与监听port可独立配置 + * 配置优先级:启动环境变量 -> java命令参数-D -> protocol配置文件port属性配置 -> 协议默认端口 + * + * @param protocolConfig + * @param name + * @return + */ + private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map map) { + Integer portToBind = null; + + // 解析环境变量配置的bind port + String port = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_BIND); + portToBind = parsePort(port); + + // 如未通过环境变量配置bind port,则继续按优先级查找 + if (portToBind == null) { + portToBind = protocolConfig.getPort(); + if (provider != null && (portToBind == null || portToBind == 0)) { + portToBind = provider.getPort(); + } + final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort(); + if (portToBind == null || portToBind == 0) { + portToBind = defaultPort; + } + if (portToBind == null || portToBind <= 0) { + portToBind = getRandomPort(name); + if (portToBind == null || portToBind < 0) { + portToBind = getAvailablePort(defaultPort); + putRandomPort(name, portToBind); + } + logger.warn("Use random available port(" + portToBind + ") for protocol " + name); + } + } + + // 记录bind port,作为url的key + map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind)); + + // registry port,默认不作为bind port + String portToRegistryStr = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_REGISTRY); + Integer portToRegistry = parsePort(portToRegistryStr); + if (portToRegistry == null) { + portToRegistry = portToBind; + } + + return portToRegistry; + } + + private Integer parsePort(String configPort) { + Integer port = null; + if (configPort != null && configPort.length() > 0) { + try { + Integer intPort = Integer.parseInt(configPort); + if (isInvalidPort(intPort)) { + throw new IllegalArgumentException("Specified invalid port from env value:" + configPort); + } + port = intPort; + } catch (Exception e) { + throw new IllegalArgumentException("Specified invalid port from env value:" + configPort); + } + } + return port; + } + + private String getValueFromConfig(ProtocolConfig protocolConfig, String key) { + String protocolPrefix = protocolConfig.getName().toUpperCase() + "_"; + String port = ConfigUtils.getSystemProperty(protocolPrefix + key); + if (port == null || port.length() == 0) { + port = ConfigUtils.getSystemProperty(key); + } + return port; + } + private void checkDefault() { if (provider == null) { provider = new ProviderConfig(); diff --git a/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationParameter.java b/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationParameter.java index d60efafe9ec..ca80f66103b 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationParameter.java +++ b/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationParameter.java @@ -34,6 +34,9 @@ public class ValidationParameter implements Serializable { private static final long serialVersionUID = 7158911668568000392L; + @NotNull(groups = ValidationService.Update.class) + private Integer id; + @NotNull // 不允许为空 @Size(min = 2, max = 20) // 长度或大小范围 private String name; @@ -52,6 +55,14 @@ public class ValidationParameter implements Serializable { @Future // 必须为一个未来的时间 private Date expiryDate; + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + public String getName() { return name; } diff --git a/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationService.java b/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationService.java index 519d2801406..eb9ea2d35ed 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationService.java +++ b/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationService.java @@ -15,6 +15,8 @@ */ package com.alibaba.dubbo.config.validation; +import com.alibaba.dubbo.validation.MethodValidated; + import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; @@ -28,16 +30,31 @@ */ public interface ValidationService { // 缺省可按服务接口区分验证场景,如:@NotNull(groups = ValidationService.class) + /** + * 没有加上“@MethodValidated(ValidationService.Save.class)”这句代码时, + * 现在的检查逻辑不会去检验groups = ValidationService.Save.class这个分组 + * + * @param parameter + */ + @MethodValidated(Save.class) void save(ValidationParameter parameter); void update(ValidationParameter parameter); void delete(@Min(1) long id, @NotNull @Size(min = 2, max = 16) @Pattern(regexp = "^[a-zA-Z]+$") String operator); + /** + * 假设关联查询的时候需要同时传id和email的值。这时需要检查Sava分组和Update分组。 + * @param parameter + */ + @MethodValidated({Save.class, Update.class}) + void relatedQuery(ValidationParameter parameter); + @interface Save { } // 与方法同名接口,首字母大写,用于区分验证场景,如:@NotNull(groups = ValidationService.Save.class),可选 @interface Update { } // 与方法同名接口,首字母大写,用于区分验证场景,如:@NotNull(groups = ValidationService.Update.class),可选 + } diff --git a/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationServiceImpl.java b/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationServiceImpl.java index be45b4d9217..2fc0a106ae7 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationServiceImpl.java +++ b/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationServiceImpl.java @@ -31,4 +31,8 @@ public void update(ValidationParameter parameter) { public void delete(long id, String operator) { } + public void relatedQuery(ValidationParameter parameter){ + + } + } diff --git a/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationTest.java b/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationTest.java index 2a453910a9a..7a90dc9af42 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationTest.java @@ -81,6 +81,36 @@ public void testValidation() { Assert.assertNotNull(violations); } + //检查Save分组 save error + try { + parameter = new ValidationParameter(); + parameter.setName("liangfei"); + parameter.setAge(50); + parameter.setLoginDate(new Date(System.currentTimeMillis() - 1000000)); + parameter.setExpiryDate(new Date(System.currentTimeMillis() + 1000000)); + validationService.save(parameter); + Assert.fail(); + } catch (RpcException e) { + ConstraintViolationException ve = (ConstraintViolationException) e.getCause(); + Set> violations = ve.getConstraintViolations(); + Assert.assertNotNull(violations); + } + + // relatedQuery error 不传id和email的值,触发Save和Update的检查异常 + try { + parameter = new ValidationParameter(); + parameter.setName("liangfei"); + parameter.setAge(50); + parameter.setLoginDate(new Date(System.currentTimeMillis() - 1000000)); + parameter.setExpiryDate(new Date(System.currentTimeMillis() + 1000000)); + validationService.relatedQuery(parameter); + Assert.fail(); + } catch (RpcException e) { + ConstraintViolationException ve = (ConstraintViolationException) e.getCause(); + Set> violations = ve.getConstraintViolations(); + Assert.assertEquals(violations.size(),2); + } + // Save Error try { parameter = new ValidationParameter(); @@ -89,6 +119,7 @@ public void testValidation() { } catch (RpcException e) { ConstraintViolationException ve = (ConstraintViolationException) e.getCause(); Set> violations = ve.getConstraintViolations(); + Assert.assertTrue(violations.size() == 3); Assert.assertNotNull(violations); } diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml index 1116dc10f5b..bce18b793ae 100644 --- a/dubbo-config/dubbo-config-spring/pom.xml +++ b/dubbo-config/dubbo-config-spring/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-config - 2.5.6 + 2.5.7 dubbo-config-spring jar @@ -92,6 +92,13 @@ javax.el test + + + org.springframework + spring-test + test + + diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/AnnotationBean.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/AnnotationBean.java index 1b5eac3d968..b0efe4525e3 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/AnnotationBean.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/AnnotationBean.java @@ -57,6 +57,7 @@ * @author william.liangf * @export */ +@Deprecated public class AnnotationBean extends AbstractConfig implements DisposableBean, BeanFactoryPostProcessor, BeanPostProcessor, ApplicationContextAware { private static final long serialVersionUID = -7582802454287589552L; diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/ServiceBean.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/ServiceBean.java index 6976aa42b2b..e3d87536900 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/ServiceBean.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/ServiceBean.java @@ -53,6 +53,8 @@ public class ServiceBean extends ServiceConfig implements InitializingBean private static transient ApplicationContext SPRING_CONTEXT; + private final transient Service service; + private transient ApplicationContext applicationContext; private transient String beanName; @@ -61,10 +63,12 @@ public class ServiceBean extends ServiceConfig implements InitializingBean public ServiceBean() { super(); + this.service = null; } public ServiceBean(Service service) { super(service); + this.service = service; } public static ApplicationContext getSpringContext() { @@ -100,6 +104,15 @@ public void setBeanName(String name) { this.beanName = name; } + /** + * Gets associated {@link Service} + * + * @return associated {@link Service} + */ + public Service getService() { + return service; + } + public void onApplicationEvent(ApplicationEvent event) { if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) { if (isDelay() && !isExported() && !isUnexported()) { diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java new file mode 100644 index 00000000000..d94bee9f175 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java @@ -0,0 +1,193 @@ +package com.alibaba.dubbo.config.spring.beans.factory.annotation; + +import com.alibaba.dubbo.config.*; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.util.Assert; + +import java.lang.annotation.Annotation; +import java.util.List; + +import static com.alibaba.dubbo.config.spring.util.BeanFactoryUtils.getBeans; +import static com.alibaba.dubbo.config.spring.util.BeanFactoryUtils.getOptionalBean; + +/** + * Abstract Configurable {@link Annotation} Bean Builder + * + * @author Mercy + * @since 2.5.7 + */ +abstract class AbstractAnnotationConfigBeanBuilder { + + protected final Log logger = LogFactory.getLog(getClass()); + + protected final A annotation; + + protected final ApplicationContext applicationContext; + + protected final ClassLoader classLoader; + + protected Object bean; + + protected Class interfaceClass; + + protected AbstractAnnotationConfigBeanBuilder(A annotation, ClassLoader classLoader, + ApplicationContext applicationContext) { + Assert.notNull(annotation, "The Annotation must not be null!"); + Assert.notNull(classLoader, "The ClassLoader must not be null!"); + Assert.notNull(applicationContext, "The ApplicationContext must not be null!"); + this.annotation = annotation; + this.applicationContext = applicationContext; + this.classLoader = classLoader; + + } + + /** + * Build {@link B} + * + * @return non-null + * @throws Exception + */ + public final B build() throws Exception { + + checkDependencies(); + + B bean = doBuild(); + + configureBean(bean); + + if (logger.isInfoEnabled()) { + logger.info(bean + " has been built."); + } + + return bean; + + } + + private void checkDependencies() { + + } + + /** + * Builds {@link B Bean} + * + * @return {@link B Bean} + */ + protected abstract B doBuild(); + + + protected void configureBean(B bean) throws Exception { + + preConfigureBean(annotation, bean); + + configureRegistryConfigs(bean); + + configureMonitorConfig(bean); + + configureApplicationConfig(bean); + + configureModuleConfig(bean); + + postConfigureBean(annotation, bean); + + } + + protected abstract void preConfigureBean(A annotation, B bean) throws Exception; + + + private void configureRegistryConfigs(B bean) { + + String[] registryConfigBeanIds = resolveRegistryConfigBeanNames(annotation); + + List registryConfigs = getBeans(applicationContext, registryConfigBeanIds, RegistryConfig.class); + + bean.setRegistries(registryConfigs); + + } + + private void configureMonitorConfig(B bean) { + + String monitorBeanName = resolveMonitorConfigBeanName(annotation); + + MonitorConfig monitorConfig = getOptionalBean(applicationContext, monitorBeanName, MonitorConfig.class); + + bean.setMonitor(monitorConfig); + + } + + private void configureApplicationConfig(B bean) { + + String applicationConfigBeanName = resolveApplicationConfigBeanName(annotation); + + ApplicationConfig applicationConfig = + getOptionalBean(applicationContext, applicationConfigBeanName, ApplicationConfig.class); + + bean.setApplication(applicationConfig); + + } + + private void configureModuleConfig(B bean) { + + String moduleConfigBeanName = resolveModuleConfigBeanName(annotation); + + ModuleConfig moduleConfig = + getOptionalBean(applicationContext, moduleConfigBeanName, ModuleConfig.class); + + bean.setModule(moduleConfig); + + } + + /** + * Resolves the bean name of {@link ModuleConfig} + * + * @param annotation {@link A} + * @return + */ + protected abstract String resolveModuleConfigBeanName(A annotation); + + /** + * Resolves the bean name of {@link ApplicationConfig} + * + * @param annotation {@link A} + * @return + */ + protected abstract String resolveApplicationConfigBeanName(A annotation); + + + /** + * Resolves the bean ids of {@link com.alibaba.dubbo.config.RegistryConfig} + * + * @param annotation {@link A} + * @return non-empty array + */ + protected abstract String[] resolveRegistryConfigBeanNames(A annotation); + + /** + * Resolves the bean name of {@link MonitorConfig} + * + * @param annotation {@link A} + * @return + */ + protected abstract String resolveMonitorConfigBeanName(A annotation); + + /** + * Configures Bean + * + * @param annotation + * @param bean + */ + protected abstract void postConfigureBean(A annotation, B bean) throws Exception; + + + public > T bean(Object bean) { + this.bean = bean; + return (T) this; + } + + public > T interfaceClass(Class interfaceClass) { + this.interfaceClass = interfaceClass; + return (T) this; + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java new file mode 100644 index 00000000000..423a26397bb --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java @@ -0,0 +1,376 @@ +package com.alibaba.dubbo.config.spring.beans.factory.annotation; + +import com.alibaba.dubbo.config.annotation.Reference; +import com.alibaba.dubbo.config.spring.ReferenceBean; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.PropertyValues; +import org.springframework.beans.factory.*; +import org.springframework.beans.factory.annotation.InjectionMetadata; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; +import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.core.BridgeMethodResolver; +import org.springframework.core.Ordered; +import org.springframework.core.PriorityOrdered; +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static org.springframework.core.annotation.AnnotatedElementUtils.getMergedAnnotation; + +/** + * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation + * that Consumer service {@link Reference} annotated fields + * + * @author Mercy + * @since 2.5.7 + */ +public class ReferenceAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter + implements MergedBeanDefinitionPostProcessor, PriorityOrdered, ApplicationContextAware, BeanClassLoaderAware, + DisposableBean { + + /** + * The bean name of {@link ReferenceAnnotationBeanPostProcessor} + */ + public static String BEAN_NAME = "referenceAnnotationBeanPostProcessor"; + + private final Log logger = LogFactory.getLog(getClass()); + + private ApplicationContext applicationContext; + + private ClassLoader classLoader; + + private final ConcurrentMap injectionMetadataCache = + new ConcurrentHashMap(256); + + private final ConcurrentMap> referenceBeansCache = + new ConcurrentHashMap>(); + + @Override + public PropertyValues postProcessPropertyValues( + PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException { + + InjectionMetadata metadata = findReferenceMetadata(beanName, bean.getClass(), pvs); + try { + metadata.inject(bean, beanName, pvs); + } catch (BeanCreationException ex) { + throw ex; + } catch (Throwable ex) { + throw new BeanCreationException(beanName, "Injection of @Reference dependencies failed", ex); + } + return pvs; + } + + + /** + * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link Reference @Reference} fields + * + * @param beanClass The {@link Class} of Bean + * @return non-null {@link List} + */ + private List findFieldReferenceMetadata(final Class beanClass) { + + final List elements = new LinkedList(); + + ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() { + @Override + public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { + + Reference reference = findReferenceAnnotation(field); + + if (reference != null) { + + if (Modifier.isStatic(field.getModifiers())) { + if (logger.isWarnEnabled()) { + logger.warn("@Reference annotation is not supported on static fields: " + field); + } + return; + } + + elements.add(new ReferenceFieldElement(field, reference)); + } + + } + }); + + return elements; + + } + + /** + * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link Reference @Reference} methods + * + * @param beanClass The {@link Class} of Bean + * @return non-null {@link List} + */ + private List findMethodReferenceMetadata(final Class beanClass) { + + final List elements = new LinkedList(); + + ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() { + @Override + public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { + + Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); + + if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) { + return; + } + + Reference reference = findReferenceAnnotation(bridgedMethod); + + if (reference != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) { + if (Modifier.isStatic(method.getModifiers())) { + if (logger.isWarnEnabled()) { + logger.warn("@Reference annotation is not supported on static methods: " + method); + } + return; + } + if (method.getParameterTypes().length == 0) { + if (logger.isWarnEnabled()) { + logger.warn("@Reference annotation should only be used on methods with parameters: " + + method); + } + } + PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass); + elements.add(new ReferenceMethodElement(method, pd, reference)); + } + } + }); + + return elements; + + } + + + /** + * @param beanClass + * @return + */ + private InjectionMetadata buildReferenceMetadata(final Class beanClass) { + + final List elements = new LinkedList(); + + elements.addAll(findFieldReferenceMetadata(beanClass)); + + elements.addAll(findMethodReferenceMetadata(beanClass)); + + return new InjectionMetadata(beanClass, elements); + + } + + private InjectionMetadata findReferenceMetadata(String beanName, Class clazz, PropertyValues pvs) { + // Fall back to class name as cache key, for backwards compatibility with custom callers. + String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); + // Quick check on the concurrent map first, with minimal locking. + InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); + if (InjectionMetadata.needsRefresh(metadata, clazz)) { + synchronized (this.injectionMetadataCache) { + metadata = this.injectionMetadataCache.get(cacheKey); + if (InjectionMetadata.needsRefresh(metadata, clazz)) { + if (metadata != null) { + metadata.clear(pvs); + } + try { + metadata = buildReferenceMetadata(clazz); + this.injectionMetadataCache.put(cacheKey, metadata); + } catch (NoClassDefFoundError err) { + throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() + + "] for reference metadata: could not find class that it depends on", err); + } + } + } + } + return metadata; + } + + private Reference findReferenceAnnotation(AccessibleObject accessibleObject) { + + if (accessibleObject.getAnnotations().length > 0) { + Reference reference = getMergedAnnotation(accessibleObject, Reference.class); + return reference; + } + + return null; + + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Override + public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) { + if (beanType != null) { + InjectionMetadata metadata = findReferenceMetadata(beanName, beanType, null); + metadata.checkConfigMembers(beanDefinition); + } + } + + @Override + public int getOrder() { + return LOWEST_PRECEDENCE; + } + + @Override + public void destroy() throws Exception { + + for (ReferenceBean referenceBean : referenceBeansCache.values()) { + if (logger.isInfoEnabled()) { + logger.info(referenceBean + " was destroying!"); + } + referenceBean.destroy(); + } + + injectionMetadataCache.clear(); + referenceBeansCache.clear(); + + if (logger.isInfoEnabled()) { + logger.info(getClass() + " was destroying!"); + } + + } + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + /** + * {@link Reference} {@link Method} {@link InjectionMetadata.InjectedElement} + */ + private class ReferenceMethodElement extends InjectionMetadata.InjectedElement { + + private final Method method; + + private final Reference reference; + + protected ReferenceMethodElement(Method method, PropertyDescriptor pd, Reference reference) { + super(method, pd); + this.method = method; + this.reference = reference; + } + + @Override + protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { + + Class referenceClass = pd.getPropertyType(); + + Object referenceBean = buildReferenceBean(reference, referenceClass); + + ReflectionUtils.makeAccessible(method); + + method.invoke(bean, referenceBean); + + } + + } + + /** + * {@link Reference} {@link Field} {@link InjectionMetadata.InjectedElement} + */ + private class ReferenceFieldElement extends InjectionMetadata.InjectedElement { + + private final Field field; + + private final Reference reference; + + protected ReferenceFieldElement(Field field, Reference reference) { + super(field, null); + this.field = field; + this.reference = reference; + } + + @Override + protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { + + Class referenceClass = field.getType(); + + Object referenceBean = buildReferenceBean(reference, referenceClass); + + ReflectionUtils.makeAccessible(field); + + field.set(bean, referenceBean); + + } + + } + + private Object buildReferenceBean(Reference reference, Class referenceClass) throws Exception { + + String referenceBeanCacheKey = generateReferenceBeanCacheKey(reference, referenceClass); + + ReferenceBean referenceBean = referenceBeansCache.get(referenceBeanCacheKey); + + if (referenceBean == null) { + + ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder + .create(reference, classLoader, applicationContext) + .interfaceClass(referenceClass); + + referenceBean = beanBuilder.build(); + + referenceBeansCache.putIfAbsent(referenceBeanCacheKey, referenceBean); + + } + + + return referenceBean.get(); + } + + + /** + * Generate a cache key of {@link ReferenceBean} + * + * @param reference {@link Reference} + * @param beanClass {@link Class} + * @return + */ + private static String generateReferenceBeanCacheKey(Reference reference, Class beanClass) { + + String interfaceName = resolveInterfaceName(reference, beanClass); + + String key = reference.group() + "/" + interfaceName + ":" + reference.version(); + + return key; + + } + + private static String resolveInterfaceName(Reference reference, Class beanClass) + throws IllegalStateException { + + String interfaceName; + if (!"".equals(reference.interfaceName())) { + interfaceName = reference.interfaceName(); + } else if (!void.class.equals(reference.interfaceClass())) { + interfaceName = reference.interfaceClass().getName(); + } else if (beanClass.isInterface()) { + interfaceName = beanClass.getName(); + } else { + throw new IllegalStateException( + "The @Reference undefined interfaceClass or interfaceName, and the property type " + + beanClass.getName() + " is not a interface."); + } + + return interfaceName; + + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java new file mode 100644 index 00000000000..4ba8cf6eaf8 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java @@ -0,0 +1,114 @@ +package com.alibaba.dubbo.config.spring.beans.factory.annotation; + +import com.alibaba.dubbo.config.*; +import com.alibaba.dubbo.config.annotation.Reference; +import com.alibaba.dubbo.config.spring.ReferenceBean; +import org.springframework.context.ApplicationContext; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; + +import static com.alibaba.dubbo.config.spring.util.BeanFactoryUtils.getOptionalBean; + +/** + * {@link ReferenceBean} Builder + * + * @author Mercy + * @since 2.5.7 + */ +class ReferenceBeanBuilder extends AbstractAnnotationConfigBeanBuilder { + + + private ReferenceBeanBuilder(Reference annotation, ClassLoader classLoader, ApplicationContext applicationContext) { + super(annotation, classLoader, applicationContext); + } + + private void configureInterface(Reference reference, ReferenceBean referenceBean) { + + Class interfaceClass = reference.interfaceClass(); + + if (void.class.equals(interfaceClass)) { + + interfaceClass = null; + + String interfaceClassName = reference.interfaceName(); + + if (StringUtils.hasText(interfaceClassName)) { + if (ClassUtils.isPresent(interfaceClassName, classLoader)) { + interfaceClass = ClassUtils.resolveClassName(interfaceClassName, classLoader); + } + } + + } + + if (interfaceClass == null) { + interfaceClass = this.interfaceClass; + } + + Assert.isTrue(interfaceClass.isInterface(), + "The class of field or method that was annotated @Reference is not an interface!"); + + referenceBean.setInterface(interfaceClass); + + } + + + private void configureConsumerConfig(Reference reference, ReferenceBean referenceBean) { + + String consumerBeanName = reference.consumer(); + + ConsumerConfig consumerConfig = getOptionalBean(applicationContext, consumerBeanName, ConsumerConfig.class); + + referenceBean.setConsumer(consumerConfig); + + } + + @Override + protected ReferenceBean doBuild() { + return new ReferenceBean(annotation); + } + + @Override + protected void preConfigureBean(Reference annotation, ReferenceBean bean) { + Assert.notNull(interfaceClass, "The interface class must set first!"); + } + + @Override + protected String resolveModuleConfigBeanName(Reference annotation) { + return annotation.module(); + } + + @Override + protected String resolveApplicationConfigBeanName(Reference annotation) { + return annotation.application(); + } + + @Override + protected String[] resolveRegistryConfigBeanNames(Reference annotation) { + return annotation.registry(); + } + + @Override + protected String resolveMonitorConfigBeanName(Reference annotation) { + return annotation.monitor(); + } + + @Override + protected void postConfigureBean(Reference annotation, ReferenceBean bean) throws Exception { + + bean.setApplicationContext(applicationContext); + + configureInterface(annotation, bean); + + configureConsumerConfig(annotation, bean); + + bean.afterPropertiesSet(); + + } + + public static ReferenceBeanBuilder create(Reference annotation, ClassLoader classLoader, + ApplicationContext applicationContext) { + return new ReferenceBeanBuilder(annotation, classLoader, applicationContext); + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboClassPathBeanDefinitionScanner.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboClassPathBeanDefinitionScanner.java new file mode 100644 index 00000000000..b0783d3b46a --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboClassPathBeanDefinitionScanner.java @@ -0,0 +1,45 @@ +package com.alibaba.dubbo.config.spring.context.annotation; + +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ResourceLoader; + +import java.util.Set; + +import static org.springframework.context.annotation.AnnotationConfigUtils.registerAnnotationConfigProcessors; + +/** + * Dubbo {@link ClassPathBeanDefinitionScanner} that exposes some methods to be public. + * + * @author Mercy + * @see #doScan(String...) + * @see #registerDefaultFilters() + * @since 2.5.7 + */ +public class DubboClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner { + + + public DubboClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, + ResourceLoader resourceLoader) { + + super(registry, useDefaultFilters, environment, resourceLoader); + + registerAnnotationConfigProcessors(registry); + + } + + public DubboClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, Environment environment, + ResourceLoader resourceLoader) { + + this(registry, false, environment, resourceLoader); + + } + + public Set doScan(String... basePackages) { + return super.doScan(basePackages); + } + + +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScan.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScan.java new file mode 100644 index 00000000000..bc9f3f1ca63 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScan.java @@ -0,0 +1,56 @@ +package com.alibaba.dubbo.config.spring.context.annotation; + +import com.alibaba.dubbo.config.annotation.Reference; +import com.alibaba.dubbo.config.annotation.Service; +import org.springframework.context.annotation.Import; +import org.springframework.core.annotation.AliasFor; + +import java.lang.annotation.*; + +/** + * Dubbo Component Scan {@link Annotation},scans the classpath for annotated components that will be auto-registered as + * Spring beans. Dubbo-provided {@link Service} and {@link Reference}. + * + * @author Mercy + * @see Service + * @see Reference + * @since 2.5.7 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Import(DubboComponentScanRegistrar.class) +public @interface DubboComponentScan { + + /** + * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation + * declarations e.g.: {@code @DubboComponentScan("org.my.pkg")} instead of + * {@code @DubboComponentScan(basePackages="org.my.pkg")}. + * + * @return the base packages to scan + */ + @AliasFor("basePackages") + String[] value() default {}; + + /** + * Base packages to scan for annotated @Service classes. {@link #value()} is an + * alias for (and mutually exclusive with) this attribute. + *

+ * Use {@link #basePackageClasses()} for a type-safe alternative to String-based + * package names. + * + * @return the base packages to scan + */ + @AliasFor("value") + String[] basePackages() default {}; + + /** + * Type-safe alternative to {@link #basePackages()} for specifying the packages to + * scan for annotated @Service classes. The package of each class specified will be + * scanned. + * + * @return classes from the base packages to scan + */ + Class[] basePackageClasses() default {}; + +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrar.java new file mode 100644 index 00000000000..e453e0fa85e --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrar.java @@ -0,0 +1,298 @@ +package com.alibaba.dubbo.config.spring.context.annotation; + +import com.alibaba.dubbo.config.annotation.Service; +import com.alibaba.dubbo.config.spring.ServiceBean; +import com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor; +import com.alibaba.dubbo.config.spring.util.BeanRegistrar; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.*; +import org.springframework.context.EnvironmentAware; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.util.*; + +import java.util.*; + +import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; +import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerWithGeneratedName; +import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; +import static org.springframework.util.ClassUtils.resolveClassName; + +/** + * Dubbo {@link DubboComponentScan} Bean Registrar + * + * @author Mercy + * @see Service + * @see DubboComponentScan + * @see ImportBeanDefinitionRegistrar + * @since 2.5.7 + */ +public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, + EnvironmentAware, BeanClassLoaderAware { + + private final Log logger = LogFactory.getLog(getClass()); + + private ResourceLoader resourceLoader; + + private Environment environment; + + private ClassLoader classLoader; + + @Override + public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { + + Set packagesToScan = getPackagesToScan(importingClassMetadata); + + registerServiceBeans(packagesToScan, registry); + + registerReferenceAnnotationBeanPostProcessor(registry); + + } + + /** + * Registers Beans whose classes was annotated {@link Service} + * + * @param packagesToScan The base packages to scan + * @param registry {@link BeanDefinitionRegistry} + */ + private void registerServiceBeans(Set packagesToScan, BeanDefinitionRegistry registry) { + + DubboClassPathBeanDefinitionScanner dubboClassPathBeanDefinitionScanner = + new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader); + + dubboClassPathBeanDefinitionScanner.addIncludeFilter(new AnnotationTypeFilter(Service.class)); + + for (String packageToScan : packagesToScan) { + + Set beanDefinitionHolders = dubboClassPathBeanDefinitionScanner.doScan(packageToScan); + + for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) { + registerServiceBean(beanDefinitionHolder, registry); + } + + if (logger.isInfoEnabled()) { + logger.info(beanDefinitionHolders.size() + " annotated @Service Components { " + + beanDefinitionHolders + + " } were scanned under package[" + packageToScan + "]"); + } + } + + } + + private Class resolveClass(BeanDefinitionHolder beanDefinitionHolder) { + + BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition(); + + return resolveClass(beanDefinition); + + } + + private Class resolveClass(BeanDefinition beanDefinition) { + + String beanClassName = beanDefinition.getBeanClassName(); + + return resolveClassName(beanClassName, classLoader); + + } + + /** + * Registers {@link ServiceBean} from new annotated {@link Service} {@link BeanDefinition} + * + * @param beanDefinitionHolder + * @param registry + * @see ServiceBean + * @see BeanDefinition + */ + private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry) { + + Class beanClass = resolveClass(beanDefinitionHolder); + + Service service = findAnnotation(beanClass, Service.class); + + Class interfaceClass = resolveServiceInterfaceClass(beanClass, service); + + String beanName = beanDefinitionHolder.getBeanName(); + + AbstractBeanDefinition serviceBeanDefinition = buildServiceBeanDefinition(service, interfaceClass, beanName); + + registerWithGeneratedName(serviceBeanDefinition, registry); + + } + + private ManagedList toRuntimeBeanReferences(String... beanNames) { + + ManagedList runtimeBeanReferences = new ManagedList(); + + if (!ObjectUtils.isEmpty(beanNames)) { + + for (String beanName : beanNames) { + runtimeBeanReferences.add(new RuntimeBeanReference(beanName)); + } + + } + + return runtimeBeanReferences; + + } + + private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class interfaceClass, + String annotatedServiceBeanName) { + + BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class) + .addConstructorArgValue(service) + // References "ref" property to annotated-@Service Bean + .addPropertyReference("ref", annotatedServiceBeanName) + .addPropertyValue("interfaceClass", interfaceClass); + + /** + * Add {@link com.alibaba.dubbo.config.ProviderConfig} Bean reference + */ + String providerConfigBeanName = service.provider(); + if (StringUtils.hasText(providerConfigBeanName)) { + builder.addPropertyReference("provider", providerConfigBeanName); + } + + /** + * Add {@link com.alibaba.dubbo.config.MonitorConfig} Bean reference + */ + String monitorConfigBeanName = service.monitor(); + if (StringUtils.hasText(monitorConfigBeanName)) { + builder.addPropertyReference("monitor", monitorConfigBeanName); + } + + /** + * Add {@link com.alibaba.dubbo.config.ApplicationConfig} Bean reference + */ + String applicationConfigBeanName = service.application(); + if (StringUtils.hasText(applicationConfigBeanName)) { + builder.addPropertyReference("application", applicationConfigBeanName); + } + + /** + * Add {@link com.alibaba.dubbo.config.ModuleConfig} Bean reference + */ + String moduleConfigBeanName = service.module(); + if (StringUtils.hasText(moduleConfigBeanName)) { + builder.addPropertyReference("application", moduleConfigBeanName); + } + + + /** + * Add {@link com.alibaba.dubbo.config.RegistryConfig} Bean reference + */ + String[] registryConfigBeanNames = service.registry(); + + List registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames); + + if (!registryRuntimeBeanReferences.isEmpty()) { + builder.addPropertyValue("registries", registryRuntimeBeanReferences); + } + + /** + * Add {@link com.alibaba.dubbo.config.ProtocolConfig} Bean reference + */ + String[] protocolConfigBeanNames = service.protocol(); + + List protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames); + + if (!registryRuntimeBeanReferences.isEmpty()) { + builder.addPropertyValue("protocols", protocolRuntimeBeanReferences); + } + + return builder.getBeanDefinition(); + + } + + private Class resolveServiceInterfaceClass(Class annotatedServiceBeanClass, Service service) { + + Class interfaceClass = service.interfaceClass(); + + if (void.class.equals(interfaceClass)) { + + interfaceClass = null; + + String interfaceClassName = service.interfaceName(); + + if (StringUtils.hasText(interfaceClassName)) { + if (ClassUtils.isPresent(interfaceClassName, classLoader)) { + interfaceClass = resolveClassName(interfaceClassName, classLoader); + } + } + + } + + if (interfaceClass == null) { + + Class[] allInterfaces = annotatedServiceBeanClass.getInterfaces(); + + if (allInterfaces.length > 0) { + interfaceClass = allInterfaces[0]; + } + + } + + Assert.notNull(interfaceClass, + "@Service interfaceClass() or interfaceName() or interface class must be present!"); + + Assert.isTrue(interfaceClass.isInterface(), + "The type that was annotated @Service is not an interface!"); + + return interfaceClass; + } + + /** + * Registers {@link ReferenceAnnotationBeanPostProcessor} into {@link BeanFactory} + * + * @param registry {@link BeanDefinitionRegistry} + */ + private void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) { + + // Register @Reference Annotation Bean Processor + BeanRegistrar.registerInfrastructureBean(registry, + ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class); + + } + + private Set getPackagesToScan(AnnotationMetadata metadata) { + AnnotationAttributes attributes = AnnotationAttributes.fromMap( + metadata.getAnnotationAttributes(DubboComponentScan.class.getName())); + String[] basePackages = attributes.getStringArray("basePackages"); + Class[] basePackageClasses = attributes.getClassArray("basePackageClasses"); + Set packagesToScan = new LinkedHashSet(); + packagesToScan.addAll(Arrays.asList(basePackages)); + for (Class basePackageClass : basePackageClasses) { + packagesToScan.add(ClassUtils.getPackageName(basePackageClass)); + } + if (packagesToScan.isEmpty()) { + return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName())); + } + return packagesToScan; + } + + @Override + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/schema/DubboBeanDefinitionParser.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/schema/DubboBeanDefinitionParser.java index 98b4394c273..f8d91a4790c 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/schema/DubboBeanDefinitionParser.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/schema/DubboBeanDefinitionParser.java @@ -24,7 +24,6 @@ import com.alibaba.dubbo.config.ArgumentConfig; import com.alibaba.dubbo.config.ConsumerConfig; import com.alibaba.dubbo.config.MethodConfig; -import com.alibaba.dubbo.config.MonitorConfig; import com.alibaba.dubbo.config.ProtocolConfig; import com.alibaba.dubbo.config.ProviderConfig; import com.alibaba.dubbo.config.RegistryConfig; @@ -197,11 +196,6 @@ private static BeanDefinition parse(Element element, ParserContext parserContext ProtocolConfig protocol = new ProtocolConfig(); protocol.setName(value); reference = protocol; - } else if ("monitor".equals(property) - && (!parserContext.getRegistry().containsBeanDefinition(value) - || !MonitorConfig.class.getName().equals(parserContext.getRegistry().getBeanDefinition(value).getBeanClassName()))) { - // 兼容旧版本配置 - reference = convertMonitor(value); } else if ("onreturn".equals(property)) { int index = value.lastIndexOf("."); String returnRef = value.substring(0, index); @@ -249,29 +243,6 @@ private static BeanDefinition parse(Element element, ParserContext parserContext return beanDefinition; } - protected static MonitorConfig convertMonitor(String monitor) { - if (monitor == null || monitor.length() == 0) { - return null; - } - if (GROUP_AND_VERION.matcher(monitor).matches()) { - String group; - String version; - int i = monitor.indexOf(':'); - if (i > 0) { - group = monitor.substring(0, i); - version = monitor.substring(i + 1); - } else { - group = monitor; - version = null; - } - MonitorConfig monitorConfig = new MonitorConfig(); - monitorConfig.setGroup(group); - monitorConfig.setVersion(version); - return monitorConfig; - } - return null; - } - private static boolean isPrimitive(Class cls) { return cls.isPrimitive() || cls == Boolean.class || cls == Byte.class || cls == Character.class || cls == Short.class || cls == Integer.class diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtils.java new file mode 100644 index 00000000000..0938e192caf --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtils.java @@ -0,0 +1,75 @@ +package com.alibaba.dubbo.config.spring.util; + +import com.alibaba.dubbo.common.utils.StringUtils; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; + +import java.util.*; + +import static org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors; +import static org.springframework.beans.factory.BeanFactoryUtils.beanOfTypeIncludingAncestors; +import static org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors; + +/** + * {@link BeanFactory} Utilities class + * + * @author Mercy + * @see BeanFactory + * @see ConfigurableBeanFactory + * @see org.springframework.beans.factory.BeanFactoryUtils + * @since 2.5.7 + */ +public class BeanFactoryUtils { + + + /** + * Get optional Bean + * + * @param beanFactory {@link ListableBeanFactory} + * @param beanName the name of Bean + * @param beanType the {@link Class type} of Bean + * @param the {@link Class type} of Bean + * @return A bean if present , or null + */ + public static T getOptionalBean(ListableBeanFactory beanFactory, String beanName, Class beanType) { + + String[] allBeanNames = beanNamesForTypeIncludingAncestors(beanFactory, beanType); + + if (!StringUtils.isContains(allBeanNames, beanName)) { + return null; + } + + Map beansOfType = beansOfTypeIncludingAncestors(beanFactory, beanType); + + return beansOfType.get(beanName); + + } + + + /** + * Gets name-matched Beans from {@link ListableBeanFactory BeanFactory} + * + * @param beanFactory {@link ListableBeanFactory BeanFactory} + * @param beanNames the names of Bean + * @param beanType the {@link Class type} of Bean + * @param the {@link Class type} of Bean + * @return + */ + public static List getBeans(ListableBeanFactory beanFactory, String[] beanNames, Class beanType) { + + String[] allBeanNames = beanNamesForTypeIncludingAncestors(beanFactory, beanType); + + List beans = new ArrayList(beanNames.length); + + for (String beanName : beanNames) { + if (StringUtils.isContains(allBeanNames, beanName)) { + beans.add(beanOfTypeIncludingAncestors(beanFactory, beanType)); + } + } + + return Collections.unmodifiableList(beans); + + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanRegistrar.java new file mode 100644 index 00000000000..24ae2fae65b --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanRegistrar.java @@ -0,0 +1,34 @@ +package com.alibaba.dubbo.config.spring.util; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.RootBeanDefinition; + +/** + * Bean Registrar + * + * @author Mercy + * @since 2.5.7 + */ +public class BeanRegistrar { + + /** + * Register Infrastructure Bean + * + * @param beanDefinitionRegistry {@link BeanDefinitionRegistry} + * @param beanType the type of bean + * @param beanName the name of bean + */ + public static void registerInfrastructureBean(BeanDefinitionRegistry beanDefinitionRegistry, + String beanName, + Class beanType) { + + if (!beanDefinitionRegistry.containsBeanDefinition(beanName)) { + RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType); + beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition); + } + + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd index c003d0af172..2a41cb9caef 100644 --- a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd +++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd @@ -53,7 +53,7 @@ - + @@ -83,12 +83,12 @@ - + - + @@ -297,12 +297,20 @@ + + + + + + + + @@ -677,6 +685,7 @@ + @@ -684,6 +693,11 @@ + + + + + diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/ConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/ConfigTest.java index f589fd1ceaa..878d727d249 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/ConfigTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/ConfigTest.java @@ -47,6 +47,7 @@ import com.alibaba.dubbo.rpc.service.GenericService; import junit.framework.Assert; +import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.factory.BeanCreationException; import org.springframework.context.support.ClassPathXmlApplicationContext; @@ -68,6 +69,7 @@ * * @author william.liangf */ +@Ignore public class ConfigTest { private static void unexportService(ServiceConfig config) { diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java new file mode 100644 index 00000000000..2971213907d --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java @@ -0,0 +1,109 @@ +package com.alibaba.dubbo.config.spring.beans.factory.annotation; + +import com.alibaba.dubbo.config.annotation.Reference; +import com.alibaba.dubbo.config.spring.api.DemoService; +import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.ImportResource; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.stereotype.Component; + +/** + * {@link ReferenceAnnotationBeanPostProcessor} Test + * + * @author Mercy + * @since 2.5.7 + */ +public class ReferenceAnnotationBeanPostProcessorTest { + + private static final String PROVIDER_LOCATION = "META-INF/spring/dubbo-provider.xml"; + + @Test + public void test() throws Exception { + + + // Starts Provider + new ClassPathXmlApplicationContext(PROVIDER_LOCATION); + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(TestBean.class); + + context.refresh(); + + TestBean testBean = context.getBean(TestBean.class); + + Assert.assertNotNull(testBean.getDemoServiceFromAncestor()); + Assert.assertNotNull(testBean.getDemoServiceFromParent()); + Assert.assertNotNull(testBean.getDemoService()); + + Assert.assertEquals(testBean.getDemoServiceFromAncestor(), testBean.getDemoServiceFromParent()); + Assert.assertEquals(testBean.getDemoService(), testBean.getDemoServiceFromParent()); + + DemoService demoService = testBean.getDemoService(); + + Assert.assertEquals("annotation:Mercy", demoService.sayName("Mercy")); + + context.close(); + + } + + private static class AncestorBean { + + + private DemoService demoServiceFromAncestor; + + @Autowired + private ApplicationContext applicationContext; + + public DemoService getDemoServiceFromAncestor() { + return demoServiceFromAncestor; + } + + @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345") + public void setDemoServiceFromAncestor(DemoService demoServiceFromAncestor) { + this.demoServiceFromAncestor = demoServiceFromAncestor; + } + + public ApplicationContext getApplicationContext() { + return applicationContext; + } + + } + + + private static class ParentBean extends AncestorBean { + + @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345") + private DemoService demoServiceFromParent; + + public DemoService getDemoServiceFromParent() { + return demoServiceFromParent; + } + + + } + + @ImportResource("META-INF/spring/dubbo-annotation-consumer.xml") + @DubboComponentScan(basePackageClasses = ReferenceAnnotationBeanPostProcessorTest.class) + private static class TestBean extends ParentBean { + + private DemoService demoService; + + @Autowired + private ApplicationContext applicationContext; + + public DemoService getDemoService() { + return demoService; + } + + @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345") + public void setDemoService(DemoService demoService) { + this.demoService = demoService; + } + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DemoServiceImpl.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DemoServiceImpl.java new file mode 100644 index 00000000000..c3529b31586 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DemoServiceImpl.java @@ -0,0 +1,35 @@ +package com.alibaba.dubbo.config.spring.context.annotation; + +import com.alibaba.dubbo.config.annotation.Service; +import com.alibaba.dubbo.config.spring.api.Box; +import com.alibaba.dubbo.config.spring.api.DemoService; + +/** + * {@link DemoService} Service implementation + * + * @author Mercy + * @since 2.5.7 + */ +@Service( + version = "2.5.7", + application = "dubbo-annotation-provider", + protocol = "dubbo", + registry = "my-registry" +) +public class DemoServiceImpl implements DemoService { + + @Override + public String sayName(String name) { + return "Hello," + name; + } + + @Override + public Box getBox() { + return new Box() { + @Override + public String getName() { + return "MyBox"; + } + }; + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java new file mode 100644 index 00000000000..0c6d6e2a469 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java @@ -0,0 +1,53 @@ +package com.alibaba.dubbo.config.spring.context.annotation; + +import com.alibaba.dubbo.config.spring.api.DemoService; +import com.alibaba.dubbo.config.spring.context.annotation.consumer.ConsumerConfiguration; +import com.alibaba.dubbo.config.spring.context.annotation.provider.ProviderConfiguration; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * {@link DubboComponentScanRegistrar} Test + * + * @author Mercy + * @since 2.5.7 + */ +public class DubboComponentScanRegistrarTest { + + @Test + public void test() { + + AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext(); + + providerContext.register(ProviderConfiguration.class); + + providerContext.refresh(); + + DemoService demoService = providerContext.getBean(DemoService.class); + + String value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); + + consumerContext.register(ConsumerConfiguration.class); + + consumerContext.refresh(); + + ConsumerConfiguration consumerConfiguration = consumerContext.getBean(ConsumerConfiguration.class); + + value = consumerConfiguration.getDemoService().sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + providerContext.close(); + consumerContext.close(); + + + } + + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java new file mode 100644 index 00000000000..ff10defbc7c --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java @@ -0,0 +1,31 @@ +package com.alibaba.dubbo.config.spring.context.annotation.consumer; + +import com.alibaba.dubbo.config.annotation.Reference; +import com.alibaba.dubbo.config.spring.api.DemoService; +import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; + +/** + * @author ken.lj + * @date 2017/11/3 + */ +@Configuration("consumerConfiguration") +@DubboComponentScan( + basePackageClasses = ConsumerConfiguration.class +) +@ImportResource("META-INF/spring/dubbo-annotation-consumer.xml") +public class ConsumerConfiguration { + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345") + private DemoService demoService; + + public DemoService getDemoService() { + return demoService; + } + + public void setDemoService(DemoService demoService) { + this.demoService = demoService; + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java new file mode 100644 index 00000000000..eca69c4052a --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java @@ -0,0 +1,17 @@ +package com.alibaba.dubbo.config.spring.context.annotation.provider; + +import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan; + +import org.springframework.context.annotation.ImportResource; + +/** + * @author ken.lj + * @date 2017/11/3 + */ +@DubboComponentScan(basePackages = "com.alibaba.dubbo.config.spring.context.annotation") +@ImportResource("META-INF/spring/dubbo-annotation-provider.xml") +public class ProviderConfiguration { + + +} + diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtilsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtilsTest.java new file mode 100644 index 00000000000..b39337df3e9 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtilsTest.java @@ -0,0 +1,90 @@ +package com.alibaba.dubbo.config.spring.util; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * {@link BeanFactoryUtils} Test + * + * @author Mercy + * @since 2.5.7 + */ +public class BeanFactoryUtilsTest { + + private AnnotationConfigApplicationContext applicationContext; + + @Before + public void init() { + applicationContext = new AnnotationConfigApplicationContext(); + } + + @Test + public void testGetOptionalBean() { + + applicationContext.register(TestBean.class); + + applicationContext.refresh(); + + TestBean testBean = BeanFactoryUtils.getOptionalBean(applicationContext, "testBean", TestBean.class); + + Assert.assertNotNull(testBean); + + Assert.assertEquals("Hello,World", testBean.getName()); + + } + + @Test + public void testGetOptionalBeanIfAbsent() { + + applicationContext.refresh(); + + TestBean testBean = BeanFactoryUtils.getOptionalBean(applicationContext, "testBean", TestBean.class); + + Assert.assertNull(testBean); + } + + @Test + public void testGetBeans() { + + applicationContext.register(TestBean.class); + + applicationContext.refresh(); + + List testBeans = BeanFactoryUtils.getBeans(applicationContext, new String[]{"testBean"}, TestBean.class); + + Assert.assertEquals(1, testBeans.size()); + + Assert.assertEquals("Hello,World", testBeans.get(0).getName()); + + } + + @Test + public void testGetBeansIfAbsent() { + + applicationContext.refresh(); + + List testBeans = BeanFactoryUtils.getBeans(applicationContext, new String[]{"testBean"}, TestBean.class); + + Assert.assertTrue(testBeans.isEmpty()); + + } + + @Component("testBean") + private static class TestBean { + + private String name = "Hello,World"; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-consumer.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-consumer.xml new file mode 100644 index 00000000000..73ca10ea673 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-consumer.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-provider.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-provider.xml new file mode 100644 index 00000000000..75e6a0500dc --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-provider.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-consumer.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-consumer.xml new file mode 100644 index 00000000000..6b97dad2e92 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-consumer.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml new file mode 100644 index 00000000000..f9f6de5c2f5 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/pom.xml b/dubbo-config/pom.xml index 3a2a735a7df..1303a4d1fc5 100644 --- a/dubbo-config/pom.xml +++ b/dubbo-config/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-parent - 2.5.6 + 2.5.7 dubbo-config pom diff --git a/dubbo-container/dubbo-container-api/pom.xml b/dubbo-container/dubbo-container-api/pom.xml index b18d9d584b4..ef46e4abe5e 100644 --- a/dubbo-container/dubbo-container-api/pom.xml +++ b/dubbo-container/dubbo-container-api/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-container - 2.5.6 + 2.5.7 dubbo-container-api jar diff --git a/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/dump.sh b/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/dump.sh index c0e341ae74c..d63098bb1a5 100755 --- a/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/dump.sh +++ b/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/dump.sh @@ -12,7 +12,7 @@ if [ -z "$SERVER_NAME" ]; then SERVER_NAME=`hostname` fi -PIDS=`ps -ef | grep java | grep "$CONF_DIR" |awk '{print $2}'` +PIDS=`ps -ef | grep java | grep -v grep | grep "$CONF_DIR" |awk '{print $2}'` if [ -z "$PIDS" ]; then echo "ERROR: The $SERVER_NAME does not started!" exit 1 diff --git a/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/start.sh b/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/start.sh index 8bbea8d0a5f..ed08cbc3272 100755 --- a/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/start.sh +++ b/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/start.sh @@ -7,14 +7,19 @@ CONF_DIR=$DEPLOY_DIR/conf SERVER_NAME=`sed '/dubbo.application.name/!d;s/.*=//' conf/dubbo.properties | tr -d '\r'` SERVER_PROTOCOL=`sed '/dubbo.protocol.name/!d;s/.*=//' conf/dubbo.properties | tr -d '\r'` +SERVER_HOST=`sed '/dubbo.protocol.host/!d;s/.*=//' conf/dubbo.properties | tr -d '\r'` SERVER_PORT=`sed '/dubbo.protocol.port/!d;s/.*=//' conf/dubbo.properties | tr -d '\r'` LOGS_FILE=`sed '/dubbo.log4j.file/!d;s/.*=//' conf/dubbo.properties | tr -d '\r'` +if [ -z "$SERVER_HOST" ]; then + SERVER_HOST=`127.0.0.1` +fi + if [ -z "$SERVER_NAME" ]; then SERVER_NAME=`hostname` fi -PIDS=`ps -ef | grep java | grep "$CONF_DIR" |awk '{print $2}'` +PIDS=`ps -ef | grep java | grep -v grep | grep "$CONF_DIR" |awk '{print $2}'` if [ -n "$PIDS" ]; then echo "ERROR: The $SERVER_NAME already started!" echo "PID: $PIDS" @@ -69,12 +74,12 @@ while [ $COUNT -lt 1 ]; do sleep 1 if [ -n "$SERVER_PORT" ]; then if [ "$SERVER_PROTOCOL" == "dubbo" ]; then - COUNT=`echo status | nc -i 1 127.0.0.1 $SERVER_PORT | grep -c OK` + COUNT=`echo status | nc -i 1 $SERVER_HOST $SERVER_PORT | grep -c OK` else COUNT=`netstat -an | grep $SERVER_PORT | wc -l` fi else - COUNT=`ps -f | grep java | grep "$DEPLOY_DIR" | awk '{print $2}' | wc -l` + COUNT=`ps -f | grep java | grep -v grep | grep "$DEPLOY_DIR" | awk '{print $2}' | wc -l` fi if [ $COUNT -gt 0 ]; then break @@ -82,6 +87,6 @@ while [ $COUNT -lt 1 ]; do done echo "OK!" -PIDS=`ps -f | grep java | grep "$DEPLOY_DIR" | awk '{print $2}'` +PIDS=`ps -f | grep java | grep -v grep | grep "$DEPLOY_DIR" | awk '{print $2}'` echo "PID: $PIDS" echo "STDOUT: $STDOUT_FILE" diff --git a/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/stop.sh b/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/stop.sh index 91bbd184606..8fca15e3d64 100755 --- a/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/stop.sh +++ b/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/stop.sh @@ -11,7 +11,7 @@ if [ -z "$SERVER_NAME" ]; then SERVER_NAME=`hostname` fi -PIDS=`ps -ef | grep java | grep "$CONF_DIR" |awk '{print $2}'` +PIDS=`ps -ef | grep java | grep -v grep | grep "$CONF_DIR" |awk '{print $2}'` if [ -z "$PIDS" ]; then echo "ERROR: The $SERVER_NAME does not started!" exit 1 diff --git a/dubbo-container/dubbo-container-jetty/pom.xml b/dubbo-container/dubbo-container-jetty/pom.xml index 39c346688fe..615f846cd46 100644 --- a/dubbo-container/dubbo-container-jetty/pom.xml +++ b/dubbo-container/dubbo-container-jetty/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-container - 2.5.6 + 2.5.7 dubbo-container-jetty jar diff --git a/dubbo-container/dubbo-container-log4j/pom.xml b/dubbo-container/dubbo-container-log4j/pom.xml index d1096c2573f..4abf3578f0d 100644 --- a/dubbo-container/dubbo-container-log4j/pom.xml +++ b/dubbo-container/dubbo-container-log4j/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-container - 2.5.6 + 2.5.7 dubbo-container-log4j jar diff --git a/dubbo-container/dubbo-container-logback/pom.xml b/dubbo-container/dubbo-container-logback/pom.xml index 6f225bc5045..1cf658f109c 100644 --- a/dubbo-container/dubbo-container-logback/pom.xml +++ b/dubbo-container/dubbo-container-logback/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-container - 2.5.6 + 2.5.7 dubbo-container-logback jar diff --git a/dubbo-container/dubbo-container-spring/pom.xml b/dubbo-container/dubbo-container-spring/pom.xml index d2c6b427477..6c14d64891a 100644 --- a/dubbo-container/dubbo-container-spring/pom.xml +++ b/dubbo-container/dubbo-container-spring/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-container - 2.5.6 + 2.5.7 dubbo-container-spring jar diff --git a/dubbo-container/pom.xml b/dubbo-container/pom.xml index da4c8a48211..3bab054c0f9 100644 --- a/dubbo-container/pom.xml +++ b/dubbo-container/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-parent - 2.5.6 + 2.5.7 dubbo-container pom diff --git a/dubbo-demo/dubbo-demo-api/pom.xml b/dubbo-demo/dubbo-demo-api/pom.xml index e9b96ac8adf..299adbe5e78 100644 --- a/dubbo-demo/dubbo-demo-api/pom.xml +++ b/dubbo-demo/dubbo-demo-api/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-demo - 2.5.6 + 2.5.7 dubbo-demo-api jar diff --git a/dubbo-demo/dubbo-demo-consumer/pom.xml b/dubbo-demo/dubbo-demo-consumer/pom.xml index 1779534c68b..47d77ffd6d5 100644 --- a/dubbo-demo/dubbo-demo-consumer/pom.xml +++ b/dubbo-demo/dubbo-demo-consumer/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-demo - 2.5.6 + 2.5.7 dubbo-demo-consumer jar @@ -59,6 +59,10 @@ org.apache.curator curator-framework + + com.alibaba + fastjson + log4j log4j diff --git a/dubbo-demo/dubbo-demo-provider/pom.xml b/dubbo-demo/dubbo-demo-provider/pom.xml index 26210ff7fd9..a76488018f0 100644 --- a/dubbo-demo/dubbo-demo-provider/pom.xml +++ b/dubbo-demo/dubbo-demo-provider/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-demo - 2.5.6 + 2.5.7 dubbo-demo-provider jar @@ -59,6 +59,10 @@ org.apache.curator curator-framework + + com.alibaba + fastjson + log4j log4j diff --git a/dubbo-demo/pom.xml b/dubbo-demo/pom.xml index 5bc25a617d0..dd8f575af4f 100644 --- a/dubbo-demo/pom.xml +++ b/dubbo-demo/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-parent - 2.5.6 + 2.5.7 dubbo-demo pom diff --git a/dubbo-filter/dubbo-filter-cache/pom.xml b/dubbo-filter/dubbo-filter-cache/pom.xml index 36183ae37d3..fa32e80867a 100644 --- a/dubbo-filter/dubbo-filter-cache/pom.xml +++ b/dubbo-filter/dubbo-filter-cache/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-filter - 2.5.6 + 2.5.7 dubbo-filter-cache jar diff --git a/dubbo-filter/dubbo-filter-validation/pom.xml b/dubbo-filter/dubbo-filter-validation/pom.xml index d4693917731..6809eb2393f 100644 --- a/dubbo-filter/dubbo-filter-validation/pom.xml +++ b/dubbo-filter/dubbo-filter-validation/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-filter - 2.5.6 + 2.5.7 dubbo-filter-validation jar diff --git a/dubbo-filter/dubbo-filter-validation/src/main/java/com/alibaba/dubbo/validation/MethodValidated.java b/dubbo-filter/dubbo-filter-validation/src/main/java/com/alibaba/dubbo/validation/MethodValidated.java new file mode 100644 index 00000000000..2302ec8be3c --- /dev/null +++ b/dubbo-filter/dubbo-filter-validation/src/main/java/com/alibaba/dubbo/validation/MethodValidated.java @@ -0,0 +1,23 @@ +package com.alibaba.dubbo.validation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 方法分组验证注解 + *

使用场景:当调用某个方法时,需要检查多个分组,可以在接口方法上加上该注解


+ * 用法:
   @MethodValidated({Save.class, Update.class})
+ *  void relatedQuery(ValidationParameter parameter);
+ * 在接口方法上增加注解,表示relatedQuery这个方法需要同时检查Save和Update这两个分组 + * + * @author: zhangyinyue + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface MethodValidated { + Class[] value() default {}; +} diff --git a/dubbo-filter/dubbo-filter-validation/src/main/java/com/alibaba/dubbo/validation/support/jvalidation/JValidator.java b/dubbo-filter/dubbo-filter-validation/src/main/java/com/alibaba/dubbo/validation/support/jvalidation/JValidator.java index 4c70adb710c..8d607ed8580 100644 --- a/dubbo-filter/dubbo-filter-validation/src/main/java/com/alibaba/dubbo/validation/support/jvalidation/JValidator.java +++ b/dubbo-filter/dubbo-filter-validation/src/main/java/com/alibaba/dubbo/validation/support/jvalidation/JValidator.java @@ -20,6 +20,7 @@ import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.utils.ReflectUtils; +import com.alibaba.dubbo.validation.MethodValidated; import com.alibaba.dubbo.validation.Validator; import javassist.ClassPool; @@ -55,9 +56,12 @@ 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.Date; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -146,7 +150,7 @@ private static Object getMethodParameterBean(Class clazz, Method method, Obje ctField.getFieldInfo().addAttribute(attribute); ctClass.addField(ctField); } - parameterClass = ctClass.toClass(); + parameterClass = ctClass.toClass(clazz.getClassLoader(), null); } Object parameterBean = parameterClass.newInstance(); for (int i = 0; i < args.length; i++) { @@ -231,51 +235,60 @@ else if (memberValue instanceof ArrayMemberValue) { } public void validate(String methodName, Class[] parameterTypes, Object[] arguments) throws Exception { - String methodClassName = clazz.getName() + "_" + toUpperMethoName(methodName); + List> groups = new ArrayList>(); + String methodClassName = clazz.getName() + "$" + toUpperMethoName(methodName); Class methodClass = null; try { methodClass = Class.forName(methodClassName, false, Thread.currentThread().getContextClassLoader()); + groups.add(methodClass); } catch (ClassNotFoundException e) { } Set> violations = new HashSet>(); Method method = clazz.getMethod(methodName, parameterTypes); + Class[] methodClasses = null; + if (method.isAnnotationPresent(MethodValidated.class)){ + methodClasses = method.getAnnotation(MethodValidated.class).value(); + groups.addAll(Arrays.asList(methodClasses)); + } + //加入默认分组 + groups.add(0, Default.class); + groups.add(1, clazz); + + //将list转换为数组 + Class[] classgroups = groups.toArray(new Class[0]); + Object parameterBean = getMethodParameterBean(clazz, method, arguments); if (parameterBean != null) { - if (methodClass != null) { - violations.addAll(validator.validate(parameterBean, Default.class, clazz, methodClass)); - } else { - violations.addAll(validator.validate(parameterBean, Default.class, clazz)); - } + violations.addAll(validator.validate(parameterBean, classgroups )); } + for (Object arg : arguments) { - validate(violations, arg, clazz, methodClass); + validate(violations, arg, classgroups); } + if (violations.size() > 0) { + 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 void validate(Set> violations, Object arg, Class clazz, Class methodClass) { + private void validate(Set> violations, Object arg, Class... groups) { if (arg != null && !isPrimitives(arg.getClass())) { if (Object[].class.isInstance(arg)) { for (Object item : (Object[]) arg) { - validate(violations, item, clazz, methodClass); + validate(violations, item, groups); } } else if (Collection.class.isInstance(arg)) { for (Object item : (Collection) arg) { - validate(violations, item, clazz, methodClass); + validate(violations, item, groups); } } else if (Map.class.isInstance(arg)) { for (Map.Entry entry : ((Map) arg).entrySet()) { - validate(violations, entry.getKey(), clazz, methodClass); - validate(violations, entry.getValue(), clazz, methodClass); + validate(violations, entry.getKey(), groups); + validate(violations, entry.getValue(), groups); } } else { - if (methodClass != null) { - violations.addAll(validator.validate(arg, Default.class, clazz, methodClass)); - } else { - violations.addAll(validator.validate(arg, Default.class, clazz)); - } + violations.addAll(validator.validate(arg, groups)); } } } diff --git a/dubbo-filter/pom.xml b/dubbo-filter/pom.xml index aeaa2075d5c..efecc38d6b4 100644 --- a/dubbo-filter/pom.xml +++ b/dubbo-filter/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-parent - 2.5.6 + 2.5.7 dubbo-filter pom diff --git a/dubbo-maven/pom.xml b/dubbo-maven/pom.xml index 37b4e8dcacf..534e5e0d01e 100644 --- a/dubbo-maven/pom.xml +++ b/dubbo-maven/pom.xml @@ -23,7 +23,7 @@ com.alibaba dubbo - 2.5.6 + 2.5.7 jar Dubbo Dubbo is a distributed service framework enpowers applications with service import/export capability diff --git a/dubbo-monitor/dubbo-monitor-api/pom.xml b/dubbo-monitor/dubbo-monitor-api/pom.xml index f45bb0a2840..cb7680b34de 100644 --- a/dubbo-monitor/dubbo-monitor-api/pom.xml +++ b/dubbo-monitor/dubbo-monitor-api/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-monitor - 2.5.6 + 2.5.7 dubbo-monitor-api jar diff --git a/dubbo-monitor/dubbo-monitor-api/src/main/java/com/alibaba/dubbo/monitor/support/AbstractMonitorFactory.java b/dubbo-monitor/dubbo-monitor-api/src/main/java/com/alibaba/dubbo/monitor/support/AbstractMonitorFactory.java index 3a8f477822a..8e91ab3f8c3 100644 --- a/dubbo-monitor/dubbo-monitor-api/src/main/java/com/alibaba/dubbo/monitor/support/AbstractMonitorFactory.java +++ b/dubbo-monitor/dubbo-monitor-api/src/main/java/com/alibaba/dubbo/monitor/support/AbstractMonitorFactory.java @@ -17,6 +17,11 @@ import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.concurrent.ListenableFuture; +import com.alibaba.dubbo.common.concurrent.ListenableFutureTask; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; import com.alibaba.dubbo.monitor.Monitor; import com.alibaba.dubbo.monitor.MonitorFactory; import com.alibaba.dubbo.monitor.MonitorService; @@ -24,7 +29,14 @@ import java.util.Collection; import java.util.Collections; import java.util.Map; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; /** @@ -33,6 +45,7 @@ * @author william.liangf */ public abstract class AbstractMonitorFactory implements MonitorFactory { + private static final Logger logger = LoggerFactory.getLogger(AbstractMonitorFactory.class); // 注册中心获取过程锁 private static final ReentrantLock LOCK = new ReentrantLock(); @@ -40,6 +53,10 @@ public abstract class AbstractMonitorFactory implements MonitorFactory { // 注册中心集合 Map private static final Map MONITORS = new ConcurrentHashMap(); + private static final Map> FUTURES = new ConcurrentHashMap>(); + + private static final ExecutorService executor = new ThreadPoolExecutor(0, 10, 60L, TimeUnit.SECONDS, new SynchronousQueue(), new NamedThreadFactory("DubboMonitorCreator", true)); + public static Collection getMonitors() { return Collections.unmodifiableCollection(MONITORS.values()); } @@ -47,18 +64,27 @@ public static Collection getMonitors() { public Monitor getMonitor(URL url) { url = url.setPath(MonitorService.class.getName()).addParameter(Constants.INTERFACE_KEY, MonitorService.class.getName()); String key = url.toServiceStringWithoutResolving(); + Monitor monitor = MONITORS.get(key); + Future future = FUTURES.get(key); + if (monitor != null || future != null) { + return monitor; + } + LOCK.lock(); try { - Monitor monitor = MONITORS.get(key); - if (monitor != null) { + monitor = MONITORS.get(key); + future = FUTURES.get(key); + if (monitor != null || future != null) { return monitor; } - monitor = createMonitor(url); - if (monitor == null) { - throw new IllegalStateException("Can not create monitor " + url); - } - MONITORS.put(key, monitor); - return monitor; + + final URL monitorUrl = url; + final ListenableFutureTask listenableFutureTask = ListenableFutureTask.create(new MonitorCreator(monitorUrl)); + listenableFutureTask.addListener(new MonitorListener(key)); + executor.execute(listenableFutureTask); + FUTURES.put(key, listenableFutureTask); + + return null; } finally { // 释放锁 LOCK.unlock(); @@ -67,4 +93,42 @@ public Monitor getMonitor(URL url) { protected abstract Monitor createMonitor(URL url); -} \ No newline at end of file + class MonitorCreator implements Callable { + + private URL url; + + public MonitorCreator(URL url) { + this.url = url; + } + + @Override + public Monitor call() throws Exception { + Monitor monitor = AbstractMonitorFactory.this.createMonitor(url); + return monitor; + } + } + + class MonitorListener implements Runnable { + + private String key; + + public MonitorListener(String key) { + this.key = key; + } + + @Override + public void run() { + try { + ListenableFuture listenableFuture = AbstractMonitorFactory.FUTURES.get(key); + AbstractMonitorFactory.MONITORS.put(key, listenableFuture.get()); + AbstractMonitorFactory.FUTURES.remove(key); + } catch (InterruptedException e) { + logger.warn("Thread was interrupted unexpectedly, monitor will never be got."); + AbstractMonitorFactory.FUTURES.remove(key); + } catch (ExecutionException e) { + logger.warn("Create monitor failed, monitor data will not be collected until you fix this problem. ", e); + } + } + } + +} diff --git a/dubbo-monitor/dubbo-monitor-api/src/main/java/com/alibaba/dubbo/monitor/support/MonitorFilter.java b/dubbo-monitor/dubbo-monitor-api/src/main/java/com/alibaba/dubbo/monitor/support/MonitorFilter.java index 7d0061c657d..702346fc15c 100644 --- a/dubbo-monitor/dubbo-monitor-api/src/main/java/com/alibaba/dubbo/monitor/support/MonitorFilter.java +++ b/dubbo-monitor/dubbo-monitor-api/src/main/java/com/alibaba/dubbo/monitor/support/MonitorFilter.java @@ -87,6 +87,9 @@ private void collect(Invoker invoker, Invocation invocation, Result result, S String method = RpcUtils.getMethodName(invocation); // 获取方法名 URL url = invoker.getUrl().getUrlParameter(Constants.MONITOR_KEY); Monitor monitor = monitorFactory.getMonitor(url); + if (monitor == null) { + return; + } int localPort; String remoteKey; String remoteValue; diff --git a/dubbo-monitor/dubbo-monitor-api/src/test/java/com/alibaba/dubbo/monitor/support/AbstractMonitorFactoryTest.java b/dubbo-monitor/dubbo-monitor-api/src/test/java/com/alibaba/dubbo/monitor/support/AbstractMonitorFactoryTest.java index f51a31f7962..481baefec38 100644 --- a/dubbo-monitor/dubbo-monitor-api/src/test/java/com/alibaba/dubbo/monitor/support/AbstractMonitorFactoryTest.java +++ b/dubbo-monitor/dubbo-monitor-api/src/test/java/com/alibaba/dubbo/monitor/support/AbstractMonitorFactoryTest.java @@ -64,20 +64,38 @@ public void testMonitorFactoryCache() throws Exception { URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostAddress() + ":2233"); Monitor monitor1 = monitorFactory.getMonitor(url); Monitor monitor2 = monitorFactory.getMonitor(url); + if (monitor1 == null || monitor2 == null) { + Thread.sleep(2000); + monitor1 = monitorFactory.getMonitor(url); + monitor2 = monitorFactory.getMonitor(url); + } Assert.assertEquals(monitor1, monitor2); } @Test public void testMonitorFactoryIpCache() throws Exception { - Monitor monitor1 = monitorFactory.getMonitor(URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":2233")); - Monitor monitor2 = monitorFactory.getMonitor(URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostAddress() + ":2233")); + URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":2233"); + Monitor monitor1 = monitorFactory.getMonitor(url); + Monitor monitor2 = monitorFactory.getMonitor(url); + if (monitor1 == null || monitor2 == null) { + Thread.sleep(2000); + monitor1 = monitorFactory.getMonitor(url); + monitor2 = monitorFactory.getMonitor(url); + } Assert.assertEquals(monitor1, monitor2); } @Test public void testMonitorFactoryGroupCache() throws Exception { - Monitor monitor1 = monitorFactory.getMonitor(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":2233?group=aaa")); - Monitor monitor2 = monitorFactory.getMonitor(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":2233?group=bbb")); + URL url1 = URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":2233?group=aaa"); + URL url2 = URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":2233?group=bbb"); + Monitor monitor1 = monitorFactory.getMonitor(url1); + Monitor monitor2 = monitorFactory.getMonitor(url2); + if (monitor1 == null || monitor2 == null) { + Thread.sleep(2000); + monitor1 = monitorFactory.getMonitor(url1); + monitor2 = monitorFactory.getMonitor(url2); + } Assert.assertNotSame(monitor1, monitor2); } diff --git a/dubbo-monitor/dubbo-monitor-default/pom.xml b/dubbo-monitor/dubbo-monitor-default/pom.xml index 7628fe4927c..05ae615f83d 100644 --- a/dubbo-monitor/dubbo-monitor-default/pom.xml +++ b/dubbo-monitor/dubbo-monitor-default/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-monitor - 2.5.6 + 2.5.7 dubbo-monitor-default jar diff --git a/dubbo-monitor/dubbo-monitor-default/src/test/java/com/alibaba/dubbo/monitor/dubbo/DubboMonitorTest.java b/dubbo-monitor/dubbo-monitor-default/src/test/java/com/alibaba/dubbo/monitor/dubbo/DubboMonitorTest.java index b7003870d98..c43502f370d 100644 --- a/dubbo-monitor/dubbo-monitor-default/src/test/java/com/alibaba/dubbo/monitor/dubbo/DubboMonitorTest.java +++ b/dubbo-monitor/dubbo-monitor-default/src/test/java/com/alibaba/dubbo/monitor/dubbo/DubboMonitorTest.java @@ -129,20 +129,30 @@ public void testMonitorFactory() throws Exception { Exporter exporter = protocol.export(proxyFactory.getInvoker(monitorService, MonitorService.class, URL.valueOf("dubbo://127.0.0.1:17979/" + MonitorService.class.getName()))); try { - Monitor monitor = monitorFactory.getMonitor(URL.valueOf("dubbo://127.0.0.1:17979?interval=10")); - try { - monitor.collect(statistics); - int i = 0; - while (monitorService.getStatistics() == null && i < 200) { - i++; - Thread.sleep(10); + Monitor monitor = null; + long start = System.currentTimeMillis(); + // 如果60s都拿不到 + while (System.currentTimeMillis() - start < 60000) { + monitor = monitorFactory.getMonitor(URL.valueOf("dubbo://127.0.0.1:17979?interval=10")); + if (monitor == null) { + continue; } - URL result = monitorService.getStatistics(); - Assert.assertEquals(1, result.getParameter(MonitorService.SUCCESS, 0)); - Assert.assertEquals(3, result.getParameter(MonitorService.ELAPSED, 0)); - } finally { - monitor.destroy(); + try { + monitor.collect(statistics); + int i = 0; + while (monitorService.getStatistics() == null && i < 200) { + i++; + Thread.sleep(10); + } + URL result = monitorService.getStatistics(); + Assert.assertEquals(1, result.getParameter(MonitorService.SUCCESS, 0)); + Assert.assertEquals(3, result.getParameter(MonitorService.ELAPSED, 0)); + } finally { + monitor.destroy(); + } + break; } + Assert.assertNotNull(monitor); } finally { exporter.unexport(); } diff --git a/dubbo-monitor/pom.xml b/dubbo-monitor/pom.xml index 11f331575af..3c8b4270696 100644 --- a/dubbo-monitor/pom.xml +++ b/dubbo-monitor/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-parent - 2.5.6 + 2.5.7 dubbo-monitor pom diff --git a/dubbo-registry/dubbo-registry-api/pom.xml b/dubbo-registry/dubbo-registry-api/pom.xml index da00055e992..5ead3bb55ad 100644 --- a/dubbo-registry/dubbo-registry-api/pom.xml +++ b/dubbo-registry/dubbo-registry-api/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-registry - 2.5.6 + 2.5.7 dubbo-registry-api jar diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryDirectory.java index f3979b28324..cb659e8f4b9 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryDirectory.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryDirectory.java @@ -486,12 +486,13 @@ private Map>> toMethodInvokers(Map> i invokersList.add(invoker); } } - newMethodInvokerMap.put(Constants.ANY_VALUE, invokersList); + List> newInvokersList = route(invokersList, null); + newMethodInvokerMap.put(Constants.ANY_VALUE, newInvokersList); if (serviceMethods != null && serviceMethods.length > 0) { for (String method : serviceMethods) { List> methodInvokers = newMethodInvokerMap.get(method); if (methodInvokers == null || methodInvokers.size() == 0) { - methodInvokers = invokersList; + methodInvokers = newInvokersList; } newMethodInvokerMap.put(method, route(methodInvokers, method)); } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java index 0db690db189..1a73fb570ed 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java @@ -20,7 +20,6 @@ import com.alibaba.dubbo.common.extension.ExtensionLoader; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; -import com.alibaba.dubbo.common.utils.NetUtils; import com.alibaba.dubbo.common.utils.StringUtils; import com.alibaba.dubbo.common.utils.UrlUtils; import com.alibaba.dubbo.registry.NotifyListener; @@ -37,6 +36,7 @@ import com.alibaba.dubbo.rpc.protocol.InvokerWrapper; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -210,7 +210,10 @@ private Registry getRegistry(final Invoker originInvoker) { private URL getRegistedProviderUrl(final Invoker originInvoker) { URL providerUrl = getProviderUrl(originInvoker); //注册中心看到的地址 - final URL registedProviderUrl = providerUrl.removeParameters(getFilteredKeys(providerUrl)).removeParameter(Constants.MONITOR_KEY); + final URL registedProviderUrl = providerUrl.removeParameters(getFilteredKeys(providerUrl)) + .removeParameter(Constants.MONITOR_KEY) + .removeParameter(Constants.BIND_IP_KEY) + .removeParameter(Constants.BIND_PORT_KEY); return registedProviderUrl; } @@ -276,7 +279,9 @@ private Invoker doRefer(Cluster cluster, Registry registry, Class type RegistryDirectory directory = new RegistryDirectory(type, url); directory.setRegistry(registry); directory.setProtocol(protocol); - URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, NetUtils.getLocalHost(), 0, type.getName(), directory.getUrl().getParameters()); + // REFER_KEY的所有属性 + Map parameters = new HashMap(directory.getUrl().getParameters()); + URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, parameters.remove(Constants.REGISTER_IP_KEY), 0, type.getName(), parameters); if (!Constants.ANY_VALUE.equals(url.getServiceInterface()) && url.getParameter(Constants.REGISTER_KEY, true)) { registry.register(subscribeUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY, diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/AbstractRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/AbstractRegistry.java index face7ca7e32..a347c411e7c 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/AbstractRegistry.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/AbstractRegistry.java @@ -83,7 +83,7 @@ public AbstractRegistry(URL url) { setUrl(url); // 启动文件保存定时器 syncSaveFile = url.getParameter(Constants.REGISTRY_FILESAVE_SYNC_KEY, false); - String filename = url.getParameter(Constants.FILE_KEY, System.getProperty("user.home") + "/.dubbo/dubbo-registry-" + url.getHost() + ".cache"); + String filename = url.getParameter(Constants.FILE_KEY, System.getProperty("user.home") + "/.dubbo/dubbo-registry-" + url.getParameter(Constants.APPLICATION_KEY) + "-" + url.getAddress() + ".cache"); File file = null; if (ConfigUtils.isNotEmpty(filename)) { file = new File(filename); @@ -149,28 +149,8 @@ public void doSaveProperties(long version) { if (file == null) { return; } - Properties newProperties = new Properties(); - // 保存之前先读取一遍,防止多个注册中心之间冲突 - InputStream in = null; - try { - if (file.exists()) { - in = new FileInputStream(file); - newProperties.load(in); - } - } catch (Throwable e) { - logger.warn("Failed to load registry store file, cause: " + e.getMessage(), e); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - logger.warn(e.getMessage(), e); - } - } - } // 保存 try { - newProperties.putAll(properties); File lockfile = new File(file.getAbsolutePath() + ".lock"); if (!lockfile.exists()) { lockfile.createNewFile(); @@ -190,7 +170,7 @@ public void doSaveProperties(long version) { } FileOutputStream outputFile = new FileOutputStream(file); try { - newProperties.store(outputFile, "Dubbo Registry Cache"); + properties.store(outputFile, "Dubbo Registry Cache"); } finally { outputFile.close(); } diff --git a/dubbo-registry/dubbo-registry-default/pom.xml b/dubbo-registry/dubbo-registry-default/pom.xml index 5cf42f6afda..208314760f9 100644 --- a/dubbo-registry/dubbo-registry-default/pom.xml +++ b/dubbo-registry/dubbo-registry-default/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-registry - 2.5.6 + 2.5.7 dubbo-registry-default jar diff --git a/dubbo-registry/dubbo-registry-default/src/test/java/com/alibaba/dubbo/registry/dubbo/RegistryDirectoryTest.java b/dubbo-registry/dubbo-registry-default/src/test/java/com/alibaba/dubbo/registry/dubbo/RegistryDirectoryTest.java index c538ef09f76..950d6d3d775 100644 --- a/dubbo-registry/dubbo-registry-default/src/test/java/com/alibaba/dubbo/registry/dubbo/RegistryDirectoryTest.java +++ b/dubbo-registry/dubbo-registry-default/src/test/java/com/alibaba/dubbo/registry/dubbo/RegistryDirectoryTest.java @@ -56,10 +56,10 @@ public class RegistryDirectoryTest { String service = DemoService.class.getName(); RpcInvocation invocation = new RpcInvocation(); URL noMeaningUrl = URL.valueOf("notsupport:/" + service + "?refer=" + URL.encode("interface=" + service)); - URL SERVICEURL = URL.valueOf("dubbo://127.0.0.1:9091/" + service + "?lazy=true"); - URL SERVICEURL2 = URL.valueOf("dubbo://127.0.0.1:9092/" + service + "?lazy=true"); - URL SERVICEURL3 = URL.valueOf("dubbo://127.0.0.1:9093/" + service + "?lazy=true"); - URL SERVICEURL_DUBBO_NOPATH = URL.valueOf("dubbo://127.0.0.1:9092" + "?lazy=true"); + URL SERVICEURL = URL.valueOf("dubbo://127.0.0.1:9091/" + service + "?lazy=true&side=consumer"); + URL SERVICEURL2 = URL.valueOf("dubbo://127.0.0.1:9092/" + service + "?lazy=true&side=consumer"); + URL SERVICEURL3 = URL.valueOf("dubbo://127.0.0.1:9093/" + service + "?lazy=true&side=consumer"); + URL SERVICEURL_DUBBO_NOPATH = URL.valueOf("dubbo://127.0.0.1:9092" + "?lazy=true&side=consumer"); @Before public void setUp() { @@ -694,8 +694,8 @@ public void testNofityOverrideUrls_Provider() { invocation = new RpcInvocation(); List durls = new ArrayList(); - durls.add(SERVICEURL.setHost("10.20.30.140").addParameter("timeout", "1"));//一个一样,一个不一样 - durls.add(SERVICEURL2.setHost("10.20.30.141").addParameter("timeout", "2")); + durls.add(SERVICEURL.setHost("10.20.30.140").addParameter("timeout", "1").addParameter(Constants.SIDE_KEY, Constants.CONSUMER_SIDE));//一个一样,一个不一样 + durls.add(SERVICEURL2.setHost("10.20.30.141").addParameter("timeout", "2").addParameter(Constants.SIDE_KEY, Constants.CONSUMER_SIDE)); registryDirectory.notify(durls); durls = new ArrayList(); @@ -835,7 +835,7 @@ public void testNofityOverrideUrls_disabled_specifiedProvider() { registryDirectory.notify(durls); durls = new ArrayList(); - durls.add(URL.valueOf("override://10.20.30.140?" + Constants.DISABLED_KEY + "=true")); + durls.add(URL.valueOf("override://10.20.30.140:9091?" + Constants.DISABLED_KEY + "=true")); registryDirectory.notify(durls); List> invokers = registryDirectory.list(invocation); @@ -901,7 +901,7 @@ public void testNofity_disabled_specifiedProvider() { // 通过覆盖规则启用 durls = new ArrayList(); - durls.add(URL.valueOf("override://10.20.30.140?" + Constants.DISABLED_KEY + "=false")); + durls.add(URL.valueOf("override://10.20.30.140:9091?" + Constants.DISABLED_KEY + "=false")); registryDirectory.notify(durls); List> invokers2 = registryDirectory.list(invocation); Assert.assertEquals(2, invokers2.size()); diff --git a/dubbo-registry/dubbo-registry-default/src/test/java/com/alibaba/dubbo/registry/dubbo/RegistryProtocolTest.java b/dubbo-registry/dubbo-registry-default/src/test/java/com/alibaba/dubbo/registry/dubbo/RegistryProtocolTest.java index f9670fd0504..45c9f670248 100644 --- a/dubbo-registry/dubbo-registry-default/src/test/java/com/alibaba/dubbo/registry/dubbo/RegistryProtocolTest.java +++ b/dubbo-registry/dubbo-registry-default/src/test/java/com/alibaba/dubbo/registry/dubbo/RegistryProtocolTest.java @@ -53,7 +53,7 @@ public class RegistryProtocolTest { } final String service = "com.alibaba.dubbo.registry.protocol.DemoService:1.0.0"; - final String serviceUrl = "dubbo://127.0.0.1:9453/" + service + "?notify=true&methods=test1,test2"; + 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(); diff --git a/dubbo-registry/dubbo-registry-multicast/pom.xml b/dubbo-registry/dubbo-registry-multicast/pom.xml index 702d0c83229..2174d5bcf82 100644 --- a/dubbo-registry/dubbo-registry-multicast/pom.xml +++ b/dubbo-registry/dubbo-registry-multicast/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-registry - 2.5.6 + 2.5.7 dubbo-registry-multicast jar diff --git a/dubbo-registry/dubbo-registry-redis/pom.xml b/dubbo-registry/dubbo-registry-redis/pom.xml index 71dd24d3590..1ebd27dc646 100644 --- a/dubbo-registry/dubbo-registry-redis/pom.xml +++ b/dubbo-registry/dubbo-registry-redis/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-registry - 2.5.6 + 2.5.7 dubbo-registry-redis jar diff --git a/dubbo-registry/dubbo-registry-zookeeper/pom.xml b/dubbo-registry/dubbo-registry-zookeeper/pom.xml index 383d53c340f..5ab4ebcd1ea 100644 --- a/dubbo-registry/dubbo-registry-zookeeper/pom.xml +++ b/dubbo-registry/dubbo-registry-zookeeper/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-registry - 2.5.6 + 2.5.7 dubbo-registry-zookeeper jar diff --git a/dubbo-registry/pom.xml b/dubbo-registry/pom.xml index 87a3ef2770e..2e4bbd2b25b 100644 --- a/dubbo-registry/pom.xml +++ b/dubbo-registry/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-parent - 2.5.6 + 2.5.7 dubbo-registry pom diff --git a/dubbo-remoting/dubbo-remoting-api/pom.xml b/dubbo-remoting/dubbo-remoting-api/pom.xml index 349f5f4c34e..36cd82c0110 100644 --- a/dubbo-remoting/dubbo-remoting-api/pom.xml +++ b/dubbo-remoting/dubbo-remoting-api/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-remoting - 2.5.6 + 2.5.7 dubbo-remoting-api jar diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/AbstractServer.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/AbstractServer.java index 7ce8025f2fb..0d166f56e23 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/AbstractServer.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/AbstractServer.java @@ -52,10 +52,13 @@ public abstract class AbstractServer extends AbstractEndpoint implements Server public AbstractServer(URL url, ChannelHandler handler) throws RemotingException { super(url, handler); localAddress = getUrl().toInetSocketAddress(); - String host = url.getParameter(Constants.ANYHOST_KEY, false) - || NetUtils.isInvalidLocalHost(getUrl().getHost()) - ? NetUtils.ANYHOST : getUrl().getHost(); - bindAddress = new InetSocketAddress(host, getUrl().getPort()); + + String bindIp = getUrl().getParameter(Constants.BIND_IP_KEY, getUrl().getHost()); + int bindPort = getUrl().getParameter(Constants.BIND_PORT_KEY, getUrl().getPort()); + if (url.getParameter(Constants.ANYHOST_KEY, false) || NetUtils.isInvalidLocalHost(bindIp)) { + bindIp = NetUtils.ANYHOST; + } + bindAddress = new InetSocketAddress(bindIp, bindPort); this.accepts = url.getParameter(Constants.ACCEPTS_KEY, Constants.DEFAULT_ACCEPTS); this.idleTimeout = url.getParameter(Constants.IDLE_TIMEOUT_KEY, Constants.DEFAULT_IDLE_TIMEOUT); try { diff --git a/dubbo-remoting/dubbo-remoting-grizzly/pom.xml b/dubbo-remoting/dubbo-remoting-grizzly/pom.xml index f1746666811..dc97041b9ca 100644 --- a/dubbo-remoting/dubbo-remoting-grizzly/pom.xml +++ b/dubbo-remoting/dubbo-remoting-grizzly/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-remoting - 2.5.6 + 2.5.7 dubbo-remoting-grizzly jar diff --git a/dubbo-remoting/dubbo-remoting-http/pom.xml b/dubbo-remoting/dubbo-remoting-http/pom.xml index ee6194c5e78..a50faa330d6 100644 --- a/dubbo-remoting/dubbo-remoting-http/pom.xml +++ b/dubbo-remoting/dubbo-remoting-http/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-remoting - 2.5.6 + 2.5.7 dubbo-remoting-http jar diff --git a/dubbo-remoting/dubbo-remoting-http/src/main/java/com/alibaba/dubbo/remoting/http/jetty/JettyHttpServer.java b/dubbo-remoting/dubbo-remoting-http/src/main/java/com/alibaba/dubbo/remoting/http/jetty/JettyHttpServer.java index 56e7f45fb03..fc478ce4fbd 100644 --- a/dubbo-remoting/dubbo-remoting-http/src/main/java/com/alibaba/dubbo/remoting/http/jetty/JettyHttpServer.java +++ b/dubbo-remoting/dubbo-remoting-http/src/main/java/com/alibaba/dubbo/remoting/http/jetty/JettyHttpServer.java @@ -38,7 +38,7 @@ public class JettyHttpServer extends AbstractHttpServer { public JettyHttpServer(URL url, final HttpHandler handler) { super(url, handler); - DispatcherServlet.addHttpHandler(url.getPort(), handler); + DispatcherServlet.addHttpHandler(url.getParameter(Constants.BIND_PORT_KEY, url.getPort()), handler); int threads = url.getParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS); QueuedThreadPool threadPool = new QueuedThreadPool(); @@ -47,10 +47,12 @@ public JettyHttpServer(URL url, final HttpHandler handler) { threadPool.setMinThreads(threads); SelectChannelConnector connector = new SelectChannelConnector(); - if (!url.isAnyHost() && NetUtils.isValidLocalHost(url.getHost())) { - connector.setHost(url.getHost()); + + String bindIp = url.getParameter(Constants.BIND_IP_KEY, url.getHost()); + if (!url.isAnyHost() && NetUtils.isValidLocalHost(bindIp)) { + connector.setHost(bindIp); } - connector.setPort(url.getPort()); + connector.setPort(url.getParameter(Constants.BIND_PORT_KEY, url.getPort())); server = new Server(); server.setThreadPool(threadPool); @@ -65,7 +67,7 @@ public JettyHttpServer(URL url, final HttpHandler handler) { try { server.start(); } catch (Exception e) { - throw new IllegalStateException("Failed to start jetty server on " + url.getAddress() + ", cause: " + throw new IllegalStateException("Failed to start jetty server on " + url.getParameter(Constants.BIND_IP_KEY) + ":" + url.getParameter(Constants.BIND_PORT_KEY) + ", cause: " + e.getMessage(), e); } } diff --git a/dubbo-remoting/dubbo-remoting-http/src/main/java/com/alibaba/dubbo/remoting/http/servlet/ServletHttpServer.java b/dubbo-remoting/dubbo-remoting-http/src/main/java/com/alibaba/dubbo/remoting/http/servlet/ServletHttpServer.java index 9f27354e232..c75cc1b50d7 100644 --- a/dubbo-remoting/dubbo-remoting-http/src/main/java/com/alibaba/dubbo/remoting/http/servlet/ServletHttpServer.java +++ b/dubbo-remoting/dubbo-remoting-http/src/main/java/com/alibaba/dubbo/remoting/http/servlet/ServletHttpServer.java @@ -15,6 +15,7 @@ */ package com.alibaba.dubbo.remoting.http.servlet; +import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.remoting.http.HttpHandler; import com.alibaba.dubbo.remoting.http.support.AbstractHttpServer; @@ -23,7 +24,7 @@ public class ServletHttpServer extends AbstractHttpServer { public ServletHttpServer(URL url, HttpHandler handler) { super(url, handler); - DispatcherServlet.addHttpHandler(url.getPort(), handler); + DispatcherServlet.addHttpHandler(url.getParameter(Constants.BIND_PORT_KEY, 8080), handler); } } \ No newline at end of file diff --git a/dubbo-remoting/dubbo-remoting-mina/pom.xml b/dubbo-remoting/dubbo-remoting-mina/pom.xml index ae2b129b1af..89e353baffc 100644 --- a/dubbo-remoting/dubbo-remoting-mina/pom.xml +++ b/dubbo-remoting/dubbo-remoting-mina/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-remoting - 2.5.6 + 2.5.7 dubbo-remoting-mina jar diff --git a/dubbo-remoting/dubbo-remoting-netty/pom.xml b/dubbo-remoting/dubbo-remoting-netty/pom.xml index 6f7418158df..b56696a8f00 100644 --- a/dubbo-remoting/dubbo-remoting-netty/pom.xml +++ b/dubbo-remoting/dubbo-remoting-netty/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-remoting - 2.5.6 + 2.5.7 dubbo-remoting-netty jar diff --git a/dubbo-remoting/dubbo-remoting-netty/src/test/java/com/alibaba/dubbo/remoting/transport/netty/ClientReconnectTest.java b/dubbo-remoting/dubbo-remoting-netty/src/test/java/com/alibaba/dubbo/remoting/transport/netty/ClientReconnectTest.java index 3b882a80294..fd322c3121b 100644 --- a/dubbo-remoting/dubbo-remoting-netty/src/test/java/com/alibaba/dubbo/remoting/transport/netty/ClientReconnectTest.java +++ b/dubbo-remoting/dubbo-remoting-netty/src/test/java/com/alibaba/dubbo/remoting/transport/netty/ClientReconnectTest.java @@ -28,6 +28,7 @@ import org.apache.log4j.Level; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; /** @@ -40,6 +41,11 @@ public static void main(String[] args) { System.out.println(3 % 1); } + @Before + public void clear() { + DubboAppender.clear(); + } + @Test public void testReconnect() throws RemotingException, InterruptedException { { @@ -90,9 +96,9 @@ public void testReconnectWarnLog() throws RemotingException, InterruptedExceptio DubboAppender.doStop(); } - /** + /* *//** * 重连日志的校验,不能一直抛出error日志. - */ + *//* @Test public void testReconnectErrorLog() throws RemotingException, InterruptedException { int port = NetUtils.getAvailablePort(); @@ -110,9 +116,9 @@ public void testReconnectErrorLog() throws RemotingException, InterruptedExcepti DubboAppender.doStop(); } - /** + *//** * 测试client重连方法不会导致重连线程失效. - */ + *//* @Test public void testClientReconnectMethod() throws RemotingException, InterruptedException { int port = NetUtils.getAvailablePort(); @@ -131,9 +137,9 @@ public void testClientReconnectMethod() throws RemotingException, InterruptedExc DubboAppender.doStop(); } - /** + *//** * 重连日志的校验 - */ + *//* @Test public void testReconnectWaringLog() throws RemotingException, InterruptedException { int port = NetUtils.getAvailablePort(); @@ -157,7 +163,7 @@ public void testReconnectWaringLog() throws RemotingException, InterruptedExcept } Assert.assertTrue("warning message count must >= 1, real :" + count, count >= 1); DubboAppender.doStop(); - } + }*/ public Client startClient(int port, int reconnectPeriod) throws RemotingException { final String url = "exchange://127.0.0.1:" + port + "/client.reconnect.test?check=false&" + Constants.RECONNECT_KEY + "=" + reconnectPeriod; diff --git a/dubbo-remoting/dubbo-remoting-netty4/pom.xml b/dubbo-remoting/dubbo-remoting-netty4/pom.xml index dfd51f13862..89220456b90 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/pom.xml +++ b/dubbo-remoting/dubbo-remoting-netty4/pom.xml @@ -3,7 +3,7 @@ dubbo-remoting com.alibaba - 2.5.6 + 2.5.7 4.0.0 diff --git a/dubbo-remoting/dubbo-remoting-p2p/pom.xml b/dubbo-remoting/dubbo-remoting-p2p/pom.xml index cf21d10d623..3e3199db92d 100644 --- a/dubbo-remoting/dubbo-remoting-p2p/pom.xml +++ b/dubbo-remoting/dubbo-remoting-p2p/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-remoting - 2.5.6 + 2.5.7 dubbo-remoting-p2p jar diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/pom.xml b/dubbo-remoting/dubbo-remoting-zookeeper/pom.xml index d93699a98e6..6ca92a54801 100644 --- a/dubbo-remoting/dubbo-remoting-zookeeper/pom.xml +++ b/dubbo-remoting/dubbo-remoting-zookeeper/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-remoting - 2.5.6 + 2.5.7 dubbo-remoting-zookeeper jar diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/com/alibaba/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/com/alibaba/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java index 4f20ae76b17..f211a3e02a3 100644 --- a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/com/alibaba/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java +++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/com/alibaba/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java @@ -27,7 +27,7 @@ public CuratorZookeeperClient(URL url) { try { CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder() .connectString(url.getBackupAddress()) - .retryPolicy(new RetryNTimes(Integer.MAX_VALUE, 1000)) + .retryPolicy(new RetryNTimes(1, 1000)) .connectionTimeoutMs(5000); String authority = url.getAuthority(); if (authority != null && authority.length() > 0) { @@ -88,6 +88,15 @@ public List getChildren(String path) { } } + public boolean checkExists(String path) { + try { + if (client.checkExists().forPath(path) != null) { + return true; + } + } catch (Exception e) { + } + return false; + } public boolean isConnected() { return client.getZookeeperClient().isConnected(); } diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/com/alibaba/dubbo/remoting/zookeeper/support/AbstractZookeeperClient.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/com/alibaba/dubbo/remoting/zookeeper/support/AbstractZookeeperClient.java index 8b89efb1891..f9ff9639dd4 100644 --- a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/com/alibaba/dubbo/remoting/zookeeper/support/AbstractZookeeperClient.java +++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/com/alibaba/dubbo/remoting/zookeeper/support/AbstractZookeeperClient.java @@ -36,7 +36,10 @@ public URL getUrl() { public void create(String path, boolean ephemeral) { int i = path.lastIndexOf('/'); if (i > 0) { - create(path.substring(0, i), false); + String parentPath = path.substring(0, i); + if (!checkExists(parentPath)) { + create(parentPath, false); + } } if (ephemeral) { createEphemeral(path); @@ -105,6 +108,8 @@ public void close() { protected abstract void createEphemeral(String path); + protected abstract boolean checkExists(String path); + protected abstract TargetChildListener createTargetChildListener(String path, ChildListener listener); protected abstract List addTargetChildListener(String path, TargetChildListener listener); diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/com/alibaba/dubbo/remoting/zookeeper/zkclient/ZkClientWrapper.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/com/alibaba/dubbo/remoting/zookeeper/zkclient/ZkClientWrapper.java new file mode 100644 index 00000000000..318443ae53c --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/com/alibaba/dubbo/remoting/zookeeper/zkclient/ZkClientWrapper.java @@ -0,0 +1,122 @@ +package com.alibaba.dubbo.remoting.zookeeper.zkclient; + +import com.alibaba.dubbo.common.concurrent.ListenableFutureTask; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.Assert; + +import org.I0Itec.zkclient.IZkChildListener; +import org.I0Itec.zkclient.IZkStateListener; +import org.I0Itec.zkclient.ZkClient; +import org.apache.zookeeper.Watcher.Event.KeeperState; + +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +/** + * 连接超时后,能自动监听连接状态的zkclient包装类 + * 也为和curator在使用上总体保持一致 + * @author ken.lj + * @date 2017/10/29 + */ +public class ZkClientWrapper { + Logger logger = LoggerFactory.getLogger(ZkClientWrapper.class); + + private long timeout; + private ZkClient client; + private volatile KeeperState state; + private ListenableFutureTask listenableFutureTask; + private volatile boolean started = false; + + + public ZkClientWrapper(final String serverAddr, long timeout) { + this.timeout = timeout; + listenableFutureTask = ListenableFutureTask.create(new Callable() { + @Override + public ZkClient call() throws Exception { + return new ZkClient(serverAddr, Integer.MAX_VALUE); + } + }); + } + + public void start() { + if (!started) { + Thread connectThread = new Thread(listenableFutureTask); + connectThread.setName("DubboZkclientConnector"); + connectThread.setDaemon(true); + connectThread.start(); + try { + client = listenableFutureTask.get(timeout, TimeUnit.MILLISECONDS); + } catch (Throwable t) { + logger.error("Timeout! zookeeper server can not be connected in : " + timeout + "ms!", t); + } + started = true; + } else { + logger.warn("Zkclient has already been started!"); + } + } + + public void addListener(final IZkStateListener listener) { + listenableFutureTask.addListener(new Runnable() { + @Override + public void run() { + try { + client = listenableFutureTask.get(); + client.subscribeStateChanges(listener); + } catch (InterruptedException e) { + logger.warn(Thread.currentThread().getName() + " was interrupted unexpectedly, which may cause unpredictable exception!"); + } catch (ExecutionException e) { + logger.error("Got an exception when trying to create zkclient instance, can not connect to zookeeper server, please check!", e); + } + } + }); + } + + public boolean isConnected() { + return client != null && state == KeeperState.SyncConnected; + } + + public void createPersistent(String path) { + Assert.notNull(client, new IllegalStateException("Zookeeper is not connected yet!")); + client.createPersistent(path, true); + } + + public void createEphemeral(String path) { + Assert.notNull(client, new IllegalStateException("Zookeeper is not connected yet!")); + client.createEphemeral(path); + } + + public void delete(String path) { + Assert.notNull(client, new IllegalStateException("Zookeeper is not connected yet!")); + client.delete(path); + } + + public List getChildren(String path) { + Assert.notNull(client, new IllegalStateException("Zookeeper is not connected yet!")); + return client.getChildren(path); + } + + public boolean exists(String path) { + Assert.notNull(client, new IllegalStateException("Zookeeper is not connected yet!")); + return client.exists(path); + } + + public void close() { + Assert.notNull(client, new IllegalStateException("Zookeeper is not connected yet!")); + client.close(); + } + + public List subscribeChildChanges(String path, final IZkChildListener listener) { + Assert.notNull(client, new IllegalStateException("Zookeeper is not connected yet!")); + return client.subscribeChildChanges(path, listener); + } + + public void unsubscribeChildChanges(String path, IZkChildListener listener) { + Assert.notNull(client, new IllegalStateException("Zookeeper is not connected yet!")); + client.unsubscribeChildChanges(path, listener); + } + + +} diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/com/alibaba/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperClient.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/com/alibaba/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperClient.java index 8109b753f66..498f43158b9 100644 --- a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/com/alibaba/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperClient.java +++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/com/alibaba/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperClient.java @@ -7,7 +7,6 @@ import org.I0Itec.zkclient.IZkChildListener; import org.I0Itec.zkclient.IZkStateListener; -import org.I0Itec.zkclient.ZkClient; import org.I0Itec.zkclient.exception.ZkNoNodeException; import org.I0Itec.zkclient.exception.ZkNodeExistsException; import org.apache.zookeeper.Watcher.Event.KeeperState; @@ -16,14 +15,14 @@ public class ZkclientZookeeperClient extends AbstractZookeeperClient { - private final ZkClient client; + private final ZkClientWrapper client; private volatile KeeperState state = KeeperState.SyncConnected; public ZkclientZookeeperClient(URL url) { super(url); - client = new ZkClient(url.getBackupAddress()); - client.subscribeStateChanges(new IZkStateListener() { + client = new ZkClientWrapper(url.getBackupAddress(), 30000); + client.addListener(new IZkStateListener() { public void handleStateChanged(KeeperState state) throws Exception { ZkclientZookeeperClient.this.state = state; if (state == KeeperState.Disconnected) { @@ -37,11 +36,13 @@ public void handleNewSession() throws Exception { stateChanged(StateListener.RECONNECTED); } }); + client.start(); } + public void createPersistent(String path) { try { - client.createPersistent(path, true); + client.createPersistent(path); } catch (ZkNodeExistsException e) { } } @@ -68,6 +69,14 @@ public List getChildren(String path) { } } + public boolean checkExists(String path) { + try { + return client.exists(path); + } catch (Throwable t) { + } + return false; + } + public boolean isConnected() { return state == KeeperState.SyncConnected; } diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/com/alibaba/dubbo/remoting/zookeeper/curator/CuratorZookeeperClientTest.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/com/alibaba/dubbo/remoting/zookeeper/curator/CuratorZookeeperClientTest.java new file mode 100644 index 00000000000..159c57a24fc --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/com/alibaba/dubbo/remoting/zookeeper/curator/CuratorZookeeperClientTest.java @@ -0,0 +1,48 @@ +package com.alibaba.dubbo.remoting.zookeeper.curator; + +import com.alibaba.dubbo.common.URL; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +/** + * @author ken.lj + * @date 2017/10/16 + */ +@Ignore +public class CuratorZookeeperClientTest { + + @Test + public void testCheckExists() { + CuratorZookeeperClient curatorClient = new CuratorZookeeperClient(URL.valueOf("zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService")); + String path = "/dubbo/com.alibaba.dubbo.demo.DemoService/providers"; + curatorClient.create(path, false); + Assert.assertTrue(curatorClient.checkExists(path)); + Assert.assertFalse(curatorClient.checkExists(path + "/noneexits")); + } + + /** + * create checkExists 性能測試 + */ + @Test + public void testCreate() { + CuratorZookeeperClient curatorClient = new CuratorZookeeperClient(URL.valueOf("zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService")); + String path = "/dubbo/com.alibaba.dubbo.demo.DemoService/providers"; + curatorClient.create(path, false); + + // 重复create 100次,耗时 + long startTime = System.nanoTime(); + for (int i = 0; i < 100; i++) { + curatorClient.create(path, true); + } + System.out.println("create cost: " + (System.nanoTime() - startTime) / 1000 / 1000); + + // 判断100次,耗时 + startTime = System.nanoTime(); + for (int i = 0; i < 100; i++) { + curatorClient.checkExists(path); + } + System.out.println("judge cost: " + (System.nanoTime() - startTime) / 1000 / 1000); + } +} diff --git a/dubbo-remoting/pom.xml b/dubbo-remoting/pom.xml index 6cf1edfba23..8a691dcee65 100644 --- a/dubbo-remoting/pom.xml +++ b/dubbo-remoting/pom.xml @@ -20,7 +20,7 @@ com.alibaba dubbo-parent - 2.5.6 + 2.5.7 dubbo-remoting pom diff --git a/dubbo-rpc/dubbo-rpc-api/pom.xml b/dubbo-rpc/dubbo-rpc-api/pom.xml index e756c84a316..0d123a56c1b 100644 --- a/dubbo-rpc/dubbo-rpc-api/pom.xml +++ b/dubbo-rpc/dubbo-rpc-api/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-rpc - 2.5.6 + 2.5.7 dubbo-rpc-api jar diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/AccessLogFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/AccessLogFilter.java index 66fc366e7cd..932633e58f5 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/AccessLogFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/AccessLogFilter.java @@ -17,7 +17,7 @@ import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.extension.Activate; -import com.alibaba.dubbo.common.json.JSON; +import com.alibaba.fastjson.JSON; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.utils.ConcurrentHashSet; @@ -139,7 +139,7 @@ public Result invoke(Invoker invoker, Invocation inv) throws RpcException { sn.append(") "); Object[] args = inv.getArguments(); if (args != null && args.length > 0) { - sn.append(JSON.json(args)); + sn.append(JSON.toJSONString(args)); } String msg = sn.toString(); if (ConfigUtils.isDefault(accesslog)) { diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/listener/ListenerInvokerWrapper.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/listener/ListenerInvokerWrapper.java index d9b850920c4..e27c2b1a798 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/listener/ListenerInvokerWrapper.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/listener/ListenerInvokerWrapper.java @@ -76,7 +76,7 @@ public Result invoke(Invocation invocation) throws RpcException { @Override public String toString() { - return getInterface() + " -> " + getUrl() == null ? " " : getUrl().toString(); + return getInterface() + " -> " + (getUrl() == null ? " " : getUrl().toString()); } public void destroy() { @@ -97,4 +97,4 @@ public void destroy() { } } -} \ No newline at end of file +} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/protocol/AbstractProxyProtocol.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/protocol/AbstractProxyProtocol.java index 12e4a214539..a088768c83e 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/protocol/AbstractProxyProtocol.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/protocol/AbstractProxyProtocol.java @@ -16,7 +16,9 @@ package com.alibaba.dubbo.rpc.protocol; +import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; import com.alibaba.dubbo.rpc.Exporter; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; @@ -35,7 +37,6 @@ public abstract class AbstractProxyProtocol extends AbstractProtocol { private final List> rpcExceptions = new CopyOnWriteArrayList>(); - ; private ProxyFactory proxyFactory; @@ -122,6 +123,14 @@ protected RpcException getRpcException(Class type, URL url, Invocation invoca return re; } + protected String getAddr(URL url) { + String bindIp = url.getParameter(Constants.BIND_IP_KEY, url.getHost()); + if (url.getParameter(Constants.ANYHOST_KEY, false)) { + bindIp = Constants.ANYHOST_VALUE; + } + return NetUtils.getIpByHost(bindIp) + ":" + url.getParameter(Constants.BIND_PORT_KEY, url.getPort()); + } + protected int getErrorCode(Throwable e) { return RpcException.UNKNOWN_EXCEPTION; } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java index f41d7a4b9bb..9369fbeb2cf 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java @@ -81,8 +81,8 @@ public Result invoke(Invocation invocation) throws RpcException { @Override public String toString() { - return getInterface() + " -> " + getUrl() == null ? " " : getUrl().toString(); + return getInterface() + " -> " + (getUrl() == null ? " " : getUrl().toString()); } -} \ No newline at end of file +} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/StubProxyFactoryWrapper.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/StubProxyFactoryWrapper.java index d15fd5d3ee6..579b0f85f6f 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/StubProxyFactoryWrapper.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/StubProxyFactoryWrapper.java @@ -72,7 +72,7 @@ public T getProxy(Invoker invoker) throws RpcException { try { Class stubClass = ReflectUtils.forName(stub); if (!serviceType.isAssignableFrom(stubClass)) { - throw new IllegalStateException("The stub implemention class " + stubClass.getName() + " not implement interface " + serviceType.getName()); + throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + serviceType.getName()); } try { Constructor constructor = ReflectUtils.findConstructor(stubClass, serviceType); @@ -89,10 +89,10 @@ public T getProxy(Invoker invoker) throws RpcException { } } } catch (NoSuchMethodException e) { - throw new IllegalStateException("No such constructor \"public " + stubClass.getSimpleName() + "(" + serviceType.getName() + ")\" in stub implemention class " + stubClass.getName(), e); + throw new IllegalStateException("No such constructor \"public " + stubClass.getSimpleName() + "(" + serviceType.getName() + ")\" in stub implementation class " + stubClass.getName(), e); } } catch (Throwable t) { - LOGGER.error("Failed to create stub implemention class " + stub + " in consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", cause: " + t.getMessage(), t); + LOGGER.error("Failed to create stub implementation class " + stub + " in consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", cause: " + t.getMessage(), t); // ignore } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/MockInvoker.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/MockInvoker.java index e1be31fce22..67a97461a0e 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/MockInvoker.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/MockInvoker.java @@ -18,7 +18,6 @@ import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.common.extension.ExtensionLoader; -import com.alibaba.dubbo.common.json.JSON; import com.alibaba.dubbo.common.utils.ConfigUtils; import com.alibaba.dubbo.common.utils.PojoUtils; import com.alibaba.dubbo.common.utils.ReflectUtils; @@ -30,6 +29,7 @@ import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.RpcInvocation; import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.fastjson.JSON; import java.lang.reflect.Constructor; import java.lang.reflect.Type; @@ -74,9 +74,9 @@ public static Object parseMockValue(String mock, Type[] returnTypes) throws Exce } else if (StringUtils.isNumeric(mock)) { value = JSON.parse(mock); } else if (mock.startsWith("{")) { - value = JSON.parse(mock, Map.class); + value = JSON.parseObject(mock, Map.class); } else if (mock.startsWith("[")) { - value = JSON.parse(mock, List.class); + value = JSON.parseObject(mock, List.class); } else { value = mock; } diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/com/alibaba/dubbo/rpc/filter/ActiveLimitFilterTest.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/com/alibaba/dubbo/rpc/filter/ActiveLimitFilterTest.java index e2023427ecd..1261b628d3e 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/test/java/com/alibaba/dubbo/rpc/filter/ActiveLimitFilterTest.java +++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/com/alibaba/dubbo/rpc/filter/ActiveLimitFilterTest.java @@ -20,11 +20,14 @@ import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.support.BlockMyInvoker; import com.alibaba.dubbo.rpc.support.MockInvocation; import com.alibaba.dubbo.rpc.support.MyInvoker; import org.junit.Test; +import java.util.concurrent.CountDownLatch; + import static org.junit.Assert.assertNotSame; /** @@ -56,12 +59,18 @@ public void testInvokeLessActives() { @Test public void testInvokeGreaterActives() { URL url = URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1&actives=1&timeout=1"); - final Invoker invoker = new MyInvoker(url); + final Invoker invoker = new BlockMyInvoker(url, 100); final Invocation invocation = new MockInvocation(); + final CountDownLatch latch = new CountDownLatch(1); for (int i = 0; i < 100; i++) { Thread thread = new Thread(new Runnable() { public void run() { + try { + latch.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } for (int i = 0; i < 100; i++) { try { activeLimitFilter.invoke(invoker, invocation); @@ -73,6 +82,8 @@ public void run() { }); thread.start(); } + latch.countDown(); + try { Thread.sleep(1000); } catch (InterruptedException e) { diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/com/alibaba/dubbo/rpc/support/BlockMyInvoker.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/com/alibaba/dubbo/rpc/support/BlockMyInvoker.java new file mode 100644 index 00000000000..cfe19e10929 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/com/alibaba/dubbo/rpc/support/BlockMyInvoker.java @@ -0,0 +1,51 @@ +package com.alibaba.dubbo.rpc.support; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcResult; + +/** + * @author ken.lj + * @date 2017/10/24 + */ +public class BlockMyInvoker extends MyInvoker { + + private long blockTime = 100; + + public BlockMyInvoker(URL url, long blockTime) { + super(url); + this.blockTime = blockTime; + } + + public BlockMyInvoker(URL url, boolean hasException, long blockTime) { + super(url, hasException); + this.blockTime = blockTime; + } + + @Override + public Result invoke(Invocation invocation) throws RpcException { + RpcResult result = new RpcResult(); + if (hasException == false) { + try { + Thread.sleep(blockTime); + } catch (InterruptedException e) { + } + result.setValue("alibaba"); + return result; + } else { + result.setException(new RuntimeException("mocked exception")); + return result; + } + + } + + public long getBlockTime() { + return blockTime; + } + + public void setBlockTime(long blockTime) { + this.blockTime = blockTime; + } +} diff --git a/dubbo-rpc/dubbo-rpc-default/pom.xml b/dubbo-rpc/dubbo-rpc-default/pom.xml index 7b50f6ca3a0..3f08a2f2534 100644 --- a/dubbo-rpc/dubbo-rpc-default/pom.xml +++ b/dubbo-rpc/dubbo-rpc-default/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-rpc - 2.5.6 + 2.5.7 dubbo-rpc-default jar diff --git a/dubbo-rpc/dubbo-rpc-default/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java b/dubbo-rpc/dubbo-rpc-default/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java index c673c5167ad..00266064154 100644 --- a/dubbo-rpc/dubbo-rpc-default/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java +++ b/dubbo-rpc/dubbo-rpc-default/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java @@ -59,8 +59,6 @@ public class DubboProtocol extends AbstractProtocol { public static final String NAME = "dubbo"; - public static final String COMPATIBLE_CODEC_NAME = "dubbo1compatible"; - public static final int DEFAULT_PORT = 20880; private static final String IS_CALLBACK_SERVICE_INVOKE = "_isCallBackServiceInvoke"; private static DubboProtocol INSTANCE; @@ -271,7 +269,7 @@ private ExchangeServer createServer(URL url) { if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) throw new RpcException("Unsupported server type: " + str + ", url: " + url); - url = url.addParameter(Constants.CODEC_KEY, Version.isCompatibleVersion() ? COMPATIBLE_CODEC_NAME : DubboCodec.NAME); + url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME); ExchangeServer server; try { server = Exchangers.bind(url, requestHandler); @@ -349,7 +347,7 @@ private ExchangeClient initClient(URL url) { String version = url.getParameter(Constants.DUBBO_VERSION_KEY); boolean compatible = (version != null && version.startsWith("1.0.")); - url = url.addParameter(Constants.CODEC_KEY, Version.isCompatibleVersion() && compatible ? COMPATIBLE_CODEC_NAME : DubboCodec.NAME); + url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME); //默认开启heartbeat url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT)); diff --git a/dubbo-rpc/dubbo-rpc-default/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/filter/TraceFilter.java b/dubbo-rpc/dubbo-rpc-default/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/filter/TraceFilter.java index 30f1eb6ff5f..17484cad3b9 100644 --- a/dubbo-rpc/dubbo-rpc-default/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/filter/TraceFilter.java +++ b/dubbo-rpc/dubbo-rpc-default/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/filter/TraceFilter.java @@ -17,7 +17,7 @@ import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.extension.Activate; -import com.alibaba.dubbo.common.json.JSON; +import com.alibaba.fastjson.JSON; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.utils.ConcurrentHashSet; @@ -105,7 +105,7 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept channel.send("\r\n" + RpcContext.getContext().getRemoteAddress() + " -> " + invoker.getInterface().getName() + "." + invocation.getMethodName() - + "(" + JSON.json(invocation.getArguments()) + ")" + " -> " + JSON.json(result.getValue()) + + "(" + JSON.toJSONString(invocation.getArguments()) + ")" + " -> " + JSON.toJSONString(result.getValue()) + "\r\nelapsed: " + (end - start) + " ms." + "\r\n\r\n" + prompt); } diff --git a/dubbo-rpc/dubbo-rpc-default/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/InvokeTelnetHandler.java b/dubbo-rpc/dubbo-rpc-default/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/InvokeTelnetHandler.java index 50a6c763470..a8d0e237acb 100644 --- a/dubbo-rpc/dubbo-rpc-default/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/InvokeTelnetHandler.java +++ b/dubbo-rpc/dubbo-rpc-default/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/InvokeTelnetHandler.java @@ -16,7 +16,6 @@ package com.alibaba.dubbo.rpc.protocol.dubbo.telnet; import com.alibaba.dubbo.common.extension.Activate; -import com.alibaba.dubbo.common.json.JSON; import com.alibaba.dubbo.common.utils.PojoUtils; import com.alibaba.dubbo.common.utils.ReflectUtils; import com.alibaba.dubbo.common.utils.StringUtils; @@ -28,6 +27,7 @@ import com.alibaba.dubbo.rpc.RpcContext; import com.alibaba.dubbo.rpc.RpcInvocation; import com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol; +import com.alibaba.fastjson.JSON; import java.lang.reflect.Method; import java.util.Collection; @@ -110,7 +110,7 @@ public String telnet(Channel channel, String message) { } List list; try { - list = (List) JSON.parse("[" + args + "]", List.class); + list = JSON.parseArray("[" + args + "]", Object.class); } catch (Throwable t) { return "Invalid json argument, cause: " + t.getMessage(); } @@ -141,7 +141,7 @@ public String telnet(Channel channel, String message) { long start = System.currentTimeMillis(); Object result = invoker.invoke(new RpcInvocation(invokeMethod, array)).recreate(); long end = System.currentTimeMillis(); - buf.append(JSON.json(result)); + buf.append(JSON.toJSONString(result)); buf.append("\r\nelapsed: "); buf.append(end - start); buf.append(" ms."); diff --git a/dubbo-rpc/dubbo-rpc-default/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/PortTelnetHandlerTest.java b/dubbo-rpc/dubbo-rpc-default/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/PortTelnetHandlerTest.java index 4e7d5b006a8..ca292710a97 100644 --- a/dubbo-rpc/dubbo-rpc-default/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/PortTelnetHandlerTest.java +++ b/dubbo-rpc/dubbo-rpc-default/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/PortTelnetHandlerTest.java @@ -59,6 +59,11 @@ public void after() { ProtocolUtils.closeAll(); } + /** + * NAT网络场景,server channel.getRemoteAddress()可能拿到的是网关或NAT转换后的地址 + * 只判断端口 + * @throws Exception + */ @Test public void testListClient() throws Exception { ExchangeClient client1 = Exchangers.connect("dubbo://127.0.0.1:20887/demo"); @@ -70,8 +75,8 @@ public void testListClient() throws Exception { System.out.printf("Result: %s %n", result); System.out.printf("Client 1 Address %s %n", client1Addr); System.out.printf("Client 2 Address %s %n", client2Addr); - assertTrue(result.contains(client1Addr)); - assertTrue(result.contains(client2Addr)); + assertTrue(result.contains(String.valueOf(client1.getLocalAddress().getPort()))); + assertTrue(result.contains(String.valueOf(client2.getLocalAddress().getPort()))); } diff --git a/dubbo-rpc/dubbo-rpc-hessian/pom.xml b/dubbo-rpc/dubbo-rpc-hessian/pom.xml index 271b82c15b1..961e2f223dc 100644 --- a/dubbo-rpc/dubbo-rpc-hessian/pom.xml +++ b/dubbo-rpc/dubbo-rpc-hessian/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-rpc - 2.5.6 + 2.5.7 dubbo-rpc-hessian jar diff --git a/dubbo-rpc/dubbo-rpc-hessian/src/main/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocol.java b/dubbo-rpc/dubbo-rpc-hessian/src/main/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocol.java index bb0c5e6437d..33292631fbf 100644 --- a/dubbo-rpc/dubbo-rpc-hessian/src/main/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocol.java +++ b/dubbo-rpc/dubbo-rpc-hessian/src/main/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocol.java @@ -65,7 +65,7 @@ public int getDefaultPort() { } protected Runnable doExport(T impl, Class type, URL url) throws RpcException { - String addr = url.getIp() + ":" + url.getPort(); + String addr = getAddr(url); HttpServer server = serverMap.get(addr); if (server == null) { server = httpBinder.bind(url, new HessianHandler()); diff --git a/dubbo-rpc/dubbo-rpc-http/pom.xml b/dubbo-rpc/dubbo-rpc-http/pom.xml index 725cc7b0a55..d0816ac0fc7 100644 --- a/dubbo-rpc/dubbo-rpc-http/pom.xml +++ b/dubbo-rpc/dubbo-rpc-http/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-rpc - 2.5.6 + 2.5.7 dubbo-rpc-http jar diff --git a/dubbo-rpc/dubbo-rpc-http/src/main/java/com/alibaba/dubbo/rpc/protocol/http/HttpProtocol.java b/dubbo-rpc/dubbo-rpc-http/src/main/java/com/alibaba/dubbo/rpc/protocol/http/HttpProtocol.java index a7cfa2a373a..f06bf676427 100644 --- a/dubbo-rpc/dubbo-rpc-http/src/main/java/com/alibaba/dubbo/rpc/protocol/http/HttpProtocol.java +++ b/dubbo-rpc/dubbo-rpc-http/src/main/java/com/alibaba/dubbo/rpc/protocol/http/HttpProtocol.java @@ -67,7 +67,7 @@ public int getDefaultPort() { } protected Runnable doExport(final T impl, Class type, URL url) throws RpcException { - String addr = url.getIp() + ":" + url.getPort(); + String addr = getAddr(url); HttpServer server = serverMap.get(addr); if (server == null) { server = httpBinder.bind(url, new InternalHandler()); diff --git a/dubbo-rpc/dubbo-rpc-injvm/pom.xml b/dubbo-rpc/dubbo-rpc-injvm/pom.xml index 24d841ec214..1741572f886 100644 --- a/dubbo-rpc/dubbo-rpc-injvm/pom.xml +++ b/dubbo-rpc/dubbo-rpc-injvm/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-rpc - 2.5.6 + 2.5.7 dubbo-rpc-injvm jar diff --git a/dubbo-rpc/dubbo-rpc-memcached/pom.xml b/dubbo-rpc/dubbo-rpc-memcached/pom.xml index 07c1aa4980b..36ff3f2a5d2 100644 --- a/dubbo-rpc/dubbo-rpc-memcached/pom.xml +++ b/dubbo-rpc/dubbo-rpc-memcached/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-rpc - 2.5.6 + 2.5.7 dubbo-rpc-memcached jar diff --git a/dubbo-rpc/dubbo-rpc-redis/pom.xml b/dubbo-rpc/dubbo-rpc-redis/pom.xml index 69bb655768f..88a86a3347c 100644 --- a/dubbo-rpc/dubbo-rpc-redis/pom.xml +++ b/dubbo-rpc/dubbo-rpc-redis/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-rpc - 2.5.6 + 2.5.7 dubbo-rpc-redis jar diff --git a/dubbo-rpc/dubbo-rpc-rmi/pom.xml b/dubbo-rpc/dubbo-rpc-rmi/pom.xml index d0a9911e2ff..ce49751c0c7 100644 --- a/dubbo-rpc/dubbo-rpc-rmi/pom.xml +++ b/dubbo-rpc/dubbo-rpc-rmi/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-rpc - 2.5.6 + 2.5.7 dubbo-rpc-rmi jar diff --git a/dubbo-rpc/dubbo-rpc-rmi/src/main/java/com/alibaba/dubbo/rpc/protocol/rmi/RmiProtocol.java b/dubbo-rpc/dubbo-rpc-rmi/src/main/java/com/alibaba/dubbo/rpc/protocol/rmi/RmiProtocol.java index 171b8069867..f79d7e860e3 100644 --- a/dubbo-rpc/dubbo-rpc-rmi/src/main/java/com/alibaba/dubbo/rpc/protocol/rmi/RmiProtocol.java +++ b/dubbo-rpc/dubbo-rpc-rmi/src/main/java/com/alibaba/dubbo/rpc/protocol/rmi/RmiProtocol.java @@ -18,10 +18,12 @@ import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.protocol.AbstractProxyProtocol; - +import org.aopalliance.intercept.MethodInvocation; import org.springframework.remoting.RemoteAccessException; import org.springframework.remoting.rmi.RmiProxyFactoryBean; import org.springframework.remoting.rmi.RmiServiceExporter; +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.remoting.support.RemoteInvocationFactory; import java.io.IOException; import java.net.SocketTimeoutException; @@ -69,6 +71,12 @@ public void run() { @SuppressWarnings("unchecked") protected T doRefer(final Class serviceType, final URL url) throws RpcException { final RmiProxyFactoryBean rmiProxyFactoryBean = new RmiProxyFactoryBean(); + //RMI传输时使用自定义的远程执行对象,从而传递额外的参数 + rmiProxyFactoryBean.setRemoteInvocationFactory(new RemoteInvocationFactory() { + public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { + return new RmiRemoteInvocation(methodInvocation); + } + }); rmiProxyFactoryBean.setServiceUrl(url.toIdentityString()); rmiProxyFactoryBean.setServiceInterface(serviceType); rmiProxyFactoryBean.setCacheStub(true); diff --git a/dubbo-rpc/dubbo-rpc-rmi/src/main/java/com/alibaba/dubbo/rpc/protocol/rmi/RmiRemoteInvocation.java b/dubbo-rpc/dubbo-rpc-rmi/src/main/java/com/alibaba/dubbo/rpc/protocol/rmi/RmiRemoteInvocation.java new file mode 100644 index 00000000000..1f1097f36f3 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-rmi/src/main/java/com/alibaba/dubbo/rpc/protocol/rmi/RmiRemoteInvocation.java @@ -0,0 +1,56 @@ +/* + * Copyright 2013-2023 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.rpc.protocol.rmi; + +import com.alibaba.dubbo.rpc.RpcContext; +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.remoting.support.RemoteInvocation; + +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; + +/** + * @author 杨浩 + */ +public class RmiRemoteInvocation extends RemoteInvocation { + private static final long serialVersionUID = 1L; + private static final String dubboAttachmentsAttrName = "dubbo.attachments"; + + /** + * 构造将在消费端执行 + */ + public RmiRemoteInvocation(MethodInvocation methodInvocation) { + super(methodInvocation); + addAttribute(dubboAttachmentsAttrName, new HashMap(RpcContext.getContext().getAttachments())); + } + + /** + * 服务端执行时,重新放入上下文(虽然这时上下文在ContextFilter执行时将被Invocation的attachments覆盖,我们在Invocation构造时还原attachments, see InvokerInvocationHandler) + */ + @SuppressWarnings("unchecked") + @Override + public Object invoke(Object targetObject) throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + RpcContext context = RpcContext.getContext(); + context.setAttachments((Map) getAttribute(dubboAttachmentsAttrName)); + try { + return super.invoke(targetObject); + } finally { + context.setAttachments(null); + } + } +} \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-thrift/pom.xml b/dubbo-rpc/dubbo-rpc-thrift/pom.xml index 900b9bf2ea5..d2f41c55704 100644 --- a/dubbo-rpc/dubbo-rpc-thrift/pom.xml +++ b/dubbo-rpc/dubbo-rpc-thrift/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-rpc - 2.5.6 + 2.5.7 dubbo-rpc-thrift jar diff --git a/dubbo-rpc/dubbo-rpc-thrift/src/test/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftCodecTest.java b/dubbo-rpc/dubbo-rpc-thrift/src/test/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftCodecTest.java index 67c3162ec9a..a7bc3918c67 100644 --- a/dubbo-rpc/dubbo-rpc-thrift/src/test/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftCodecTest.java +++ b/dubbo-rpc/dubbo-rpc-thrift/src/test/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftCodecTest.java @@ -35,6 +35,7 @@ import org.apache.thrift.transport.TIOStreamTransport; import org.apache.thrift.transport.TTransport; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import java.io.ByteArrayInputStream; @@ -42,6 +43,7 @@ /** * @author gang.lvg */ +@Ignore public class ThriftCodecTest { private ThriftCodec codec = new ThriftCodec(); diff --git a/dubbo-rpc/dubbo-rpc-thrift/src/test/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftProtocolTest.java b/dubbo-rpc/dubbo-rpc-thrift/src/test/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftProtocolTest.java index 7916f32b64b..4fbac227d4a 100644 --- a/dubbo-rpc/dubbo-rpc-thrift/src/test/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftProtocolTest.java +++ b/dubbo-rpc/dubbo-rpc-thrift/src/test/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftProtocolTest.java @@ -19,7 +19,6 @@ import org.junit.After; import org.junit.Before; -import org.junit.Test; /** * @author kimi @@ -61,11 +60,11 @@ public void tearDown() throws Exception { } } - +/* @Test public void testRefer() throws Exception { // FIXME - /*invoker = protocol.refer( Demo.class, url ); + *//*invoker = protocol.refer( Demo.class, url ); Assert.assertNotNull( invoker ); @@ -81,8 +80,8 @@ public void testRefer() throws Exception { Result result = invoker.invoke( invocation ); - Assert.assertEquals( arg, result.getResult() );*/ + Assert.assertEquals( arg, result.getResult() );*//* - } + }*/ } diff --git a/dubbo-rpc/dubbo-rpc-webservice/pom.xml b/dubbo-rpc/dubbo-rpc-webservice/pom.xml index ea8c0e184ac..610e48228e7 100644 --- a/dubbo-rpc/dubbo-rpc-webservice/pom.xml +++ b/dubbo-rpc/dubbo-rpc-webservice/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-rpc - 2.5.6 + 2.5.7 dubbo-rpc-webservice jar diff --git a/dubbo-rpc/dubbo-rpc-webservice/src/main/java/com/alibaba/dubbo/rpc/protocol/webservice/WebServiceProtocol.java b/dubbo-rpc/dubbo-rpc-webservice/src/main/java/com/alibaba/dubbo/rpc/protocol/webservice/WebServiceProtocol.java index e9ad4692073..2900307c6b2 100644 --- a/dubbo-rpc/dubbo-rpc-webservice/src/main/java/com/alibaba/dubbo/rpc/protocol/webservice/WebServiceProtocol.java +++ b/dubbo-rpc/dubbo-rpc-webservice/src/main/java/com/alibaba/dubbo/rpc/protocol/webservice/WebServiceProtocol.java @@ -78,7 +78,7 @@ public int getDefaultPort() { } protected Runnable doExport(T impl, Class type, URL url) throws RpcException { - String addr = url.getIp() + ":" + url.getPort(); + String addr = getAddr(url); HttpServer httpServer = serverMap.get(addr); if (httpServer == null) { httpServer = httpBinder.bind(url, new WebServiceHandler()); diff --git a/dubbo-rpc/pom.xml b/dubbo-rpc/pom.xml index 7eb9deb1764..87bbc808bb9 100644 --- a/dubbo-rpc/pom.xml +++ b/dubbo-rpc/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-parent - 2.5.6 + 2.5.7 dubbo-rpc pom diff --git a/dubbo-simple/dubbo-monitor-simple/pom.xml b/dubbo-simple/dubbo-monitor-simple/pom.xml index ffd65553be4..d120bad6535 100644 --- a/dubbo-simple/dubbo-monitor-simple/pom.xml +++ b/dubbo-simple/dubbo-monitor-simple/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-simple - 2.5.6 + 2.5.7 dubbo-monitor-simple jar diff --git a/dubbo-simple/dubbo-registry-simple/pom.xml b/dubbo-simple/dubbo-registry-simple/pom.xml index dace74e6f74..a286ea3099d 100644 --- a/dubbo-simple/dubbo-registry-simple/pom.xml +++ b/dubbo-simple/dubbo-registry-simple/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-simple - 2.5.6 + 2.5.7 dubbo-registry-simple jar diff --git a/dubbo-simple/pom.xml b/dubbo-simple/pom.xml index 16f3dfbce93..16789ee0638 100644 --- a/dubbo-simple/pom.xml +++ b/dubbo-simple/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-parent - 2.5.6 + 2.5.7 dubbo-simple pom diff --git a/dubbo-test/dubbo-test-benchmark/pom.xml b/dubbo-test/dubbo-test-benchmark/pom.xml index da39bee6b4b..10fbd629bf4 100644 --- a/dubbo-test/dubbo-test-benchmark/pom.xml +++ b/dubbo-test/dubbo-test-benchmark/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-test - 2.5.6 + 2.5.7 dubbo-test-benchmark jar diff --git a/dubbo-test/dubbo-test-compatibility/pom.xml b/dubbo-test/dubbo-test-compatibility/pom.xml index 0a95b425d46..1532c2330d8 100644 --- a/dubbo-test/dubbo-test-compatibility/pom.xml +++ b/dubbo-test/dubbo-test-compatibility/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-test - 2.5.6 + 2.5.7 dubbo-test-compatibility jar diff --git a/dubbo-test/dubbo-test-examples/pom.xml b/dubbo-test/dubbo-test-examples/pom.xml index 27ea2da91d2..4ae6af43a62 100644 --- a/dubbo-test/dubbo-test-examples/pom.xml +++ b/dubbo-test/dubbo-test-examples/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-test - 2.5.6 + 2.5.7 dubbo-test-examples jar diff --git a/dubbo-test/dubbo-test-examples/src/main/java/com/alibaba/dubbo/examples/heartbeat/heartbeat-consumer.xml b/dubbo-test/dubbo-test-examples/src/main/java/com/alibaba/dubbo/examples/heartbeat/heartbeat-consumer.xml index b2a63fbc498..829d8687efa 100644 --- a/dubbo-test/dubbo-test-examples/src/main/java/com/alibaba/dubbo/examples/heartbeat/heartbeat-consumer.xml +++ b/dubbo-test/dubbo-test-examples/src/main/java/com/alibaba/dubbo/examples/heartbeat/heartbeat-consumer.xml @@ -23,7 +23,7 @@ - diff --git a/dubbo-test/dubbo-test-examples/src/main/java/com/alibaba/dubbo/examples/heartbeat/heartbeat-provider.xml b/dubbo-test/dubbo-test-examples/src/main/java/com/alibaba/dubbo/examples/heartbeat/heartbeat-provider.xml index cc3b2bafa95..cdefba28f0c 100644 --- a/dubbo-test/dubbo-test-examples/src/main/java/com/alibaba/dubbo/examples/heartbeat/heartbeat-provider.xml +++ b/dubbo-test/dubbo-test-examples/src/main/java/com/alibaba/dubbo/examples/heartbeat/heartbeat-provider.xml @@ -25,9 +25,9 @@ - + - diff --git a/dubbo-test/dubbo-test-integration/pom.xml b/dubbo-test/dubbo-test-integration/pom.xml index 8b37abea5dc..943aa0a1800 100644 --- a/dubbo-test/dubbo-test-integration/pom.xml +++ b/dubbo-test/dubbo-test-integration/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-test - 2.5.6 + 2.5.7 dubbo-test-integration jar diff --git a/dubbo-test/pom.xml b/dubbo-test/pom.xml index d70ba60cfd6..f2d64ad7096 100644 --- a/dubbo-test/pom.xml +++ b/dubbo-test/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-parent - 2.5.6 + 2.5.7 dubbo-test pom diff --git a/dubbo/pom.xml b/dubbo/pom.xml index 3141b68cca3..53a857f9aee 100644 --- a/dubbo/pom.xml +++ b/dubbo/pom.xml @@ -19,7 +19,7 @@ com.alibaba dubbo-parent - 2.5.6 + 2.5.7 dubbo jar diff --git a/hessian-lite/pom.xml b/hessian-lite/pom.xml index 888693be1f4..77de9249cd8 100644 --- a/hessian-lite/pom.xml +++ b/hessian-lite/pom.xml @@ -6,7 +6,7 @@ com.alibaba dubbo-parent - 2.5.6 + 2.5.7 hessian-lite jar diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/EnumSetHandler.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/EnumSetHandler.java new file mode 100644 index 00000000000..5ec64626b75 --- /dev/null +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/EnumSetHandler.java @@ -0,0 +1,25 @@ +package com.alibaba.com.caucho.hessian.io; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.EnumSet; + +/** + * @author bw on 24/10/2017. + */ +class EnumSetHandler implements Serializable, HessianHandle { + private Class type; + private Object[] objects; + + EnumSetHandler(Class type, Object[] objects) { + this.type = type; + this.objects = objects; + } + + @SuppressWarnings("unchecked") + private Object readResolve() { + EnumSet enumSet = EnumSet.noneOf(type); + enumSet.addAll(Arrays.asList(objects)); + return enumSet; + } +} diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/EnumSetSerializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/EnumSetSerializer.java new file mode 100644 index 00000000000..c8c432c7df1 --- /dev/null +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/EnumSetSerializer.java @@ -0,0 +1,34 @@ +package com.alibaba.com.caucho.hessian.io; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.EnumSet; + +/** + * @author bw on 24/10/2017. + */ +public class EnumSetSerializer extends AbstractSerializer { + private static EnumSetSerializer SERIALIZER = new EnumSetSerializer(); + + public static EnumSetSerializer getInstance() { + return SERIALIZER; + } + + @Override + public void writeObject(Object obj, AbstractHessianOutput out) throws IOException { + if (obj == null) { + out.writeNull(); + } else { + try { + Field field = EnumSet.class.getDeclaredField("elementType"); + field.setAccessible(true); + Class type = (Class) field.get(obj); + EnumSet enumSet = (EnumSet) obj; + Object[] objects = enumSet.toArray(); + out.writeObject(new EnumSetHandler(type, objects)); + } catch (Throwable t) { + throw new IOException(t); + } + } + } +} diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java index b12453ddd81..972143ae90e 100644 --- a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java @@ -73,6 +73,7 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; +import java.util.EnumSet; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; @@ -323,6 +324,8 @@ public Serializer getSerializer(Class cl) } else if (isZoneId(cl)) //must before "else if (JavaSerializer.getWriteReplace(cl) != null)" serializer = ZoneIdSerializer.getInstance(); + else if (isEnumSet(cl)) + serializer = EnumSetSerializer.getInstance(); else if (JavaSerializer.getWriteReplace(cl) != null) serializer = new JavaSerializer(cl, _loader); @@ -673,6 +676,10 @@ private static boolean isZoneId(Class cl) { return false; } + private static boolean isEnumSet(Class cl) { + return EnumSet.class.isAssignableFrom(cl); + } + /** * check if the environment is java 8 or beyond * diff --git a/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/Hessian2EnumSetTest.java b/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/Hessian2EnumSetTest.java new file mode 100644 index 00000000000..5edd563a379 --- /dev/null +++ b/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/Hessian2EnumSetTest.java @@ -0,0 +1,68 @@ +package com.alibaba.com.caucho.hessian.io; + +import junit.framework.TestCase; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.Arrays; +import java.util.EnumSet; + +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + +public class Hessian2EnumSetTest { + + @Test + public void singleton() throws Exception { + EnumSet h = EnumSet.of(Type.High); + + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + Hessian2Output out = new Hessian2Output(bout); + + out.writeObject(h); + out.flush(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + Hessian2Input input = new Hessian2Input(bin); + EnumSet set = (EnumSet) input.readObject(); + + assertTrue(Arrays.asList(set.toArray()).contains(Type.High)); + assertFalse(Arrays.asList(set.toArray()).contains(Type.Lower)); + } + + @Test + public void set() throws Exception { + EnumSet types = EnumSet.of(Type.High, Type.Lower); + + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + Hessian2Output out = new Hessian2Output(bout); + + out.writeObject(types); + out.flush(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + Hessian2Input input = new Hessian2Input(bin); + + EnumSet set = (EnumSet) input.readObject(); + assertTrue(set.contains(Type.High)); + assertFalse(set.contains(Type.Normal)); + } + + @Test + public void none() throws Exception { + EnumSet types = EnumSet.noneOf(Type.class); + + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + Hessian2Output out = new Hessian2Output(bout); + + out.writeObject(types); + out.flush(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + Hessian2Input input = new Hessian2Input(bin); + + EnumSet set = (EnumSet) input.readObject(); + TestCase.assertEquals(set, EnumSet.noneOf(Type.class)); + } +} diff --git a/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/Type.java b/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/Type.java new file mode 100644 index 00000000000..4a27537decb --- /dev/null +++ b/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/Type.java @@ -0,0 +1,8 @@ +package com.alibaba.com.caucho.hessian.io; + +/** + * @author bw on 24/10/2017. + */ +public enum Type { + High, Normal, Lower +} diff --git a/pom.xml b/pom.xml index 8f60dea379a..b002fa4a15b 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ 4.0.0 com.alibaba dubbo-parent - 2.5.6 + 2.5.7 pom ${project.artifactId} The parent project of dubbo @@ -110,7 +110,8 @@ 2.0-M5.1 3.0 2.2 - 3.0.8 + 3.1.6 + 1.7 1.7.25 1.2 @@ -300,6 +301,11 @@ citrus-webx-all ${webx_version} + + org.apache.velocity + velocity + ${velocity_version} + org.slf4j