需求:
企业应用要有有redundancy, 两台或者多台服务器提供HA(High available)服务,提供热备用。服务一般是EJB/RMI/Web Service等服务, 在一台发生服务故障后,客户端一般自动切换到其它可用服务器, 所有服务器都依次fail后才报错。
EJB也应该适用,但是一般EJB容器都提供了更完善的HA机制和策略。这里不cover.
不足和限制:
1. 暂时没有考虑内网/外网优先顺序。
2. 使用接口+java proxy实现拦截,接口必须。
3. web service使用动态绑定。
4. 一台失败后,遍历所有服务器,故障服务器没有排除
5. java 6以上测试通过
6. 通信失败的检测不见得完善
7. Web Service采用POJO发布,要求Port和Service名称和接口名称相同,便于简化查找。建议定义为常量。
测试服务代码(同时提供rmi/ws服务):
================================================
package org.steeven.remote;
import java.rmi.Remote;
import java.rmi.RemoteException;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
@WebService(targetNamespace = Hello.WS_QNAME)
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface Hello extends Remote {
public static final String WS_QNAME = "http://steeeven.org/client";
public String add(String a, String b) throws RemoteException;
}
package org.steeven.remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.ws.Endpoint;
@WebService(targetNamespace = Hello.WS_QNAME, portName = "Hello", serviceName = "Hello")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class ServerImpl extends UnicastRemoteObject implements Hello {
private static final long serialVersionUID = 1L;
protected ServerImpl() throws RemoteException {
super();
}
public String add(String a, String b) throws RemoteException {
if ("steeven".equals(b))
throw new RuntimeException("SH IT");
return a + b;
}
public static void main(String[] args) throws Exception {
// 发布为RMI服务
Registry registry = LocateRegistry.createRegistry(18888);
registry.bind("server", new ServerImpl());
// 发布为web service
Endpoint.publish("http://0.0.0.0:18889/server", new ServerImpl());
System.err.println("Server ready");
}
}
实现和测试代码:
===========================================
package org.steeven.client;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.rmi.ConnectException;
import java.util.LinkedList;
public class HaClient<T> {
private LinkedList<String> preferredUrls = new LinkedList<String>();
private LinkedList<String> otherUrls = new LinkedList<String>();
private T currentService;
private Class<T> type;
private ProtocolHandler protocalHandler;
InvocationHandler invokeHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
try {
try {
System.out.println("invoke: " + method);
return method.invoke(getServer(false), args);
} catch (Throwable e) {
if (protocalHandler
.isServiceOut(e instanceof InvocationTargetException ? e
.getCause()
: e)) {
System.out.println("Prefered server failed");
return method.invoke(getServer(true), args);
} else
throw e;
}
} catch (InvocationTargetException ex) {
throw ex.getCause(); // InvocationTargetExcetpion.getCause()
}
}
};
protected HaClient(ProtocolHandler protocalHandler, Class<T> type,
String service, InetSocketAddress... nameServers) {
this.protocalHandler = protocalHandler;
this.type = type;
for (InetSocketAddress address : nameServers) {
if (isLocalHost(address.getAddress()))
preferredUrls.add(protocalHandler.buildServiceUrl(service,
address));
else
otherUrls
.add(protocalHandler.buildServiceUrl(service, address));
}
}
protected HaClient(ProtocolHandler protocalHandler, Class<T> type,
LinkedList<String> preferredUrls, LinkedList<String> otherUrls) {
this.type = type;
this.protocalHandler = protocalHandler;
this.preferredUrls = preferredUrls;
this.otherUrls = otherUrls;
}
/**
* check preferred server (local host) list first, then other server list.
*/
synchronized protected T getServer(boolean retry) throws Exception {
// try local first, then others
if (!retry && currentService != null) {
System.out.println("user last server");
return currentService;
}
currentService = null;
tryServers(preferredUrls); // try preferred
if (currentService == null)
tryServers(otherUrls); // try others
if (currentService == null)
throw new ConnectException("No server available now");
return currentService;
}
/**
* remove active from list to current, roll failed server to bottom.
*/
@SuppressWarnings("unchecked")
private void tryServers(LinkedList<String> list) throws Exception {
LinkedList<String> badList = new LinkedList<String>();
try {
String url;
while (list.size() > 0) {
url = list.peek();
try {
System.out.println("trying: " + url);
// TODO URI InetAddress.isReachable(n) to ping first
currentService = (T) protocalHandler.lookupService(url,
type);
return;
} catch (Exception e) {
if (protocalHandler.isServiceOut(e)) {
System.out.println("failed to try: " + url);
list.pop();
badList.add(url);
} else
throw e;
}
}
} finally {
list.addAll(badList);
}
}
@SuppressWarnings("unchecked")
public T newInstance() {
return (T) Proxy.newProxyInstance(type.getClassLoader(),
new Class<?>[] { type }, invokeHandler);
}
private boolean isLocalHost(InetAddress address) {
boolean local = address.isLoopbackAddress()
|| address.isAnyLocalAddress();
if (!local)
try {
local = (NetworkInterface.getByInetAddress(address) != null);
} catch (SocketException e) {
}
return local;
}
public static <T> T create(ProtocolHandler protocol, Class<T> type,
String service, InetSocketAddress... addresses) {
return new HaClient<T>(protocol, type, service, addresses)
.newInstance();
}
public static <T> T create(ProtocolHandler protocol, Class<T> type,
String service, int port, String... hosts) {
InetSocketAddress[] addresses = new InetSocketAddress[hosts.length];
for (int i = 0; i < addresses.length; i++) {
addresses[i] = new InetSocketAddress(hosts[i], port);
if (addresses[i].getAddress() == null)
throw new IllegalArgumentException("Invalid host: " + hosts[i]);
}
return new HaClient<T>(protocol, type, service, addresses)
.newInstance();
}
public abstract static class ProtocolHandler {
public String buildServiceUrl(String service, InetSocketAddress address) {
return getProtocol() + "://"
+ address.getAddress().getHostAddress() + ":"
+ address.getPort() + service;
}
public abstract String getProtocol();
public abstract boolean isServiceOut(Throwable e);
public abstract Object lookupService(String url, Class<?> type)
throws Exception;
}
}
package org.steeven.client;
import java.net.ConnectException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebServiceException;
import org.steeven.remote.Hello;
/**
* High Available Http client. Provide service proxy that auto detect available
* RMI service form several servers.
*
* @author xli
*
* @param <T>
*/
public class HttpProtocolHandler extends HaClient.ProtocolHandler {
private String qname;
public HttpProtocolHandler(String qname) {
this.qname = qname;
}
@Override
public String getProtocol() {
return "http";
}
public boolean isServiceOut(Throwable e) {
return e instanceof WebServiceException
&& e.getCause() instanceof ConnectException;
}
@Override
public Object lookupService(String url, Class<?> type) throws Exception {
Service service = Service.create(new URL(url + "?wsdl"), new QName(
qname, type.getSimpleName()));
return service.getPort(new QName(Hello.WS_QNAME, type.getSimpleName()),
type);
}
public static void main(String args[]) throws Exception {
Hello hello = HaClient.create(new HttpProtocolHandler(Hello.WS_QNAME),
Hello.class, "/server", 18889, "10.80.1.113", "10.80.2.184",
"10.80.1.117");
while (true) {
try {
System.out.println("------------------------new-----------------");
System.out.println(hello.add("hello ", "steeven1"));
} catch (Exception e) {
e.printStackTrace();
}
Thread.sleep(3000);
}
}
}
package org.steeven.client;
import java.rmi.ConnectException;
import java.rmi.Naming;
import org.steeven.remote.Hello;
/**
* High Available RMI client. Provide service proxy that auto detect available
* RMI service form several servers.
*
* @author xli
*
* @param <T>
*/
public class RmiProtocolHandler extends HaClient.ProtocolHandler {
@Override
public String getProtocol() {
return "rmi";
}
public boolean isServiceOut(Throwable e) {
return e instanceof ConnectException;
}
@Override
public Object lookupService(String url, Class<?> type) throws Exception {
return Naming.lookup(url);
}
public static void main(String args[]) throws Exception {
Hello hello = HaClient.create(new RmiProtocolHandler(), Hello.class,
"/server", 18888, "10.80.1.113", "10.80.2.184", "10.80.1.117");
while (true) {
try {
System.out.println("------------------------new-----------------");
System.out.println(hello.add("hello ", "steeven1"));
} catch (Exception e) {
e.printStackTrace();
}
Thread.sleep(3000);
}
}
}
分享到:
相关推荐
具体到实验文件"rmi",这可能是RMI相关代码或者教程的集合,可能包含了服务器端和客户端的示例代码,以及如何在Java中设置和运行RMI服务的说明。"cs"可能代表"Client-Server",也就是客户端-服务器相关的文件,可能...
本示例中,"RMI 服务器与客户端源码"很可能是为了教学目的设计的,适合初学者了解RMI的基本工作原理和实践操作。 创建RMI服务器主要涉及以下步骤: 1. **定义远程接口**:远程接口是一个Java接口,其中声明了所有...
**客户端服务器交互流程:** 1. **客户端初始化ORB**:客户端创建ORB实例,设置必要的配置,如服务器地址和端口。 2. **查找IR(接口 Repository)**:客户端通过ORB查找IR,获取远程接口的IRI(接口引用标识符)。 ...
JMX以RMI方式连接的场景示例 JMX(Java Management Extensions)是一种Java技术,用于管理...JMX框架提供了一种灵活、可扩展和高效的方式来管理和监控应用程序,而RMI连接方式允许远程客户端访问MBean提供的管理功能。
【标题】:“(转)通用JAVA RMI服务器框架” 【正文】: 在Java远程方法调用(Remote Method Invocation,RMI)技术中,构建一个通用的服务器框架是提高开发效率和代码可复用性的关键。Java RMI允许分布式计算,使得...
在这个基于Java的C/S(客户端/服务器)编程实验中,我们将探讨两种不同的实现方式:基于Socket的通信和基于Java Remote Method Invocation (RMI) 的通信。 首先,我们来看基于Socket的C/S编程。Socket是网络编程的...
本实验旨在通过编写简单的HTTP 1.0客户端/服务器程序、多线程Web服务器以及RMI程序,帮助你深入理解这些关键技术。 首先,我们来看HTTP 1.0客户端/服务器程序。HTTP是超文本传输协议,它是互联网上应用最为广泛的一...
RMI使得客户端能够调用运行在远程服务器上的对象的方法,就像调用本地对象一样。这个过程涉及到一系列复杂的步骤,包括序列化、远程接口定义、注册表服务和反序列化等。 首先,我们要理解RMI的基本概念。在RMI中,...
以下是对“RMI客户端调用远程服务器方法”这一主题的详细解释: 一、RMI基本概念 1. 远程接口(Remote Interface):定义了可以被远程调用的方法,这些接口需要继承自`java.rmi.Remote`接口,并且可能抛出`java....
在给定的实验中,"客户端服务器"部分可能包括了如何建立这样的通信链路,以及如何在Java中编写请求和响应的逻辑。 其次,多线程服务器是用于处理并发请求的高效手段。当多个客户端同时连接到服务器时,单线程服务器...
RMI的核心概念包括客户端、服务端、接口和 stub/skeleton。 **1. RMI 客户端** RMI 客户端是执行远程调用的应用程序。它通过Java的`java.rmi.*`包中的类与服务端建立连接。客户端需要知道服务端的接口(远程接口)...
3. 网络通信:通过Java的Socket编程或者更高层次的API如RMI(远程方法调用)或JDBC(Java数据库连接)与服务器进行通信,发送请求并接收响应。 服务器端的主要职责包括: 1. 数据存储:服务器通常与数据库系统相...
在实际应用中,开发者可以利用这个TCP协议服务器/客户端框架,快速搭建自己的网络应用,比如游戏服务器、实时数据交换系统或者分布式应用等。通过理解和掌握上述知识点,开发者可以更好地理解和使用这个框架,进行...
RMI服务器允许一个Java对象在远程机器上执行方法,使得客户端可以像调用本地对象一样调用远程对象,极大地简化了分布式应用的开发。下面我们将深入探讨Java RMI服务器的搭建过程以及其具体实现步骤。 一、RMI基础...
rmi-客户端-服务器 RMI 客户端和服务器的简单 Java 实现 服务器 shell 脚本会将服务器库编译为 jar,然后运行服务器。 像这样运行它: ./server.sh 现在启动客户端: ./client.sh 客户端当前实现为 Groovy 脚本...
rmi技术客户端调用服务器的函数解决问题 刚刚开始准备这个rmi作业的时候,我都有点无从下手。于是我先开始一起找资料,看书,经过不断的尝试编码,以及总结错误,为后期的工作奠定了基础。 在基础知识基本搞定的...
本项目"rmi服务端与客户端小程序"提供了简单易懂的示例,帮助初学者快速理解和上手RMI。 1. **RMI基本概念** - **远程对象**:在远程JVM上运行的对象,可以通过RMI接口被本地对象调用。 - **接口**:定义了远程...
在Java的远程方法调用(Remote Method Invocation, RMI)技术中,客户端和服务端的交互是实现分布式系统的关键。RMI允许一个Java对象在一台计算机上执行另一个计算机上的对象的方法,就像是本地调用一样。本示例将...
在Java RMI中,一个JVM作为服务器,暴露远程接口,而其他JVM作为客户端,通过这些接口进行远程调用。 标题中的“rmi 远程调用 实现客户端之间会话”指的是利用RMI技术让多个客户端与同一服务端建立会话,进行交互。...
- **启动RMIServer和RMIClient**: 通常,服务器会有一个启动RMI服务的main方法,而客户端也有一个启动并连接到服务器的main方法。 4. **Java_RMI_ClientServer示例** - 项目中的`Java_RMI_ClientServer-master`很...