提交 dd677eae 编写于 作者: W william.liangf

git-svn-id: http://code.alibabatech.com/svn/dubbo/tags/2.0.9@683 1a56cb94-b969-4eaa-88fa-be21384802f2
上级
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.
See the License for the specific language governing permissions and
limitations under the License.
\ No newline at end of file
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 1999-2101 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.
See the License for the specific language governing permissions and
limitations under the License.
<!--
- 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.
- See the License for the specific language governing permissions and
- limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-parent</artifactId>
<version>2.0.9</version>
</parent>
<artifactId>dubbo-cluster</artifactId>
<packaging>jar</packaging>
<name>Dubbo Cluster Module</name>
<description>The cluster module of dubbo project</description>
<properties>
<skip_maven_deploy>true</skip_maven_deploy>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-rpc</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.apache.bsf</groupId>
<artifactId>bsf-api</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>
</project>
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster;
import com.alibaba.dubbo.common.Adaptive;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.support.FailoverCluster;
/**
* Cluster. (SPI, Singleton, ThreadSafe)
*
* <a href="http://en.wikipedia.org/wiki/Computer_cluster">Cluster</a>
* <a href="http://en.wikipedia.org/wiki/Fault-tolerant_system">Fault-Tolerant</a>
*
* @author william.liangf
*/
@Extension(FailoverCluster.NAME)
public interface Cluster {
/**
* Merge the directory invokers to a virtual invoker.
*
* @param <T>
* @param directory
* @return
* @throws RpcException
*/
@Adaptive
<T> Invoker<T> merge(Directory<T> directory) throws RpcException;
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster;
import java.util.List;
import com.alibaba.dubbo.common.Node;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcException;
/**
* Directory. (SPI, Singleton, ThreadSafe)
*
* <a href="http://en.wikipedia.org/wiki/Directory_service">Directory Service</a>
*
* @see com.alibaba.dubbo.rpc.cluster.Cluster#merge(Directory)
* @author william.liangf
*/
public interface Directory<T> extends Node {
/**
* get service type.
*
* @return service type.
*/
Class<T> getInterface();
/**
* list invokers.
*
* @return invokers
*/
List<Invoker<T>> list(Invocation invocation) throws RpcException;
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster;
import java.util.List;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance;
/**
* LoadBalance. (SPI, Singleton, ThreadSafe)
*
* <a href="http://en.wikipedia.org/wiki/Load_balancing_(computing)">Load-Balancing</a>
*
* @see com.alibaba.dubbo.rpc.cluster.Cluster#merge(Directory)
* @author qian.lei
* @author william.liangf
*/
@Extension(RandomLoadBalance.NAME)
public interface LoadBalance {
/**
* select one invoker in list.
*
* @param invokers invokers.
* @param invocation invocation.
* @return selected invoker.
*/
<T> Invoker<T> select(List<Invoker<T>> invokers, Invocation invocation) throws RpcException;
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster;
import java.util.List;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.RpcException;
/**
* Router.
*
* @author chao.liuc
*/
public interface Router {
/**
* route.
*
* @param invokers
* @param invocation
* @return
* @throws RpcException
*/
<T> List<Invoker<T>> route(List<Invoker<T>> invokers, Invocation invocation) throws RpcException;
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster;
import com.alibaba.dubbo.common.Adaptive;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.common.URL;
/**
* RouterFactory. (SPI, Singleton, ThreadSafe)
*
* @author chao.liuc
*/
@Extension
public interface RouterFactory {
/**
* Create router.
*
* @param url
* @return
*/
@Adaptive("protocol")
Router getRouter(URL url);
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.directory;
import java.util.List;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Router;
import com.alibaba.dubbo.rpc.cluster.support.AbstractDirectory;
/**
* StaticDirectory
*
* @author william.liangf
*/
public class StaticDirectory<T> extends AbstractDirectory<T> {
private final List<Invoker<T>> invokers;
public StaticDirectory(List<Invoker<T>> invokers){
this(null, invokers, null);
}
public StaticDirectory(List<Invoker<T>> invokers, List<Router> routers){
this(null, invokers, routers);
}
public StaticDirectory(URL url, List<Invoker<T>> invokers) {
this(url, invokers, null);
}
public StaticDirectory(URL url, List<Invoker<T>> invokers, List<Router> routers) {
super(url == null && invokers != null && invokers.size() > 0 ? invokers.get(0).getUrl() : url, routers);
if (invokers == null || invokers.size() == 0)
throw new IllegalArgumentException("invokers == null");
this.invokers = invokers;
}
public Class<T> getInterface() {
return invokers.get(0).getInterface();
}
public boolean isAvailable() {
if (destroyed) return false;
for (Invoker<T> invoker : invokers) {
if (invoker.isAvailable()) {
return true;
}
}
return false;
}
public void destroy() {
if(destroyed) {
return;
}
super.destroy();
for (Invoker<T> invoker : invokers) {
invoker.destroy();
}
invokers.clear();
}
@Override
protected List<Invoker<T>> doList(Invocation invocation) throws RpcException {
return invokers;
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.loadbalance;
import java.util.List;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
/**
* AbstractLoadBalance
*
* @author william.liangf
*/
public abstract class AbstractLoadBalance implements LoadBalance {
public <T> Invoker<T> select(List<Invoker<T>> invokers, Invocation invocation) {
if (invokers == null || invokers.size() == 0)
return null;
if (invokers.size() == 1)
return invokers.get(0);
return doSelect(invokers, invocation);
}
protected abstract <T> Invoker<T> doSelect(List<Invoker<T>> invokers, Invocation invocation);
protected int getWeight(Invoker<?> invoker, Invocation invocation) {
return invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT);
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.loadbalance;
import java.util.List;
import java.util.Random;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcStatus;
import com.alibaba.dubbo.rpc.Invocation;
/**
* LeastActiveLoadBalance
*
* @author william.liangf
*/
@Extension(LeastActiveLoadBalance.NAME)
public class LeastActiveLoadBalance extends AbstractLoadBalance {
public static final String NAME = "leastactive";
private final Random random = new Random();
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, Invocation invocation) {
int length = invokers.size(); // 总个数
int leastActive = -1; // 最小的活跃数
int leastCount = 0; // 相同最小活跃数的个数
int[] leastIndexs = new int[length]; // 相同最小活跃数的下标
int totalWeight = 0; // 总权重
int firstWeight = 0; // 第一个权重,用于于计算是否相同
boolean sameWeight = true; // 是否所有权重相同
for (int i = 0; i < length; i++) {
Invoker<T> invoker = invokers.get(i);
int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive(); // 活跃数
int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT); // 权重
if (leastActive == -1 || active < leastActive) { // 发现更小的活跃数,重新开始
leastActive = active; // 记录最小活跃数
leastCount = 1; // 重新统计相同最小活跃数的个数
leastIndexs[0] = i; // 重新记录最小活跃数下标
totalWeight = weight; // 重新累计总权重
firstWeight = weight; // 记录第一个权重
sameWeight = true; // 还原权重相同标识
} else if (active == leastActive) { // 累计相同最小的活跃数
leastIndexs[leastCount ++] = i; // 累计相同最小活跃数下标
totalWeight += weight; // 累计总权重
// 判断所有权重是否一样
if (sameWeight && i > 0
&& weight != firstWeight) {
sameWeight = false;
}
}
}
// assert(leastCount > 0)
if (leastCount == 1) {
// 如果只有一个最小则直接返回
return invokers.get(leastIndexs[0]);
}
if (! sameWeight && totalWeight > 0) {
// 如果权重不相同且权重大于0则按总权重数随机
int offsetWeight = random.nextInt(totalWeight);
// 并确定随机值落在哪个片断上
for (int i = 0; i < leastCount; i++) {
int leastIndex = leastIndexs[i];
offsetWeight -= getWeight(invokers.get(leastIndex), invocation);
if (offsetWeight <= 0)
return invokers.get(leastIndex);
}
}
// 如果权重相同或权重为0则均等随机
return invokers.get(leastIndexs[random.nextInt(leastCount)]);
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.loadbalance;
import java.util.List;
import com.alibaba.dubbo.common.Adaptive;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.ExtensionLoader;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
/**
* LoadBalanceAdptive
*
* @author ding.lid
* @author william.liangf
*/
@Adaptive
public class LoadBalanceAdptive implements LoadBalance {
public <T> Invoker<T> select(List<Invoker<T>> invokers, Invocation invocation) throws RpcException {
if (invokers == null || invokers.size() == 0) {
return null;
}
URL url = invokers.get(0).getUrl();
String method = invocation.getMethodName();
String name;
if (method == null || method.length() == 0) {
name = url.getParameter(Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE);
} else {
name = url.getMethodParameter(method, Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE);
}
LoadBalance loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(name);
return loadbalance.select(invokers, invocation);
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.loadbalance;
import java.util.List;
import java.util.Random;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Invocation;
/**
* random load balance.
*
* @author qianlei
* @author william.liangf
*/
@Extension(RandomLoadBalance.NAME)
public class RandomLoadBalance extends AbstractLoadBalance {
public static final String NAME = "random";
private final Random random = new Random();
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, Invocation invocation) {
int length = invokers.size(); // 总个数
int totalWeight = 0; // 总权重
boolean sameWeight = true; // 权重是否都一样
for (int i = 0; i < length; i++) {
// 获取权重
int weight = getWeight(invokers.get(i), invocation);
// 累计总权重
totalWeight += weight;
// 判断所有权重是否一样
if (sameWeight && i > 0
&& weight != getWeight(invokers.get(i - 1), invocation)) {
sameWeight = false;
}
}
if (!sameWeight && totalWeight > 0) {
// 如果权重不相同且权重大于0则按总权重数随机
int offset = random.nextInt(totalWeight);
// 并确定随机值落在哪个片断上
for (int i = 0; i < length; i++) {
offset -= getWeight(invokers.get(i), invocation);
if (offset < 0) {
return invokers.get(i);
}
}
}
// 如果权重相同或权重为0则均等随机
return invokers.get(random.nextInt(length));
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.loadbalance;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.common.utils.AtomicPositiveInteger;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Invocation;
/**
* Round robin load balance.
*
* @author qian.lei
* @author william.liangf
*/
@Extension(RoundRobinLoadBalance.NAME)
public class RoundRobinLoadBalance extends AbstractLoadBalance {
public static final String NAME = "roundrobin";
private final ConcurrentMap<String, AtomicPositiveInteger> sequences = new ConcurrentHashMap<String, AtomicPositiveInteger>();
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, Invocation invocation) {
String key = invokers.get(0).getInterface().getName() + "." + invocation.getMethodName();// + System.identityHashCode(invokers);
AtomicPositiveInteger sequence = sequences.get(key);
if (sequence == null) {
sequences.putIfAbsent(key, new AtomicPositiveInteger());
sequence = sequences.get(key);
}
// 取模轮循
return invokers.get(sequence.getAndIncrement() % invokers.size());
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.router;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.utils.IOUtils;
import com.alibaba.dubbo.rpc.RpcConstants;
import com.alibaba.dubbo.rpc.cluster.Router;
import com.alibaba.dubbo.rpc.cluster.RouterFactory;
@Extension(FileRouterFactory.NAME)
public class FileRouterFactory implements RouterFactory {
public static final String NAME = "file";
private RouterFactory routerFactory;
public void setRouterFactory(RouterFactory routerFactory) {
this.routerFactory = routerFactory;
}
public Router getRouter(URL url) {
try {
// File URL 转换成 其它Route URL,然后Load
// file:///d:/path/to/route.js?router=script ==> script:///d:/path/to/route.js?type=js&rule=<file-content>
String protocol = url.getParameter(RpcConstants.ROUTER_KEY, ScriptRouterFactory.NAME); // 将原类型转为协议
String type = null; // 使用文件后缀做为类型
String path = url.getPath();
if (path != null) {
int i = path.lastIndexOf('.');
if (i > 0) {
type = path.substring(i + 1);
}
}
String rule = IOUtils.read(new FileReader(new File(url.getAbsolutePath())));
URL script = url.setProtocol(protocol).addParameter(RpcConstants.TYPE_KEY, type).addParameterAndEncoded(RpcConstants.RULE_KEY, rule);
return routerFactory.getRouter(script);
} catch (IOException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.router;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcConstants;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Router;
/**
* ScriptRouter
*
* @author william.liangf
*/
public class ScriptRouter implements Router {
private static final Logger logger = LoggerFactory.getLogger(ScriptRouter.class);
private static final Map<String, ScriptEngine> engines = new ConcurrentHashMap<String, ScriptEngine>();
private final ScriptEngine engine;
private final String rule;
public ScriptRouter(URL url) {
String type = url.getParameter(RpcConstants.TYPE_KEY);
String rule = url.getParameterAndDecoded(RpcConstants.RULE_KEY);
if (type == null || type.length() == 0){
type = RpcConstants.DEFAULT_SCRIPT_TYPE_KEY;
}
if (rule == null || rule.length() == 0){
throw new IllegalStateException(new IllegalStateException("route rule can not be empty. rule:" + rule));
}
ScriptEngine engine = engines.get(type);
if (engine == null){
engine = new ScriptEngineManager().getEngineByName(type);
if (engine == null) {
throw new IllegalStateException(new IllegalStateException("Unsupported route rule type: " + type + ", rule: " + rule));
}
engines.put(type, engine);
}
this.engine = engine;
this.rule = rule;
}
@SuppressWarnings("unchecked")
public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, Invocation invocation) throws RpcException {
try {
List<Invoker<T>> invokersCopy = new ArrayList<Invoker<T>>(invokers);
Compilable compilable = (Compilable) engine;
Bindings bindings = engine.createBindings();
bindings.put("invokers", invokersCopy);
bindings.put("invocation", invocation);
bindings.put("context", RpcContext.getContext());
CompiledScript function = compilable.compile(rule);
Object obj = function.eval(bindings);
if (obj instanceof Invoker[]) {
invokersCopy = Arrays.asList((Invoker<T>[]) obj);
} else if (obj instanceof Object[]) {
invokersCopy = new ArrayList<Invoker<T>>();
for (Object inv : (Object[]) obj) {
invokersCopy.add((Invoker<T>)inv);
}
} else {
invokersCopy = (List<Invoker<T>>) obj;
}
return invokersCopy;
} catch (ScriptException e) {
//fail then ignore rule .invokers.
logger.error("route error , rule has been ignored .rule :"+ rule + ",invocation:" + invocation + ",url :"+(RpcContext.getContext().getInvoker() == null ? "" : RpcContext.getContext().getInvoker().getUrl()), e);
return invokers;
}
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.router;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.cluster.Router;
import com.alibaba.dubbo.rpc.cluster.RouterFactory;
/**
* ScriptRouterFactory
*
* Script Router Factory用到的URL形如:
* <ol>
* <li> script://registyAddress?type=js&rule=xxxx
* <li> script:///path/to/routerfile.js?type=js&rule=xxxx
* <li> script://D:\path\to\routerfile.js?type=js&rule=xxxx
* <li> script://C:/path/to/routerfile.js?type=js&rule=xxxx
* </ol>
* URL的Host一段包含的是Script Router内容的来源,Registry、File etc
*
* @author william.liangf
*/
@Extension(ScriptRouterFactory.NAME)
public class ScriptRouterFactory implements RouterFactory {
public static final String NAME = "script";
public Router getRouter(URL url) {
return new ScriptRouter(url);
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.ExtensionLoader;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.Version;
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.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcConstants;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Directory;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
/**
* AbstractRpcRouter
*
* @author william.liangf
* @author chao.liuc
*/
public abstract class AbstractClusterInvoker<T> implements Invoker<T> {
private static final Logger logger = LoggerFactory
.getLogger(AbstractClusterInvoker.class);
protected final Directory<T> directory;
protected final boolean availablecheck;
private volatile boolean destroyed = false;
private volatile Invoker<T> stickyInvoker = null;
public AbstractClusterInvoker(Directory<T> directory) {
this(directory, directory.getUrl());
}
public AbstractClusterInvoker(Directory<T> directory, URL url) {
if (directory == null)
throw new IllegalArgumentException("service directory == null");
this.directory = directory ;
this.availablecheck = url.getParameter(RpcConstants.CLUSTER_AVAILABLE_CHECK_KEY, RpcConstants.DEFAULT_CLUSTER_AVAILABLE_CHECK) ;
}
public Class<T> getInterface() {
return directory.getInterface();
}
public URL getUrl() {
return directory.getUrl();
}
public boolean isAvailable() {
Invoker<T> invoker = stickyInvoker;
if (invoker != null) {
return invoker.isAvailable();
}
return directory.isAvailable();
}
public void destroy() {
directory.destroy();
destroyed = true;
}
/**
* 使用loadbalance选择invoker.</br>
* a)先lb选择,如果在selected列表中 或者 不可用且做检验时,进入下一步(重选),否则直接返回</br>
* b)重选验证规则:selected > available .保证重选出的结果尽量不在select中,并且是可用的
*
* @param availablecheck 如果设置true,在选择的时候先选invoker.available == true
* @param selected 已选过的invoker.注意:输入保证不重复
*
*/
protected Invoker<T> select(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected) throws RpcException {
if (invokers == null || invokers.size() == 0)
return null;
String methodName = invocation == null ? "" : invocation.getMethodName();
boolean sticky = invokers.get(0).getUrl().getMethodParameter(methodName,RpcConstants.CLUSTER_STICKY_KEY, RpcConstants.DEFAULT_CLUSTER_STICKY) ;
{
//ignore overloaded method
if ( stickyInvoker != null && !invokers.contains(stickyInvoker) ){
stickyInvoker = null;
}
//ignore cucurrent problem
if (sticky && stickyInvoker != null && (selected == null || !selected.contains(stickyInvoker))){
if (availablecheck && stickyInvoker.isAvailable()){
return stickyInvoker;
}
}
}
Invoker<T> invoker = doselect(loadbalance, invocation, invokers, selected);
if (sticky){
stickyInvoker = invoker;
}
return invoker;
}
private Invoker<T> doselect(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected) throws RpcException {
if (invokers == null || invokers.size() == 0)
return null;
if (invokers.size() == 1)
return invokers.get(0);
// 如果只有两个invoker,退化成轮循
if (invokers.size() == 2 && selected != null && selected.size() > 0) {
return selected.get(0) == invokers.get(0) ? invokers.get(1) : invokers.get(0);
}
Invoker<T> invoker = loadbalance.select(invokers, invocation);
//如果 selected中包含(优先判断) 或者 不可用&&availablecheck=true 则重试.
if( (selected != null && selected.contains(invoker))
||(!invoker.isAvailable() && getUrl()!=null && availablecheck)){
try{
Invoker<T> rinvoker = reselect(loadbalance, invocation, invokers, selected, availablecheck);
if(rinvoker != null){
invoker = rinvoker;
}else{
//看下第一次选的位置,如果不是最后,选+1位置.
int index = invokers.indexOf(invoker);
try{
//最后在避免碰撞
invoker = index <invokers.size()-1?invokers.get(index+1) :invoker;
}catch (Exception e) {
logger.warn(e.getMessage()+" may because invokers list dynamic change, ignore.",e);
}
}
}catch (Throwable t){
logger.error("clustor relselect fail reason is :"+t.getMessage() +" if can not slove ,you can set cluster.availablecheck=false in url",t);
}
}
return invoker;
}
/**
* 重选,先从非selected的列表中选择,没有在从selected列表中选择.
* @param loadbalance
* @param invocation
* @param invokers
* @param selected
* @return
* @throws RpcException
*/
private Invoker<T> reselect(LoadBalance loadbalance,Invocation invocation,
List<Invoker<T>> invokers, List<Invoker<T>> selected ,boolean availablecheck)
throws RpcException {
//预先分配一个,这个列表是一定会用到的.
List<Invoker<T>> reselectInvokers = new ArrayList<Invoker<T>>(invokers.size()>1?(invokers.size()-1):invokers.size());
//先从非select中选
if( availablecheck ){ //选isAvailable 的非select
for(Invoker<T> invoker : invokers){
if(invoker.isAvailable()){
if(selected ==null || !selected.contains(invoker)){
reselectInvokers.add(invoker);
}
}
}
if(reselectInvokers.size()>0){
return loadbalance.select(reselectInvokers, invocation);
}
}else{ //选全部非select
for(Invoker<T> invoker : invokers){
if(selected ==null || !selected.contains(invoker)){
reselectInvokers.add(invoker);
}
}
if(reselectInvokers.size()>0){
return loadbalance.select(reselectInvokers, invocation);
}
}
//最后从select中选可用的.
{
if(selected != null){
for(Invoker<T> invoker : selected){
if((invoker.isAvailable()) //优先选available
&& !reselectInvokers.contains(invoker)){
reselectInvokers.add(invoker);
}
}
}
if(reselectInvokers.size()>0){
return loadbalance.select(reselectInvokers, invocation);
}
}
return null;
}
public Result invoke(final Invocation invocation) throws RpcException {
if(destroyed){
throw new RpcException("Rpc invoker for " + getInterface() + " on consumer " + NetUtils.getLocalHost()
+ " use dubbo version " + Version.getVersion()
+ " is not destroyed! Can not invoke any more.");
}
LoadBalance loadbalance;
List<Invoker<T>> invokers = directory.list(invocation);
if (invokers != null && invokers.size() > 0) {
loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()
.getMethodParameter(invocation.getMethodName(),Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE));
} else {
loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(Constants.DEFAULT_LOADBALANCE);
}
return doInvoke(invocation, invokers, loadbalance);
}
@Override
public String toString() {
return getInterface() + " -> " + getUrl().toString();
}
protected abstract Result doInvoke(Invocation invocation, List<Invoker<T>> invokers,
LoadBalance loadbalance) throws RpcException;
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.ExtensionLoader;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Directory;
import com.alibaba.dubbo.rpc.cluster.Router;
import com.alibaba.dubbo.rpc.cluster.RouterFactory;
/**
* 增加router的Directory
* @author chao.liuc
*/
public abstract class AbstractDirectory<T> implements Directory<T> {
private final URL url ;
protected volatile boolean destroyed = false;
private List<Router> routers = new ArrayList<Router>();
public AbstractDirectory(URL url) {
this(url, null);
}
public AbstractDirectory(URL url, List<Router> routers) {
if (url == null)
throw new IllegalArgumentException("url == null");
if (routers == null){
routers = new ArrayList<Router>();
}
this.url = url;
String routerkey = url.getParameter(Constants.ROUTER_KEY);
if (routerkey != null && routerkey.length()>0 ){
RouterFactory routerFactory = ExtensionLoader.getExtensionLoader(RouterFactory.class).getExtension(routerkey);
routers.add(routerFactory.getRouter(url));
}
if (routers != null) {
setRouters(routers);
}
}
public List<Invoker<T>> list(Invocation invocation) throws RpcException {
if (destroyed){
throw new RpcException("Directory already destroyed .url: "+ getUrl());
}
List<Invoker<T>> invokers = doList(invocation);
for (Router router: routers){
invokers = router.route(invokers, invocation);
}
return invokers;
}
public URL getUrl() {
return url;
}
public List<Router> getRouters(){
return routers;
}
protected abstract List<Invoker<T>> doList(Invocation invocation) throws RpcException ;
protected void setRouters(List<Router> r){
routers = r;
}
public void destroy(){
destroyed = true;
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import java.util.List;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.cluster.Cluster;
import com.alibaba.dubbo.rpc.cluster.Directory;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
/**
* AvailableCluster
*
* @author william.liangf
*/
@Extension(AvailableCluster.NAME)
public class AvailableCluster implements Cluster {
public static final String NAME = "available";
public <T> Invoker<T> merge(Directory<T> directory) throws RpcException {
return new AbstractClusterInvoker<T>(directory) {
public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
for (Invoker<T> invoker : invokers) {
if (invoker.isAvailable()) {
return invoker.invoke(invocation);
}
}
throw new RpcException("No provider available in " + invokers);
}
};
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import java.util.List;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Directory;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
/**
* AvailableCluster
*
* @author william.liangf
*/
public class AvailableClusterInvoker<T> extends AbstractClusterInvoker<T> {
public AvailableClusterInvoker(Directory<T> directory) {
super(directory);
}
public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
for (Invoker<T> invoker : invokers) {
if (invoker.isAvailable()) {
return invoker.invoke(invocation);
}
}
throw new RpcException("No provider available in " + invokers);
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
/**
* ClusterUtils
*
* @author william.liangf
*/
public class ClusterUtils {
public static URL mergeUrl(URL remoteUrl, Map<String, String> localMap) {
Map<String, String> map = new HashMap<String, String>();
Map<String, String> remoteMap = remoteUrl.getParameters();
if (remoteMap != null && remoteMap.size() > 0) {
map.putAll(remoteMap);
//线程池配置不使用提供者的
map.remove(Constants.THREAD_NAME_KEY);
map.remove(Constants.THREADS_KEY);
map.remove(Constants.QUEUES_KEY);
map.remove(Constants.THREAD_ALIVE_KEY);
}
if (localMap != null && localMap.size() > 0) {
map.putAll(localMap);
}
if (remoteMap != null && remoteMap.size() > 0) {
// 版本号使用提供者的
String dubbo = remoteMap.get(Constants.DUBBO_VERSION_KEY);
if (dubbo != null && dubbo.length() > 0) {
map.put(Constants.DUBBO_VERSION_KEY, dubbo);
}
String version = remoteMap.get(Constants.VERSION_KEY);
if (version != null && version.length() > 0) {
map.put(Constants.VERSION_KEY, version);
}
String group = remoteMap.get(Constants.GROUP_KEY);
if (group != null && group.length() > 0) {
map.put(Constants.GROUP_KEY, group);
}
String methods = remoteMap.get(Constants.METHODS_KEY);
if (methods != null && methods.length() > 0) {
map.put(Constants.METHODS_KEY, methods);
}
// 合并filter和listener
String remoteFilter = remoteMap.get(Constants.REFERENCE_FILTER_KEY);
String localFilter = localMap.get(Constants.REFERENCE_FILTER_KEY);
if (remoteFilter != null && remoteFilter.length() > 0
&& localFilter != null && localFilter.length() > 0) {
localMap.put(Constants.REFERENCE_FILTER_KEY, remoteFilter + "," + localFilter);
}
String remoteListener = remoteMap.get(Constants.INVOKER_LISTENER_KEY);
String localListener = localMap.get(Constants.INVOKER_LISTENER_KEY);
if (remoteListener != null && remoteListener.length() > 0
&& localListener != null && localListener.length() > 0) {
localMap.put(Constants.INVOKER_LISTENER_KEY, remoteListener + "," + localListener);
}
}
return remoteUrl.addParameters(map);
}
private ClusterUtils() {}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Cluster;
import com.alibaba.dubbo.rpc.cluster.Directory;
/**
* 失败自动恢复,后台记录失败请求,定时重发,通常用于消息通知操作。
*
* <a href="http://en.wikipedia.org/wiki/Failback">Failback</a>
*
* @author william.liangf
*/
@Extension(FailbackCluster.NAME)
public class FailbackCluster implements Cluster {
public final static String NAME = "failback";
public <T> Invoker<T> merge(Directory<T> directory) throws RpcException {
return new FailbackClusterInvoker<T>(directory);
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import com.alibaba.dubbo.common.Version;
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.common.utils.NetUtils;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.RpcResult;
import com.alibaba.dubbo.rpc.cluster.Directory;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
/**
* 失败自动恢复,后台记录失败请求,定时重发,通常用于消息通知操作。
*
* @author tony.chenl
*/
public class FailbackClusterInvoker<T> extends AbstractClusterInvoker<T> {
public FailbackClusterInvoker(Directory<T> directory){
super(directory);
}
private static final Logger logger = LoggerFactory.getLogger(FailbackClusterInvoker.class);
private static final long RETRY_FAILED_PERIOD = 5 * 1000;
private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2,
new NamedThreadFactory(
"failback-cluster-timer",
true));
private volatile ScheduledFuture<?> retryFuture;
private final ConcurrentMap<Invocation, AbstractClusterInvoker<?>> failed = new ConcurrentHashMap<Invocation, AbstractClusterInvoker<?>>();
private void addFailed(Invocation invocation, AbstractClusterInvoker<?> router) {
if (retryFuture == null) {
synchronized (this) {
if (retryFuture == null) {
retryFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
public void run() {
// 收集统计信息
try {
retryFailed();
} catch (Throwable t) { // 防御性容错
logger.error("Unexpected error occur at collect statistic", t);
}
}
}, RETRY_FAILED_PERIOD, RETRY_FAILED_PERIOD, TimeUnit.MILLISECONDS);
}
}
}
failed.put(invocation, router);
}
void retryFailed() {
if (failed.size() == 0) {
return;
}
for (Map.Entry<Invocation, AbstractClusterInvoker<?>> entry : new HashMap<Invocation, AbstractClusterInvoker<?>>(
failed).entrySet()) {
Invocation invocation = entry.getKey();
Invoker<?> invoker = entry.getValue();
try {
invoker.invoke(invocation);
failed.remove(invocation);
} catch (Throwable e) {
logger.error("Failed retry to invoke " + invocation + ", waiting again.", e);
}
}
}
protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
try {
if (invokers == null || invokers.size() == 0)
throw new RpcException("No provider available for service " + getInterface().getName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", Please check whether the service do exist or version is right firstly, and check the provider has started.");
Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
return invoker.invoke(invocation);
} catch (Throwable e) {
logger.error("Failback to invoke " + invocation + ", wait for retry in background. Ignored exception: "
+ e.getMessage() + ", ", e);
addFailed(invocation, this);
return new RpcResult(); // ignore
}
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Cluster;
import com.alibaba.dubbo.rpc.cluster.Directory;
/**
* 快速失败,只发起一次调用,失败立即报错,通常用于非幂等性的写操作。</br>
* <a href="http://en.wikipedia.org/wiki/Fail-fast">Fail-fast</a>
*
* @author william.liangf
*/
@Extension(FailfastCluster.NAME)
public class FailfastCluster implements Cluster {
public final static String NAME = "failfast";
public <T> Invoker<T> merge(Directory<T> directory) throws RpcException {
return new FailfastClusterInvoker<T>(directory);
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import java.util.List;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.common.Version;
import com.alibaba.dubbo.common.utils.NetUtils;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Directory;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
/**
* 快速失败,只发起一次调用,失败立即报错,通常用于非幂等性的写操作。</br>
* <a href="http://en.wikipedia.org/wiki/Fail-fast">Fail-fast</a>
*
* @author william.liangf
* @author chao.liuc
*
*/
public class FailfastClusterInvoker<T> extends AbstractClusterInvoker<T>{
public FailfastClusterInvoker(Directory<T> directory) {
super(directory);
}
public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
if (invokers == null || invokers.size() == 0)
throw new RpcException("No provider available for service " + getInterface().getName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", Please check whether the service do exist or version is right firstly, and check the provider has started.");
Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
try {
return invoker.invoke(invocation);
} catch (Throwable e) {
throw new RpcException("Failfast invoke providers " + invoker.getUrl() + " " + loadbalance.getClass().getAnnotation(Extension.class).value() + " select from all providers " + invokers + " for service " + getInterface().getName() + " method " + invocation.getMethodName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e);
}
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Cluster;
import com.alibaba.dubbo.rpc.cluster.Directory;
/**
* 失败转移,当出现失败,重试其它服务器,通常用于读操作,但重试会带来更长延迟。 <a
* href="http://en.wikipedia.org/wiki/Failover">Failover</a>
*
* @author william.liangf
*/
@Extension(FailoverCluster.NAME)
public class FailoverCluster implements Cluster {
public final static String NAME = "failover";
public <T> Invoker<T> merge(Directory<T> directory) throws RpcException {
return new FailoverClusterInvoker<T>(directory);
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.Version;
import com.alibaba.dubbo.common.utils.NetUtils;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Directory;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
/**
* 失败转移,当出现失败,重试其它服务器,通常用于读操作,但重试会带来更长延迟。
*
* <a href="http://en.wikipedia.org/wiki/Failover">Failover</a>
* @author william.liangf
*
*/
public class FailoverClusterInvoker<T> extends AbstractClusterInvoker<T>{
public FailoverClusterInvoker(Directory<T> directory) {
super(directory);
}
public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
if (invokers == null || invokers.size() == 0)
throw new RpcException("No provider available for service " + getInterface().getName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", Please check whether the service do exist or version is right firstly, and check the provider has started.");
int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1;
if (len <= 0)
len = 1;
// retry loop.
RpcException le = null; // last exception.
List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(invokers.size()); // invoked invokers.
Set<URL> providers = new HashSet<URL>(len);
for (int i = 0; i < len; i++) {
//boolean pp = false; // is provider problem.
Invoker<T> invoker = select(loadbalance, invocation, invokers, invoked);
invoked.add(invoker);
providers.add(invoker.getUrl());
try {
return invoker.invoke(invocation);
} catch (RpcException e) {
if (e.isBiz()) throw e;
le = e;
//pp = true;
} catch (Throwable e) // biz exception.
{
throw new RpcException(e.getMessage(), e);
} finally {
//if (pp) // if provider problem, fail over.
// inv.setWeight(0);
}
}
List<URL> urls = new ArrayList<URL>(invokers.size());
for(Invoker<T> invoker : invokers){
if(invoker != null )
urls.add(invoker.getUrl());
}
throw new RpcException(le.getCode(),"Tried " + len + " times to invoke providers " + providers + " " + loadbalance.getClass().getAnnotation(Extension.class).value() + " select from all providers " + invokers + " for service " + getInterface().getName() + " method " + invocation.getMethodName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", but no luck to perform the invocation. Last error is: " + (le != null ? le.getMessage() : ""), le);
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Cluster;
import com.alibaba.dubbo.rpc.cluster.Directory;
/**
* 失败安全,出现异常时,直接忽略,通常用于写入审计日志等操作。 <a
* href="http://en.wikipedia.org/wiki/Fail-safe">Fail-safe</a>
*
* @author william.liangf
*/
@Extension(FailsafeCluster.NAME)
public class FailsafeCluster implements Cluster {
public final static String NAME = "failsafe";
public <T> Invoker<T> merge(Directory<T> directory) throws RpcException {
return new FailsafeClusterInvoker<T>(directory);
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import java.util.List;
import com.alibaba.dubbo.common.Version;
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.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.RpcResult;
import com.alibaba.dubbo.rpc.cluster.Directory;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
/**
* 失败安全,出现异常时,直接忽略,通常用于写入审计日志等操作。
*
* <a href="http://en.wikipedia.org/wiki/Fail-safe">Fail-safe</a>
*
* @author william.liangf
*/
public class FailsafeClusterInvoker<T> extends AbstractClusterInvoker<T>{
private static final Logger logger = LoggerFactory.getLogger(FailsafeClusterInvoker.class);
public FailsafeClusterInvoker(Directory<T> directory) {
super(directory);
}
public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
try {
if (invokers == null || invokers.size() == 0)
throw new RpcException("No provider available for service " + getInterface().getName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", Please check whether the service do exist or version is right firstly, and check the provider has started.");
Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
return invoker.invoke(invocation);
} catch (Throwable e) {
logger.error("Failsafe ignore exception: " + e.getMessage(), e);
return new RpcResult(); // ignore
}
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import com.alibaba.dubbo.common.Extension;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Cluster;
import com.alibaba.dubbo.rpc.cluster.Directory;
/**
* 并行调用,只要一个成功即返回,通常用于实时性要求较高的操作,但需要浪费更多服务资源。
*
* @author william.liangf
*/
@Extension(ForkingCluster.NAME)
public class ForkingCluster implements Cluster {
public final static String NAME = "forking";
public <T> Invoker<T> merge(Directory<T> directory) throws RpcException {
return new ForkingClusterInvoker<T>(directory);
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.Version;
import com.alibaba.dubbo.common.utils.NamedThreadFactory;
import com.alibaba.dubbo.common.utils.NetUtils;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.RpcResult;
import com.alibaba.dubbo.rpc.cluster.Directory;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
/**
* 并行调用,只要一个成功即返回,通常用于实时性要求较高的操作,但需要浪费更多服务资源。
*
* @author william.liangf
*/
public class ForkingClusterInvoker<T> extends AbstractClusterInvoker<T>{
public ForkingClusterInvoker(Directory<T> directory) {
super(directory);
}
private final ExecutorService executor = Executors.newCachedThreadPool(new NamedThreadFactory("forking-cluster-timer", true));
public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
if (invokers == null || invokers.size() == 0)
throw new RpcException("No provider available for service " + getInterface().getName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", Please check whether the service do exist or version is right firstly, and check the provider has started.");
final List<Invoker<T>> selected;
final int forks = getUrl().getParameter(Constants.FORKS_KEY, Constants.DEFAULT_FORKS);
final int timeout = getUrl().getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
if (forks <= 0 || forks >= invokers.size()) {
selected = invokers;
} else {
selected = new ArrayList<Invoker<T>>();
for (int i = 0; i < forks; i++) {
//在invoker列表(排除selected)后,如果没有选够,则存在重复循环问题.见select实现.
Invoker<T> invoker = select(loadbalance, invocation, invokers, selected);
if(!selected.contains(invoker)){//防止重复添加invoker
selected.add(invoker);
}
}
}
final AtomicInteger count = new AtomicInteger();
final BlockingQueue<Result> ref = new LinkedBlockingQueue<Result>();
for (final Invoker<T> invoker : selected) {
executor.execute(new Runnable() {
public void run() {
try {
Result result = invoker.invoke(invocation);
ref.offer(result);
} catch(Throwable e) {
int value = count.incrementAndGet();
if (value >= selected.size()) {
ref.offer(new RpcResult(e));
}
}
}
});
}
try {
return ref.poll(timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new RpcException("Failed to forking invoke provider " + selected + ", cause: " + e.getMessage(), e);
}
}
}
\ No newline at end of file
com.alibaba.dubbo.rpc.cluster.support.FailoverCluster
com.alibaba.dubbo.rpc.cluster.support.FailfastCluster
com.alibaba.dubbo.rpc.cluster.support.FailsafeCluster
com.alibaba.dubbo.rpc.cluster.support.FailbackCluster
com.alibaba.dubbo.rpc.cluster.support.ForkingCluster
com.alibaba.dubbo.rpc.cluster.support.AvailableCluster
\ No newline at end of file
com.alibaba.dubbo.rpc.cluster.loadbalance.LoadBalanceAdptive
com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance
com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance
\ No newline at end of file
com.alibaba.dubbo.rpc.cluster.router.FileRouterFactory
com.alibaba.dubbo.rpc.cluster.router.ScriptRouterFactory
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster;
import java.util.ArrayList;
import java.util.List;
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcConstants;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.RpcResult;
import com.alibaba.dubbo.rpc.cluster.Directory;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
import com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker;
@SuppressWarnings("unchecked")
public class StickyTest {
List<Invoker<StickyTest>> invokers = new ArrayList<Invoker<StickyTest>>();
Invoker<StickyTest> invoker1 = EasyMock.createMock(Invoker.class);
Invoker<StickyTest> invoker2 = EasyMock.createMock(Invoker.class);
Invocation invocation;
Directory<StickyTest> dic ;
Result result = new RpcResult();
StickyClusterInvoker<StickyTest> clusterinvoker = null;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@Before
public void setUp() throws Exception {
dic = EasyMock.createMock(Directory.class);
invocation = EasyMock.createMock(Invocation.class);
EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(dic.list(invocation)).andReturn(invokers).anyTimes();
EasyMock.expect(dic.getInterface()).andReturn(StickyTest.class).anyTimes();
EasyMock.replay(dic);
invokers.add(invoker1);
invokers.add(invoker2);
clusterinvoker = new StickyClusterInvoker<StickyTest>(dic);
}
URL url = URL.valueOf("test://test:11/test?"
+"&loadbalance=roundrobin"
// +"&"+RpcConstants.CLUSTER_AVAILABLE_CHECK_KEY+"=true"
+"&"+RpcConstants.CLUSTER_STICKY_KEY+"=true"
);
int runs = 1;
@Test
public void testStickyNoCheck() {
int count = testSticky(null,false);
System.out.println(count);
Assert.assertTrue(count>0 && count <=runs);
}
@Test
public void testStickyForceCheck() {
int count = testSticky(null,true);
Assert.assertTrue(count == 0 || count == runs);
}
@Test
public void testMethodStickyNoCheck() {
int count = testSticky("method1",false);
System.out.println(count);
Assert.assertTrue(count>0 && count <=runs);
}
@Test
public void testMethodStickyForceCheck() {
int count = testSticky("method1",true);
Assert.assertTrue(count == 0 || count == runs);
}
@Test
public void testMethodsSticky() {
for(int i = 0 ;i<100 ; i++){//多次调用看两个方法是否都选在同一个invoker
int count1 = testSticky("method1",true);
int count2 = testSticky("method2",true);
Assert.assertTrue(count1 == count2);
}
}
public int testSticky(String methodName, boolean check) {
if (methodName == null){
url = url.addParameter(RpcConstants.CLUSTER_STICKY_KEY, String.valueOf(check));
}else {
url = url.addParameter(methodName+"."+RpcConstants.CLUSTER_STICKY_KEY, String.valueOf(check));
}
EasyMock.reset(invoker1);
EasyMock.expect(invoker1.invoke(invocation)).andReturn(result).anyTimes();
EasyMock.expect(invoker1.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker1.getInterface()).andReturn(StickyTest.class).anyTimes();
EasyMock.replay(invoker1);
EasyMock.reset(invoker2);
EasyMock.expect(invoker2.invoke(invocation)).andReturn(result).anyTimes();
EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker2.getInterface()).andReturn(StickyTest.class).anyTimes();
EasyMock.replay(invoker2);
EasyMock.reset(invocation);
EasyMock.expect(invocation.getMethodName()).andReturn(methodName).anyTimes();
EasyMock.replay(invocation);
int count = 0;
for (int i = 0; i < runs; i++) {
Assert.assertEquals(null, clusterinvoker.invoke(invocation));
if(invoker1 == clusterinvoker.getSelectedInvoker()){
count ++;
}
}
return count;
}
static class StickyClusterInvoker<T> extends AbstractClusterInvoker<T>{
private Invoker<T> selectedInvoker ;
public StickyClusterInvoker(Directory<T> directory) {
super(directory);
}
public StickyClusterInvoker(Directory<T> directory,URL url) {
super(directory, url);
}
@Override
protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers,
LoadBalance loadbalance) throws RpcException {
Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
selectedInvoker = invoker ;
return null;
}
public Invoker<T> getSelectedInvoker() {
return selectedInvoker;
}
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.filter;
/**
* <code>TestService</code>
*/
public interface DemoService
{
String sayHello(String name);
int plus(int a,int b);
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.filter;
/**
* <code>TestService</code>
*/
public class DemoServiceLocal implements DemoService {
public DemoServiceLocal(DemoService demoService){
}
public String sayHello(String name) {
return name;
}
public int plus(int a, int b) {
return a + b;
}
public void ondisconnect(){
}
public void onconnect(){
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.filter;
/**
* MockService.java
* @author tony.chenl
*/
public class DemoServiceMock implements DemoService{
public String sayHello(String name) {
return name;
}
public int plus(int a, int b) {
return a+b;
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.filter;
/**
* <code>TestService</code>
*/
public class DemoServiceStub implements DemoService {
public DemoServiceStub(DemoService demoService){
}
public String sayHello(String name) {
return name;
}
public int plus(int a, int b) {
return a + b;
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.filter;
/**
* MockService.java
* @author tony.chenl
*/
public class MockService implements DemoService{
public String sayHello(String name) {
return name;
}
public int plus(int a, int b) {
return a+b;
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.loadbalance;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import junit.framework.Assert;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.alibaba.dubbo.common.ExtensionLoader;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
/**
* RoundRobinLoadBalanceTest
* @author liuchao
*
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public class LoadBalanceTest {
Invocation invocation ;
List<Invoker<LoadBalanceTest>> invokers = new ArrayList<Invoker<LoadBalanceTest>>();
Invoker<LoadBalanceTest> invoker1 ;
Invoker<LoadBalanceTest> invoker2 ;
Invoker<LoadBalanceTest> invoker3 ;
Invoker<LoadBalanceTest> invoker4 ;
Invoker<LoadBalanceTest> invoker5 ;
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
invocation = EasyMock.createMock(Invocation.class);
EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes();
invoker1 = EasyMock.createMock(Invoker.class);
invoker2 = EasyMock.createMock(Invoker.class);
invoker3 = EasyMock.createMock(Invoker.class);
invoker4 = EasyMock.createMock(Invoker.class);
invoker5 = EasyMock.createMock(Invoker.class);
URL url = URL.valueOf("test://127.0.0.1/DemoService");
EasyMock.expect(invoker1.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker1.getInterface()).andReturn(LoadBalanceTest.class).anyTimes();
EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker2.getInterface()).andReturn(LoadBalanceTest.class).anyTimes();
EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker3.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker3.getInterface()).andReturn(LoadBalanceTest.class).anyTimes();
EasyMock.expect(invoker3.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker4.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker4.getInterface()).andReturn(LoadBalanceTest.class).anyTimes();
EasyMock.expect(invoker4.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker5.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker5.getInterface()).andReturn(LoadBalanceTest.class).anyTimes();
EasyMock.expect(invoker5.getUrl()).andReturn(url).anyTimes();
EasyMock.replay(invocation,invoker1,invoker2,invoker3,invoker4,invoker5);
invokers.add(invoker1);
invokers.add(invoker2);
invokers.add(invoker3);
invokers.add(invoker4);
invokers.add(invoker5);
}
@Test
public void testRoundRobinLoadBalance_select() {
int runs = 10000;
Map<Invoker,AtomicLong> counter = getInvokeCounter(runs,RoundRobinLoadBalance.NAME);
for (Invoker minvoker :counter.keySet() ){
Long count = counter.get(minvoker).get();
Assert.assertTrue("abs diff shoud < 1", Math.abs(count-runs/(0f+invokers.size())) <1f);
}
}
@Test
public void testRandomLoadBalance_select() {
int runs = 1000;
Map<Invoker,AtomicLong> counter = getInvokeCounter(runs,RandomLoadBalance.NAME);
for (Invoker minvoker :counter.keySet() ){
Long count = counter.get(minvoker).get();
// System.out.println(count);
Assert.assertTrue("abs diff shoud < avg", Math.abs(count-runs/(0f+invokers.size())) <runs/(0f+invokers.size()));
}
}
@Test
public void testLeastActiveLoadBalance_select() {
int runs = 10000;
Map<Invoker,AtomicLong> counter = getInvokeCounter(runs,LeastActiveLoadBalance.NAME);
for (Invoker minvoker :counter.keySet() ){
Long count = counter.get(minvoker).get();
// System.out.println(count);
Assert.assertTrue("abs diff shoud < avg", Math.abs(count-runs/(0f+invokers.size())) <runs/(0f+invokers.size()));
}
}
public Map<Invoker,AtomicLong> getInvokeCounter(int runs,String loadbalanceName) {
Map<Invoker,AtomicLong> counter = new ConcurrentHashMap<Invoker,AtomicLong>();
LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(loadbalanceName);
for(Invoker invoker :invokers){
counter.put(invoker, new AtomicLong(0));
}
for(int i=0;i<runs;i++){
Invoker sinvoker = lb.select(invokers, invocation);
counter.get(sinvoker).incrementAndGet();
}
return counter;
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.router;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcException;
public class MockInvoker<T> implements Invoker<T> {
private boolean available = false;
private URL url ;
public MockInvoker() {
}
public MockInvoker(URL url) {
super();
this.url = url;
}
public MockInvoker(boolean available) {
this.available = available;
}
public Class<T> getInterface() {
return null;
}
public URL getUrl() {
return url;
}
public boolean isAvailable() {
return available;
}
public Result invoke(Invocation invocation) throws RpcException {
return null;
}
public void destroy() {
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.router;
import java.util.ArrayList;
import java.util.List;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcConstants;
import com.alibaba.dubbo.rpc.RpcInvocation;
import com.alibaba.dubbo.rpc.cluster.Router;
public class ScriptRouterEngineTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@Before
public void setUp() throws Exception {
}
private URL SCRIPT_URL = URL.valueOf("script://javascript?type=javascript");
private URL getRouteUrl(String rule) {
return SCRIPT_URL.addParameterAndEncoded(RpcConstants.RULE_KEY, rule);
}
@Test
public void testRoute_ReturnAll(){
Router router = new ScriptRouterFactory().getRouter(getRouteUrl("function route(op1,op2){return op1} route(invokers)"));
List<Invoker<String>> invokers = new ArrayList<Invoker<String>>();
invokers.add(new MockInvoker<String>());
invokers.add(new MockInvoker<String>());
invokers.add(new MockInvoker<String>());
List<Invoker<String>> fileredInvokers = router.route(invokers, new RpcInvocation());
Assert.assertEquals(invokers, fileredInvokers);
}
@Test
public void testRoute_PickInvokers(){
String rule = "var result = new java.util.ArrayList(invokers.size());" +
"for (i=0;i<invokers.size(); i++){ " +
"if (invokers.get(i).isAvailable()) {" +
"result.add(invokers.get(i)) ;" +
"}" +
"} ; " +
"return result;";
String script = "function route(invokers,invocation,context){" + rule + "} route(invokers,invocation,context)";
Router router = new ScriptRouterFactory().getRouter(getRouteUrl(script));
List<Invoker<String>> invokers = new ArrayList<Invoker<String>>();
Invoker<String> invoker1 = new MockInvoker<String>(false) ;
Invoker<String> invoker2 = new MockInvoker<String>(true) ;
Invoker<String> invoker3 = new MockInvoker<String>(true) ;
invokers.add(invoker1);
invokers.add(invoker2);
invokers.add(invoker3);
List<Invoker<String>> fileredInvokers = router.route(invokers, new RpcInvocation());
Assert.assertEquals(2, fileredInvokers.size());
Assert.assertEquals(invoker2, fileredInvokers.get(0));
Assert.assertEquals(invoker3, fileredInvokers.get(1));
}
//TODO 异常场景测试。
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.router.file;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.script.ScriptEngineManager;
import junit.framework.Assert;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.alibaba.dubbo.common.ExtensionLoader;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.RpcResult;
import com.alibaba.dubbo.rpc.cluster.Directory;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
import com.alibaba.dubbo.rpc.cluster.RouterFactory;
import com.alibaba.dubbo.rpc.cluster.directory.StaticDirectory;
import com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker;
/**
* @author chao.liuc
*/
@SuppressWarnings("unchecked")
public class FileRouterEngineTest {
List<Invoker<FileRouterEngineTest>> invokers = new ArrayList<Invoker<FileRouterEngineTest>>();
Invoker<FileRouterEngineTest> invoker1 = EasyMock.createMock(Invoker.class);
Invoker<FileRouterEngineTest> invoker2 = EasyMock.createMock(Invoker.class);
Invocation invocation;
Directory<FileRouterEngineTest> dic;
Result result = new RpcResult();
private RouterFactory routerFactory = ExtensionLoader.getExtensionLoader(RouterFactory.class).getAdaptiveExtension();
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
private static boolean isScriptUnsupported = new ScriptEngineManager().getEngineByName("javascript") == null;
@Before
public void setUp() throws Exception {
invokers.add(invoker1);
invokers.add(invoker2);
}
@Test
public void testRouteNotAvailable() {
if (isScriptUnsupported) return;
URL url = initUrl("notAvailablerule.javascript");
initInvocation("method1");
initDic(url);
initInvokers(url, true, false);
MockClusterInvoker<FileRouterEngineTest> sinvoker = new MockClusterInvoker<FileRouterEngineTest>(
dic, url);
for (int i = 0; i < 100; i++) {
sinvoker.invoke(invocation);
Invoker<FileRouterEngineTest> invoker = sinvoker.getSelectedInvoker();
Assert.assertEquals(invoker2, invoker);
}
}
@Test
public void testRouteAvailable() {
if (isScriptUnsupported) return;
URL url = initUrl("availablerule.javascript");
initInvocation("method1");
initDic(url);
initInvokers(url);
MockClusterInvoker<FileRouterEngineTest> sinvoker = new MockClusterInvoker<FileRouterEngineTest>(
dic, url);
for (int i = 0; i < 100; i++) {
sinvoker.invoke(invocation);
Invoker<FileRouterEngineTest> invoker = sinvoker.getSelectedInvoker();
Assert.assertEquals(invoker1, invoker);
}
}
@Test
public void testRouteByMethodName() {
if (isScriptUnsupported) return;
URL url = initUrl("methodrule.javascript");
{
initInvocation("method1");
initDic(url);
initInvokers(url, true, true);
MockClusterInvoker<FileRouterEngineTest> sinvoker = new MockClusterInvoker<FileRouterEngineTest>(
dic, url);
for (int i = 0; i < 100; i++) {
sinvoker.invoke(invocation);
Invoker<FileRouterEngineTest> invoker = sinvoker.getSelectedInvoker();
Assert.assertEquals(invoker1, invoker);
}
}
{
initInvocation("method2");
initDic(url);
initInvokers(url, true, true);
MockClusterInvoker<FileRouterEngineTest> sinvoker = new MockClusterInvoker<FileRouterEngineTest>(
dic, url);
for (int i = 0; i < 100; i++) {
sinvoker.invoke(invocation);
Invoker<FileRouterEngineTest> invoker = sinvoker.getSelectedInvoker();
Assert.assertEquals(invoker2, invoker);
}
}
}
private URL initUrl(String filename) {
filename = getClass().getClassLoader().getResource(getClass().getPackage().getName().replace('.', '/') + "/" + filename).toString();
URL url = URL.valueOf(filename);
return url;
}
private void initInvocation(String methodName) {
invocation = EasyMock.createMock(Invocation.class);
EasyMock.expect(invocation.getMethodName()).andReturn(methodName).anyTimes();
EasyMock.replay(invocation);
}
private void initInvokers(URL url) {
initInvokers(url, true, false);
}
private void initInvokers(URL url, boolean invoker1Status, boolean invoker2Status) {
EasyMock.reset(invoker1);
EasyMock.expect(invoker1.invoke(invocation)).andReturn(result).anyTimes();
EasyMock.expect(invoker1.isAvailable()).andReturn(invoker1Status).anyTimes();
EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker1.getInterface()).andReturn(FileRouterEngineTest.class).anyTimes();
EasyMock.replay(invoker1);
EasyMock.reset(invoker2);
EasyMock.expect(invoker2.invoke(invocation)).andReturn(result).anyTimes();
EasyMock.expect(invoker2.isAvailable()).andReturn(invoker2Status).anyTimes();
EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker2.getInterface()).andReturn(FileRouterEngineTest.class).anyTimes();
EasyMock.replay(invoker2);
}
private void initDic(URL url) {
dic = new StaticDirectory<FileRouterEngineTest>(url, invokers, Arrays.asList(routerFactory.getRouter(url)));
}
static class MockClusterInvoker<T> extends AbstractClusterInvoker<T> {
private Invoker<T> selectedInvoker;
public MockClusterInvoker(Directory<T> directory) {
super(directory);
}
public MockClusterInvoker(Directory<T> directory, URL url) {
super(directory, url);
}
@Override
protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers,
LoadBalance loadbalance) throws RpcException {
Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
selectedInvoker = invoker;
return null;
}
public Invoker<T> getSelectedInvoker() {
return selectedInvoker;
}
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import junit.framework.Assert;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.alibaba.dubbo.common.ExtensionLoader;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcConstants;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Directory;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
import com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance;
import com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance;
import com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance;
/**
* AbstractClusterInvokerTest
* @author chao.liuc
*
*/
@SuppressWarnings("rawtypes")
public class AbstractClusterInvokerTest {
List<Invoker<AbstractClusterInvokerTest>> invokers = new ArrayList<Invoker<AbstractClusterInvokerTest>>();
List<Invoker<AbstractClusterInvokerTest>> selectedInvokers = new ArrayList<Invoker<AbstractClusterInvokerTest>>();
AbstractClusterInvoker<AbstractClusterInvokerTest> cluster;
AbstractClusterInvoker<AbstractClusterInvokerTest> cluster_nocheck;
Directory<AbstractClusterInvokerTest> dic ;
Invocation invocation;
URL url = URL.valueOf("registry://localhost:9090");
Invoker<AbstractClusterInvokerTest> invoker1 ;
Invoker<AbstractClusterInvokerTest> invoker2 ;
Invoker<AbstractClusterInvokerTest> invoker3 ;
Invoker<AbstractClusterInvokerTest> invoker4 ;
Invoker<AbstractClusterInvokerTest> invoker5 ;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@SuppressWarnings({ "unchecked" })
@Before
public void setUp() throws Exception {
dic = EasyMock.createMock(Directory.class);
invoker1 = EasyMock.createMock(Invoker.class);
invoker2 = EasyMock.createMock(Invoker.class);
invoker3 = EasyMock.createMock(Invoker.class);
invoker4 = EasyMock.createMock(Invoker.class);
invoker5 = EasyMock.createMock(Invoker.class);
URL turl = URL.valueOf("test://test:11/test");
EasyMock.expect(invoker1.isAvailable()).andReturn(false).anyTimes();
EasyMock.expect(invoker1.getInterface()).andReturn(AbstractClusterInvokerTest.class).anyTimes();
EasyMock.expect(invoker1.getUrl()).andReturn(turl.addParameter("name", "invoker1")).anyTimes();
EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker2.getInterface()).andReturn(AbstractClusterInvokerTest.class).anyTimes();
EasyMock.expect(invoker2.getUrl()).andReturn(turl.addParameter("name", "invoker2")).anyTimes();
EasyMock.expect(invoker3.isAvailable()).andReturn(false).anyTimes();
EasyMock.expect(invoker3.getInterface()).andReturn(AbstractClusterInvokerTest.class).anyTimes();
EasyMock.expect(invoker3.getUrl()).andReturn(turl.addParameter("name", "invoker3")).anyTimes();
EasyMock.expect(invoker4.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker4.getInterface()).andReturn(AbstractClusterInvokerTest.class).anyTimes();
EasyMock.expect(invoker4.getUrl()).andReturn(turl.addParameter("name", "invoker4")).anyTimes();
EasyMock.expect(invoker5.isAvailable()).andReturn(false).anyTimes();
EasyMock.expect(invoker5.getInterface()).andReturn(AbstractClusterInvokerTest.class).anyTimes();
EasyMock.expect(invoker5.getUrl()).andReturn(turl.addParameter("name", "invoker5")).anyTimes();
EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes();
invocation = EasyMock.createMock(Invocation.class);
EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes();
EasyMock.replay(dic,invoker1,invoker2,invoker3,invoker4,invoker5,invocation);
cluster = new AbstractClusterInvoker(dic) {
@Override
protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)
throws RpcException {
return null;
}
};
cluster_nocheck = new AbstractClusterInvoker(dic,url.addParameterIfAbsent(RpcConstants.CLUSTER_AVAILABLE_CHECK_KEY, Boolean.FALSE.toString())) {
@Override
protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)
throws RpcException {
return null;
}
};
}
@Test
public void testSelect_Invokersize0() throws Exception {
{
Invoker invoker = cluster.select(null,null,null,null);
Assert.assertEquals(null, invoker);
}
{
invokers.clear();
selectedInvokers.clear();
Invoker invoker = cluster.select(null,null,invokers,null);
Assert.assertEquals(null, invoker);
}
}
@Test
public void testSelect_Invokersize1() throws Exception {
invokers.clear();
invokers.add(invoker1);
Invoker invoker = cluster.select(null,null,invokers,null);
Assert.assertEquals(invoker1, invoker);
}
@Test
public void testSelect_Invokersize2AndselectNotNull() throws Exception {
invokers.clear();
invokers.add(invoker1);
invokers.add(invoker2);
{
selectedInvokers.clear();
selectedInvokers.add(invoker1);
Invoker invoker = cluster.select(null,null,invokers,selectedInvokers);
Assert.assertEquals(invoker2, invoker);
}
{
selectedInvokers.clear();
selectedInvokers.add(invoker2);
Invoker invoker = cluster.select(null,null,invokers,selectedInvokers);
Assert.assertEquals(invoker1, invoker);
}
}
@Test
public void testSelect_multiInvokers() throws Exception {
testSelect_multiInvokers( RoundRobinLoadBalance.NAME);
testSelect_multiInvokers( LeastActiveLoadBalance.NAME);
testSelect_multiInvokers( RandomLoadBalance.NAME);
}
@Test
public void testCloseAvailablecheck(){
LoadBalance lb = EasyMock.createMock(LoadBalance.class);
EasyMock.expect(lb.select(invokers, invocation)).andReturn(invoker1);
EasyMock.replay(lb);
initlistsize5();
Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers);
Assert.assertEquals(false,sinvoker.isAvailable());
Assert.assertEquals(invoker1,sinvoker);
}
@Test
public void testDonotSelectAgainAndNoCheckAvailable(){
LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(RoundRobinLoadBalance.NAME);
initlistsize5();
{
//边界测试.
selectedInvokers.clear();
selectedInvokers.add(invoker2);
selectedInvokers.add(invoker3);
selectedInvokers.add(invoker4);
selectedInvokers.add(invoker5);
Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers);
Assert.assertSame(invoker1, sinvoker);
}
{
//边界测试.
selectedInvokers.clear();
selectedInvokers.add(invoker1);
selectedInvokers.add(invoker3);
selectedInvokers.add(invoker4);
selectedInvokers.add(invoker5);
Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers);
Assert.assertSame(invoker2, sinvoker);
}
{
//边界测试.
selectedInvokers.clear();
selectedInvokers.add(invoker1);
selectedInvokers.add(invoker2);
selectedInvokers.add(invoker4);
selectedInvokers.add(invoker5);
Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers );
Assert.assertSame(invoker3, sinvoker);
}
{
//边界测试.
selectedInvokers.clear();
selectedInvokers.add(invoker1);
selectedInvokers.add(invoker2);
selectedInvokers.add(invoker3);
selectedInvokers.add(invoker4);
Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers );
Assert.assertSame(invoker5, sinvoker);
}
{
//边界测试.
selectedInvokers.clear();
selectedInvokers.add(invoker1);
selectedInvokers.add(invoker2);
selectedInvokers.add(invoker3);
selectedInvokers.add(invoker4);
selectedInvokers.add(invoker5);
Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers);
Assert.assertTrue(invokers.contains(sinvoker));
}
}
@Test
public void testSelectAgainAndCheckAvailable(){
LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(RoundRobinLoadBalance.NAME);
initlistsize5();
{
//边界测试.
selectedInvokers.clear();
selectedInvokers.add(invoker1);
selectedInvokers.add(invoker2);
selectedInvokers.add(invoker3);
selectedInvokers.add(invoker5);
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertTrue(sinvoker == invoker4 );
}
{
//边界测试.
selectedInvokers.clear();
selectedInvokers.add(invoker2);
selectedInvokers.add(invoker3);
selectedInvokers.add(invoker4);
selectedInvokers.add(invoker5);
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertTrue(sinvoker == invoker2 || sinvoker == invoker4);
}
{
//边界测试.
for(int i=0;i<100;i++){
selectedInvokers.clear();
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertTrue(sinvoker == invoker2 || sinvoker == invoker4);
}
}
{
//边界测试.
for(int i=0;i<100;i++){
selectedInvokers.clear();
selectedInvokers.add(invoker1);
selectedInvokers.add(invoker3);
selectedInvokers.add(invoker5);
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertTrue(sinvoker == invoker2 || sinvoker == invoker4);
}
}
{
//边界测试.
for(int i=0;i<100;i++){
selectedInvokers.clear();
selectedInvokers.add(invoker1);
selectedInvokers.add(invoker3);
selectedInvokers.add(invoker2);
selectedInvokers.add(invoker4);
selectedInvokers.add(invoker5);
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertTrue(sinvoker == invoker2 || sinvoker == invoker4);
}
}
}
public void testSelect_multiInvokers(String lbname) throws Exception {
int min=1000,max=5000;
Double d = (Math.random()*(max-min+1)+min);
int runs = d.intValue();
Assert.assertTrue(runs>min);
LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(lbname);
initlistsize5();
for(int i=0;i<runs;i++){
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertEquals(true,sinvoker.isAvailable());
}
for(int i=0;i<runs;i++){
selectedInvokers.clear();
selectedInvokers.add(invoker1);
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertEquals(true,sinvoker.isAvailable());
}
for(int i=0;i<runs;i++){
selectedInvokers.clear();
selectedInvokers.add(invoker2);
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertEquals(true,sinvoker.isAvailable());
}
for(int i=0;i<runs;i++){
selectedInvokers.clear();
selectedInvokers.add(invoker2);
selectedInvokers.add(invoker4);
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertEquals(true,sinvoker.isAvailable());
}
for(int i=0;i<runs;i++){
selectedInvokers.clear();
selectedInvokers.add(invoker1);
selectedInvokers.add(invoker3);
selectedInvokers.add(invoker5);
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertEquals(true,sinvoker.isAvailable());
}
for(int i=0;i<runs;i++){
selectedInvokers.clear();
selectedInvokers.add(invoker1);
selectedInvokers.add(invoker2);
selectedInvokers.add(invoker3);
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertEquals(true,sinvoker.isAvailable());
}
}
/**
* 测试均衡.
*/
@Test
public void testSelectBalance(){
LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(RoundRobinLoadBalance.NAME);
initlistsize5();
Map<Invoker,AtomicLong> counter = new ConcurrentHashMap<Invoker,AtomicLong>();
for(Invoker invoker :invokers){
counter.put(invoker, new AtomicLong(0));
}
int runs = 1000;
for(int i=0;i<runs;i++){
selectedInvokers.clear();
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
counter.get(sinvoker).incrementAndGet();
}
for (Invoker minvoker :counter.keySet() ){
Long count = counter.get(minvoker).get();
// System.out.println(count);
if(minvoker.isAvailable())
Assert.assertTrue("count should > avg", count>runs/invokers.size());
}
Assert.assertEquals(runs, counter.get(invoker2).get()+counter.get(invoker4).get());;
}
private void initlistsize5(){
invokers.clear();
selectedInvokers.clear();//需要清除,之前的测试中会主动将正确的invoker2放入其中.
invokers.add(invoker1);
invokers.add(invoker2);
invokers.add(invoker3);
invokers.add(invoker4);
invokers.add(invoker5);
}
@Test
public void testInvoke() {
// fail("Not yet implemented");
}
@Test
public void testDoInvoke() {
// fail("Not yet implemented");
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import junit.framework.Assert;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.utils.LogUtil;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.RpcResult;
import com.alibaba.dubbo.rpc.cluster.Directory;
import com.alibaba.dubbo.rpc.cluster.filter.DemoService;
/**
* FailfastClusterInvokerTest
* @author tony.chenl
*
*/
@SuppressWarnings("unchecked")
public class FailSafeClusterInvokerTest {
List<Invoker<DemoService>> invokers = new ArrayList<Invoker<DemoService>>();
URL url = URL.valueOf("test://test:11/test");
Invoker<DemoService> invoker = EasyMock.createMock(Invoker.class);
Invocation invocation;
Directory<DemoService> dic ;
Result result = new RpcResult();
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
dic = EasyMock.createMock(Directory.class);
invocation = EasyMock.createMock(Invocation.class);
EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(dic.list(invocation)).andReturn(invokers).anyTimes();
EasyMock.expect(dic.getInterface()).andReturn(DemoService.class).anyTimes();
EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes();
EasyMock.replay(dic,invocation);
invokers.add(invoker);
}
@After
public void tearDown(){
EasyMock.verify(invoker,dic,invocation);
}
private void resetInvokerToException(){
EasyMock.reset(invoker);
EasyMock.expect(invoker.invoke(invocation)).andThrow(new RuntimeException()).anyTimes();
EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker.getInterface()).andReturn(DemoService.class).anyTimes();
EasyMock.replay(invoker);
}
private void resetInvokerToNoException(){
EasyMock.reset(invoker);
EasyMock.expect(invoker.invoke(invocation)).andReturn(result).anyTimes();
EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker.getInterface()).andReturn(DemoService.class).anyTimes();
EasyMock.replay(invoker);
}
//TODO assert error log
@Test
public void testInvokeExceptoin() {
resetInvokerToException();
FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);
invoker.invoke(invocation);
Assert.assertNull(RpcContext.getContext().getInvoker());
}
@Test()
public void testInvokeNoExceptoin() {
resetInvokerToNoException();
FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);
Result ret = invoker.invoke(invocation);
Assert.assertSame(result, ret);
}
@Test()
public void testNoInvoke() {
dic = EasyMock.createMock(Directory.class);
invocation = EasyMock.createMock(Invocation.class);
EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(dic.list(invocation)).andReturn(null).anyTimes();
EasyMock.expect(dic.getInterface()).andReturn(DemoService.class).anyTimes();
EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes();
EasyMock.replay(dic,invocation);
resetInvokerToNoException();
FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);
LogUtil.start();
invoker.invoke(invocation);
assertEquals(1,LogUtil.findMessage("No provider"));
LogUtil.stop();
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import junit.framework.Assert;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.utils.LogUtil;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.RpcResult;
import com.alibaba.dubbo.rpc.cluster.Directory;
/**
* FailbackClusterInvokerTest
*
* @author tony.chenl
*/
@SuppressWarnings("unchecked")
public class FailbackClusterInvokerTest {
List<Invoker<FailbackClusterInvokerTest>> invokers = new ArrayList<Invoker<FailbackClusterInvokerTest>>();
URL url = URL.valueOf("test://test:11/test");
Invoker<FailbackClusterInvokerTest> invoker = EasyMock.createMock(Invoker.class);
Invocation invocation;
Directory<FailbackClusterInvokerTest> dic;
Result result = new RpcResult();
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
dic = EasyMock.createMock(Directory.class);
invocation = EasyMock.createMock(Invocation.class);
EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(dic.list(invocation)).andReturn(invokers).anyTimes();
EasyMock.expect(dic.getInterface()).andReturn(FailbackClusterInvokerTest.class).anyTimes();
EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes();
EasyMock.replay(dic, invocation);
invokers.add(invoker);
}
@After
public void tearDown() {
EasyMock.verify(invoker, dic, invocation);
}
private void resetInvokerToException() {
EasyMock.reset(invoker);
EasyMock.expect(invoker.invoke(invocation)).andThrow(new RuntimeException()).anyTimes();
EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker.getInterface()).andReturn(FailbackClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker);
}
private void resetInvokerToNoException() {
EasyMock.reset(invoker);
EasyMock.expect(invoker.invoke(invocation)).andReturn(result).anyTimes();
EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker.getInterface()).andReturn(FailbackClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker);
}
@Test
public void testInvokeExceptoin() {
resetInvokerToException();
FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
dic);
invoker.invoke(invocation);
Assert.assertNull(RpcContext.getContext().getInvoker());
}
@Test()
public void testInvokeNoExceptoin() {
resetInvokerToNoException();
FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
dic);
Result ret = invoker.invoke(invocation);
Assert.assertSame(result, ret);
}
@Test()
public void testNoInvoke() {
dic = EasyMock.createMock(Directory.class);
invocation = EasyMock.createMock(Invocation.class);
EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(dic.list(invocation)).andReturn(null).anyTimes();
EasyMock.expect(dic.getInterface()).andReturn(FailbackClusterInvokerTest.class).anyTimes();
EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes();
EasyMock.replay(dic, invocation);
invokers.add(invoker);
resetInvokerToNoException();
FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
dic);
LogUtil.start();
invoker.invoke(invocation);
assertEquals(1, LogUtil.findMessage("Failback to invoke"));
LogUtil.stop();
}
@Test()
public void testRetryFailed() {
resetInvokerToException();
FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
dic);
invoker.invoke(invocation);
Assert.assertNull(RpcContext.getContext().getInvoker());
invoker.retryFailed();// when retry the invoker which get from failed map already is not the mocked invoker,so
// it can be invoke successfully
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.List;
import junit.framework.Assert;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.RpcResult;
import com.alibaba.dubbo.rpc.cluster.Directory;
/**
* FailfastClusterInvokerTest
* @author liuchao
*
*/
@SuppressWarnings("unchecked")
public class FailfastClusterInvokerTest {
List<Invoker<FailfastClusterInvokerTest>> invokers = new ArrayList<Invoker<FailfastClusterInvokerTest>>();
URL url = URL.valueOf("test://test:11/test");
Invoker<FailfastClusterInvokerTest> invoker1 = EasyMock.createMock(Invoker.class);
Invocation invocation;
Directory<FailfastClusterInvokerTest> dic ;
Result result = new RpcResult();
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
dic = EasyMock.createMock(Directory.class);
invocation = EasyMock.createMock(Invocation.class);
EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(dic.list(invocation)).andReturn(invokers).anyTimes();
EasyMock.expect(dic.getInterface()).andReturn(FailfastClusterInvokerTest.class).anyTimes();
EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes();
EasyMock.replay(dic,invocation);
invokers.add(invoker1);
}
@After
public void tearDown(){
EasyMock.verify(invoker1,dic,invocation);
}
private void resetInvoker1ToException(){
EasyMock.reset(invoker1);
EasyMock.expect(invoker1.invoke(invocation)).andThrow(new RuntimeException()).anyTimes();
EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker1.getInterface()).andReturn(FailfastClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker1);
}
private void resetInvoker1ToNoException(){
EasyMock.reset(invoker1);
EasyMock.expect(invoker1.invoke(invocation)).andReturn(result).anyTimes();
EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker1.getInterface()).andReturn(FailfastClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker1);
}
@Test(expected = RpcException.class)
public void testInvokeExceptoin() {
resetInvoker1ToException();
FailfastClusterInvoker<FailfastClusterInvokerTest> invoker = new FailfastClusterInvoker<FailfastClusterInvokerTest>(dic);
invoker.invoke(invocation);
Assert.assertSame(invoker1, RpcContext.getContext().getInvoker());
}
@Test()
public void testInvokeNoExceptoin() {
resetInvoker1ToNoException();
FailfastClusterInvoker<FailfastClusterInvokerTest> invoker = new FailfastClusterInvoker<FailfastClusterInvokerTest>(dic);
Result ret = invoker.invoke(invocation);
Assert.assertSame(result, ret);
}
@Test()
public void testNoInvoke() {
dic = EasyMock.createMock(Directory.class);
invocation = EasyMock.createMock(Invocation.class);
EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(dic.list(invocation)).andReturn(null).anyTimes();
EasyMock.expect(dic.getInterface()).andReturn(FailfastClusterInvokerTest.class).anyTimes();
EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes();
EasyMock.replay(dic,invocation);
invokers.add(invoker1);
resetInvoker1ToNoException();
FailfastClusterInvoker<FailfastClusterInvokerTest> invoker = new FailfastClusterInvoker<FailfastClusterInvokerTest>(dic);
try {
invoker.invoke(invocation);
fail();
} catch (RpcException expected) {
}
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.List;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.RpcResult;
import com.alibaba.dubbo.rpc.cluster.Directory;
/**
* FailoverClusterInvokerTest
* @author liuchao
*
*/
@SuppressWarnings("unchecked")
public class FailoverClusterInvokerTest {
List<Invoker<FailoverClusterInvokerTest>> invokers = new ArrayList<Invoker<FailoverClusterInvokerTest>>();
int retries = 5;
URL url = URL.valueOf("test://test:11/test?retries="+retries);
Invoker<FailoverClusterInvokerTest> invoker1 = EasyMock.createMock(Invoker.class);
Invoker<FailoverClusterInvokerTest> invoker2 = EasyMock.createMock(Invoker.class);
Invocation invocation;
Directory<FailoverClusterInvokerTest> dic ;
Result result = new RpcResult();
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
dic = EasyMock.createMock(Directory.class);
invocation = EasyMock.createMock(Invocation.class);
EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(dic.list(invocation)).andReturn(invokers).anyTimes();
EasyMock.expect(dic.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes();
EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes();
EasyMock.replay(dic,invocation);
invokers.add(invoker1);
invokers.add(invoker2);
}
@Test
public void testInvokeWithRuntimeException() {
EasyMock.reset(invoker1);
EasyMock.expect(invoker1.invoke(invocation)).andThrow(new RuntimeException()).anyTimes();
EasyMock.expect(invoker1.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker1.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker1);
EasyMock.reset(invoker2);
EasyMock.expect(invoker2.invoke(invocation)).andThrow(new RuntimeException()).anyTimes();
EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker2.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker2);
FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
try {
invoker.invoke(invocation);
fail();
} catch (RpcException expected) {
assertEquals(0,expected.getCode());
}
}
@Test()
public void testInvokeWithRPCException() {
EasyMock.reset(invoker1);
EasyMock.expect(invoker1.invoke(invocation)).andThrow(new RpcException()).anyTimes();
EasyMock.expect(invoker1.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker1.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker1);
EasyMock.reset(invoker2);
EasyMock.expect(invoker2.invoke(invocation)).andReturn(result).anyTimes();
EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker2.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker2);
FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
for(int i=0;i<100;i++){
Result ret = invoker.invoke(invocation);
assertSame(result, ret);
}
}
@Test()
public void testInvoke_retryTimes() {
EasyMock.reset(invoker1);
EasyMock.expect(invoker1.invoke(invocation)).andThrow(new RpcException(RpcException.TIMEOUT_EXCEPTION)).anyTimes();
EasyMock.expect(invoker1.isAvailable()).andReturn(false).anyTimes();
EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker1.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker1);
EasyMock.reset(invoker2);
EasyMock.expect(invoker2.invoke(invocation)).andThrow(new RpcException()).anyTimes();
EasyMock.expect(invoker2.isAvailable()).andReturn(false).anyTimes();
EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker2.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker2);
FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
try{
Result ret = invoker.invoke(invocation);
assertSame(result, ret);
fail();
}catch (RpcException expected) {
assertTrue(expected.isTimeout());
assertTrue(expected.getMessage().indexOf((retries+1)+" times")>0);
}
}
@Test()
public void testNoInvoke() {
dic = EasyMock.createMock(Directory.class);
invocation = EasyMock.createMock(Invocation.class);
EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(dic.list(invocation)).andReturn(null).anyTimes();
EasyMock.expect(dic.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes();
EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes();
EasyMock.replay(dic,invocation);
invokers.add(invoker1);
FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
try {
invoker.invoke(invocation);
fail();
} catch (RpcException expected) {
expected.printStackTrace();
}
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.support;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import junit.framework.Assert;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.RpcResult;
import com.alibaba.dubbo.rpc.cluster.Directory;
/**
* ForkingClusterInvokerTest
*
* @author tony.chenl
*/
@SuppressWarnings("unchecked")
public class ForkingClusterInvokerTest {
List<Invoker<ForkingClusterInvokerTest>> invokers = new ArrayList<Invoker<ForkingClusterInvokerTest>>();
URL url = URL.valueOf("test://test:11/test?forks=2");
Invoker<ForkingClusterInvokerTest> invoker1 = EasyMock.createMock(Invoker.class);
Invoker<ForkingClusterInvokerTest> invoker2 = EasyMock.createMock(Invoker.class);
Invoker<ForkingClusterInvokerTest> invoker3 = EasyMock.createMock(Invoker.class);
Invocation invocation;
Directory<ForkingClusterInvokerTest> dic;
Result result = new RpcResult();
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
dic = EasyMock.createMock(Directory.class);
invocation = EasyMock.createMock(Invocation.class);
EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(dic.list(invocation)).andReturn(invokers).anyTimes();
EasyMock.expect(dic.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes();
EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes();
EasyMock.replay(dic, invocation);
invokers.add(invoker1);
invokers.add(invoker2);
invokers.add(invoker3);
}
@After
public void tearDown() {
EasyMock.verify(invoker1, dic, invocation);
}
private void resetInvokerToException() {
EasyMock.reset(invoker1);
EasyMock.expect(invoker1.invoke(invocation)).andThrow(new RuntimeException()).anyTimes();
EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker1.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker1.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker1);
EasyMock.reset(invoker2);
EasyMock.expect(invoker2.invoke(invocation)).andThrow(new RuntimeException()).anyTimes();
EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker2.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker2);
EasyMock.reset(invoker3);
EasyMock.expect(invoker3.invoke(invocation)).andThrow(new RuntimeException()).anyTimes();
EasyMock.expect(invoker3.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker3.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker3.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker3);
}
private void resetInvokerToNoException() {
EasyMock.reset(invoker1);
EasyMock.expect(invoker1.invoke(invocation)).andReturn(result).anyTimes();
EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker1.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker1.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker1);
EasyMock.reset(invoker2);
EasyMock.expect(invoker2.invoke(invocation)).andReturn(result).anyTimes();
EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker2.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker2);
EasyMock.reset(invoker3);
EasyMock.expect(invoker3.invoke(invocation)).andReturn(result).anyTimes();
EasyMock.expect(invoker3.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(invoker3.isAvailable()).andReturn(true).anyTimes();
EasyMock.expect(invoker3.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes();
EasyMock.replay(invoker3);
}
@Test
public void testInvokeExceptoin() {
resetInvokerToException();
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
dic);
Assert.assertNull(invoker.invoke(invocation).getResult());
Assert.assertNotNull(invoker.invoke(invocation).getException());
}
@Test()
public void testInvokeNoExceptoin() {
resetInvokerToNoException();
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
dic);
Result ret = invoker.invoke(invocation);
Assert.assertSame(result, ret);
}
@Test()
public void testNoInvoke() {
dic = EasyMock.createMock(Directory.class);
invocation = EasyMock.createMock(Invocation.class);
EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes();
EasyMock.expect(dic.list(invocation)).andReturn(null).anyTimes();
EasyMock.expect(dic.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes();
EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes();
EasyMock.replay(dic, invocation);
resetInvokerToNoException();
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
dic);
try {
invoker.invoke(invocation);
} catch (RpcException expected) {
assertTrue(expected.getMessage().contains("No provider"));
}
}
}
\ No newline at end of file
function route(invokers,invocation,context){
var result = new java.util.ArrayList(invokers.size());
for (i=0;i<invokers.size(); i++){
if (invokers.get(i).isAvailable()) {
result.add(invokers.get(i)) ;
}
} ;
return result;
};
route(invokers,invocation,context);
\ No newline at end of file
function route(invokers,invocation,context){
var result = new java.util.ArrayList();
if (invokers.size()>1 && invocation.getMethodName() .equals("method1")) {
result.add(invokers.get(0)) ;
} else {
result.add(invokers.get(1)) ;
}
return result;
};
route(invokers,invocation,context);
\ No newline at end of file
function route(invokers,invocation,context){
var result = new java.util.ArrayList(invokers.size());
for (i=0;i<invokers.size(); i++){
if (!invokers.get(i).isAvailable()) {
result.add(invokers.get(i)) ;
}
} ;
return result;
};
route(invokers,invocation,context);
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
- 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.
- See the License for the specific language governing permissions and
- limitations under the License.
-->
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
<appender name="DUBBO" class="com.alibaba.dubbo.common.utils.DubboAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%d{dd/MM/yy hh:mm:ss:sss z}] %t %5p %c{2}: %m%n" />
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="DUBBO" />
</root>
</log4j:configuration>
\ No newline at end of file
<!--
- 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.
- See the License for the specific language governing permissions and
- limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-parent</artifactId>
<version>2.0.9</version>
</parent>
<artifactId>dubbo-common</artifactId>
<packaging>jar</packaging>
<name>Dubbo Common Module</name>
<description>The common module of dubbo project</description>
<properties>
<skip_maven_deploy>true</skip_maven_deploy>
</properties>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>hessian-lite</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.common;
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;
/**
* 在{@link ExtensionLoader}生成Extension的Adaptive Instance时,为{@link ExtensionLoader}提供信息。
*
* @author ding.lid
*
* @see ExtensionLoader
* @see URL
* @see Extension
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Adaptive {
/**
* 从{@link URL}的Key名,对应的Value作为要Adapt成的Extension名。
* <p>
* 如果{@link URL}这些Key都没有Value,使用 用 缺省的扩展(在接口的{@link Extension}中设定的值)。<br>
* 比如,<code>String[] {"key1", "key2"}</code>,表示
* <ol>
* <li>先在URL上找key1的Value作为要Adapt成的Extension名;
* <li>key1没有Value,则使用key2的Value作为要Adapt成的Extension名。
* <li>key2没有Value,使用缺省的扩展。
* <li>如果没有设定缺省扩展,则方法调用会抛出{@link IllegalStateException}。
* </ol>
* <p>
* 如果不设置则缺省使用Extension接口类名的点分隔小写字串。<br>
* 即对于Extension接口{@code com.alibaba.dubbo.xxx.YyyInvokerWrapper}的缺省值为<code>String[] {"yyy.invoker.wrapper"}</code>
*
* @see Extension#value()
*/
String[] value() default {};
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.common;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
/**
* Constants
*
* @author william.liangf
*/
public class Constants {
public static final List<String> DEFAULT_TELNET_COMMANDS = Collections.unmodifiableList(Arrays.asList(new String[] {
"ls", "ps", "cd", "pwd", "invoke", "count", "trace", "status", "log", "help", "clear", "exit" }));
public static final List<String> DEFAULT_CHECK_STATUSES = Collections.unmodifiableList(Arrays.asList(new String[] {
"server", "registry", "threadpool", "datasource", "spring", "memory", "load" }));
public static final String DUBBO_PROPERTIES_KEY = "dubbo.properties.file";
public static final String DEFAULT_DUBBO_PROPERTIES = "dubbo.properties";
public static final String SENT_KEY = "sent";
public static final boolean DEFAULT_SENT = false;
public static final String REGISTRY_PROTOCOL = "registry";
public static final String $INVOKE = "$invoke";
public static final String $ECHO = "$echo";
public static final int DEFAULT_IO_THREADS = Runtime.getRuntime().availableProcessors() + 1;
public static final String DEFAULT_PROXY = "javassist";
public static final int DEFAULT_PAYLOAD = 8 * 1024 * 1024; // 8M
public static final String DEFAULT_CLUSTER = "failover";
public static final String DEFAULT_DIRECTORY = "dubbo";
public static final String DEFAULT_LOADBALANCE = "random";
public static final String DEFAULT_PROTOCOL = "dubbo";
public static final String DEFAULT_EXCHANGER = "header";
public static final String DEFAULT_TRANSPORTER = "netty";
public static final String DEFAULT_REMOTING_SERVER = "netty";
public static final String DEFAULT_REMOTING_CLIENT = "netty";
public static final String DEFAULT_REMOTING_CODEC = "dubbo";
public static final String DEFAULT_REMOTING_SERIALIZATION = "hessian2";
public static final String DEFAULT_HTTP_SERVER = "servlet";
public static final String DEFAULT_HTTP_CLIENT = "jdk";
public static final String DEFAULT_HTTP_SERIALIZATION = "json";
public static final String DEFAULT_CHARSET = "UTF-8";
public static final int DEFAULT_WEIGHT = 5;
public static final int DEFAULT_FORKS = 2;
public static final String DEFAULT_THREAD_NAME = "Dubbo";
public static final int DEFAULT_THREADS = 100;
public static final int DEFAULT_QUEUES = 0;
public static final int DEFAULT_THREAD_ALIVE = 60 * 1000;
public static final int DEFAULT_CONNECTIONS = 0;
public static final int DEFAULT_ACCEPTS = 0;
public static final int DEFAULT_IDLE_TIMEOUT = 600 * 1000;
public static final int DEFAULT_HEARTBEAT = 0;
public static final int DEFAULT_TIMEOUT = 5000;
public static final int DEFAULT_RETRIES = 2;
// default buffer size is 8k.
public static final int DEFAULT_BUFFER_SIZE = 8 * 1024;
public static final int MAX_BUFFER_SIZE = 16 * 1024;
public static final int MIN_BUFFER_SIZE = 1 * 1024;
public static final String REMOVE_VALUE_PREFIX = "-";
public static final String HIDE_KEY_PREFIX = ".";
public static final String DEFAULT_KEY_PREFIX = "default.";
public static final String DEFAULT_KEY = "default";
public static final String LOADBALANCE_KEY = "loadbalance";
public static final String ROUTER_KEY = "router";
public static final String CLUSTER_KEY = "cluster";
public static final String REGISTRY_KEY = "registry";
public static final String MONITOR_KEY = "monitor";
public static final String DEFAULT_REGISTRY = "dubbo";
public static final String BACKUP_KEY = "backup";
public static final String DIRECTORY_KEY = "directory";
public static final String DEPRECATED_KEY = "deprecated";
public static final String ANYHOST_KEY = "anyhost";
public static final String APPLICATION_KEY = "application";
public static final String LOCAL_KEY = "local";
public static final String STUB_KEY = "stub";
public static final String MOCK_KEY = "mock";
public static final String PROTOCOL_KEY = "protocol";
public static final String PROXY_KEY = "proxy";
public static final String WEIGHT_KEY = "weight";
public static final String FORKS_KEY = "forks";
public static final String DEFAULT_THREADPOOL = "fixed";
public static final String DEFAULT_CLIENT_THREADPOOL = "cached";
public static final String THREADPOOL_KEY = "threadpool";
public static final String THREAD_NAME_KEY = "threadname";
public static final String IO_THREADS_KEY = "iothreads";
public static final String THREADS_KEY = "threads";
public static final String QUEUES_KEY = "queues";
public static final String THREAD_ALIVE_KEY = "threadalive";
public static final String EXECUTES_KEY = "executes";
public static final String BUFFER_KEY = "buffer";
public static final String PAYLOAD_KEY = "payload";
public static final String REFERENCE_FILTER_KEY = "reference.filter";
public static final String INVOKER_LISTENER_KEY = "invoker.listener";
public static final String SERVICE_FILTER_KEY = "service.filter";
public static final String EXPORTER_LISTENER_KEY = "exporter.listener";
public static final String ACCESS_LOG_KEY = "accesslog";
public static final String ACTIVES_KEY = "actives";
public static final String CONNECTIONS_KEY = "connections";
public static final String ACCEPTS_KEY = "accepts";
public static final String IDLE_TIMEOUT_KEY = "idle.timeout";
public static final String HEARTBEAT_KEY = "heartbeat";
public static final String HEARTBEAT_TIMEOUT_KEY = "heartbeat.timeout";
public static final String CONNECT_TIMEOUT_KEY = "connect.timeout";
public static final String TIMEOUT_KEY = "timeout";
public static final String RETRIES_KEY = "retries";
public static final String CODEC_KEY = "codec";
public static final String DOWNSTREAM_CODEC_KEY = "codec.downstream";
public static final String SERIALIZATION_KEY = "serialization";
public static final String EXCHANGER_KEY = "exchanger";
public static final String TRANSPORTER_KEY = "transporter";
public static final String SERVER_KEY = "server";
public static final String CLIENT_KEY = "client";
public static final String ASYNC_KEY = "async";
public static final String TOKEN_KEY = "token";
public static final String METHODS_KEY = "methods";
public static final String CHARSET_KEY = "charset";
public static final String RECONNECT_KEY = "reconnect";
public static final String SEND_RECONNECT_KEY = "send.reconnect";
public static final int DEFAULT_RECONNECT_PERIOD = 2000;
public static final String SHUTDOWN_TIMEOUT_KEY = "shutdown.timeout";
public static final int DEFAULT_SHUTDOWN_TIMEOUT = 1000 * 60 * 5;
public static final String CHECK_KEY = "check";
public static final String REGISTER_KEY = "register";
public static final String GROUP_KEY = "group";
public static final String PATH_KEY = "path";
public static final String INTERFACE_KEY = "interface";
public static final String GENERIC_KEY = "generic";
public static final String FILE_KEY = "file";
public static final String WAIT_KEY = "wait";
public static final String ADMIN_KEY = "admin";
public static final String VERSION_KEY = "version";
public static final String REVISION_KEY = "revision";
public static final String DUBBO_VERSION_KEY = "dubbo";
public static final String HESSIAN_VERSION_KEY = "hessian.version";
public static final String CHANNEL_HANDLER_KEY = "channel.handler";
public static final String DEFAULT_CHANNEL_HANDLER = "default";
public static final String ANY_VALUE = "*";
public static final String COMMA_SEPARATOR = ",";
public static final Pattern COMMA_SPLIT_PATTERN = Pattern.compile("\\s*[,]+\\s*");
public static final String REGISTRY_SEPARATOR = "|";
public static final Pattern REGISTRY_SPLIT_PATTERN = Pattern.compile("\\s*[|]+\\s*");
public static final String SEMICOLON_SEPARATOR = ";";
public static final Pattern SEMICOLON_SPLIT_PATTERN = Pattern.compile("\\s*[;]+\\s*");
public static final String CONNECT_QUENE_CAPACITY = "connect.quene.capacity";
public static final String CONNECT_QUENE_WARNING_SIZE = "connect.quene.warning.size";
public static final int DEFAULT_CONNECT_QUENE_WARNING_SIZE = 1000;
public static final String CHANNEL_ATTRIBUTE_READONLY_KEY = "channel.readonly";
public static final String CHANNEL_READONLYEVENT_SENT_KEY = "channel.readonly.sent";
public static final String CHANNEL_SEND_READONLYEVENT_KEY = "channel.readonly.send";
public static final String SUBSCRIBE_PROTOCOL = "subscribe";
public static final String EMPTY_PROTOCOL = "empty";
public static final String ROUTE_PROTOCOL = "route";
private Constants(){
}
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.common;
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;
/**
* 扩展点实现的元信息。
*
* @author william.liangf
* @author ding.lid
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Extension {
/**
* 扩展点名称。<br>
*
* 如果注解在扩展的接口上,则缺省的扩展点。<p>
*/
String value() default "";
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.common;
import com.alibaba.dubbo.common.URL;
/**
* Node. (API/SPI, Prototype, ThreadSafe)
*
* @author william.liangf
*/
public interface Node {
/**
* get url.
*
* @return url.
*/
URL getUrl();
/**
* is available.
*
* @return available.
*/
boolean isAvailable();
/**
* destroy.
*/
void destroy();
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.common;
import com.alibaba.dubbo.common.URL;
/**
* Resetable.
*
* @author william.liangf
*/
public interface Resetable {
/**
* reset.
*
* @param url
*/
void reset(URL url);
}
\ No newline at end of file
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.common;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
/**
* Version
*
* @author william.liangf
*/
public final class Version {
private Version() {}
private static final Logger logger = LoggerFactory.getLogger(Version.class);
private static final String VERSION = getVersion(Version.class, "2.0.0");
private static final boolean INTERNAL = hasResource("com/alibaba/dubbo/registry/support/remote/RemoteRegistry.class");
private static final boolean COMPATIBLE = hasResource("com/alibaba/dubbo/rpc/dubbo/internal/DubboRequest.class");
static {
// 检查是否存在重复的jar包
Version.checkDuplicate(Version.class);
}
public static String getVersion(){
return VERSION;
}
public static boolean isInternalVersion() {
return INTERNAL;
}
public static boolean isCompatibleVersion() {
return COMPATIBLE;
}
public static boolean hasResource(String path) {
try {
return Version.class.getClassLoader().getResource(path) != null;
} catch (Throwable t) {
return false;
}
}
public static String getVersion(Class<?> cls, String defaultVersion) {
try {
// 首先查找MANIFEST.MF规范中的版本号
String version = cls.getPackage().getImplementationVersion();
if (version == null || version.length() == 0) {
version = cls.getPackage().getSpecificationVersion();
}
if (version == null || version.length() == 0) {
// 如果规范中没有版本号,基于jar包名获取版本号
String file = cls.getProtectionDomain().getCodeSource().getLocation().getFile();
if (file != null && file.length() > 0 && file.endsWith(".jar")) {
file = file.substring(0, file.length() - 4);
int i = file.lastIndexOf('/');
if (i >= 0) {
file = file.substring(i + 1);
}
i = file.indexOf("-");
if (i >= 0) {
file = file.substring(i + 1);
}
while (file.length() > 0 && ! Character.isDigit(file.charAt(0))) {
i = file.indexOf("-");
if (i >= 0) {
file = file.substring(i + 1);
} else {
break;
}
}
version = file;
}
}
// 返回版本号,如果为空返回缺省版本号
return version == null || version.length() == 0 ? defaultVersion : version;
} catch (Throwable e) { // 防御性容错
// 忽略异常,返回缺省版本号
logger.error(e.getMessage(), e);
return defaultVersion;
}
}
public static void checkDuplicate(Class<?> cls) {
checkDuplicate(cls.getName().replace('.', '/') + ".class");
}
public static void checkDuplicate(String path) {
try {
// 在ClassPath搜文件
Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(path);
Set<String> files = new HashSet<String>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
if (url != null) {
String file = url.getFile();
if (file != null && file.length() > 0) {
files.add(file);
}
}
}
// 如果有多个,就表示重复
if (files.size() > 1) {
logger.error("Duplicate class " + path + " in " + files.size() + " jar " + files);
}
} catch (Throwable e) { // 防御性容错
logger.error(e.getMessage(), e);
}
}
}
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册