赞
踩
一开始AB应用在同一台机器上,是本地调用
现在分到两个地方上了
server这边有很多服务A,B,HelloService
现在要把这些服务放到服务注册中心去,客户端调用的时候直接去跟服务的注册中心去就可以直接调用
注册中心用map来实现
客户端和服务端通过socket链接
服务端首先需要一些内部成员:
public class ServerCenter implements Sever{
//这个用来存放服务名和对应的接口
private static HashMap<String,Class> serviceRegister = new HashMap<>();
private static int port;
public ServerCenter(int port){
this.port = port;
}
}
然后开启
public void start() throws IOException{
ServerSocket server = new ServerSocket();
//绑定端口
server.bind(new InetSocketAddress(port));
//接受客户端的请求
server.accept();
}
服务端要告诉客户端接口的名字和 IP地址端口号()
//参数是:1.客户端请求的服务的接口,socket的地址(即ip+port) public static <T> T getRemoteProxyObj(Class serviceInterface,InetSocketAddress addr){ /* 返回一个动态代理即可 newProxyInstance需要三个参数: 1.类加载器:需要代理哪个类,比如helloService 2.接口:需要代理的对象具备哪些功能 3.一个invocationHandler,采用匿名内部类实现 */ return (T)Proxy.newProxyInstance( serviceInterface.getClassLoader(),//服务类接口的类加载器 new Class<?>[] {serviceInterface},//服务类的接口(可能有很多个接口所以使用数组) new InvocationHandler(){//匿名内部类 @Override //只需要实现这一个方法即可 /* 三个参数: 1.proxy是代理的对象 2.method是需要代理的方法 3.args是方法参数列表 */ public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{ //1.客户端向服务端发送请求,请求某一个具体的接口 Socket socket = new Socket(); socket.connect(addr);//addr = ip + port ObjectOutputStream output = newObjectOutputStream(socket.getOutputStream()); //发送:接口名,方法名,方法参数,参数类型 output.writeUTF(serviceInterface.getName()); output.writeUTP(method.getName()); output.writeObject(method.getParameterTypes()); output.writeObject(args); } } ) }
public void start() throws IOException{ ServerSocket server = new ServerSocket(); server.bind(new InetSocketAddress(port)); Socket socket = server.accept(); /*----------从这里开始-----------*/ ObjectInputStream input = socket.getInputStream(); //因为ObjectInputStream对发送数据的顺序严格要求,因此需要参照发送的顺序逐个接受 String serviceName = input.readUTF();//服务名 String methodName = input.readUTF();//方法名 Class[] parameterTypes = (Class[])input.readObject();//参数类型 Object[] arguments = (Object[])input.readObject();//参数值 //根据客户请求,在map(serviceRegister)找到具体接口 Class ServiceClass = serviceRegister.get(serviceName); //根据方法名和参数类型找到方法 Method method = ServiceClass.getMethod(methodName,parameterTypes); //执行该方法,需要类,和参数列表(反射技术) Object result = method.invoke(ServiceClass.newInstance(),arguments); //将方法执行完毕的返回值,传给客户端 ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()); output.writeObject(result); }
public static <T> T getRemoteProxyObj(Class serviceInterface,InetSocketAddress addr){ /* 1.类加载器:需要代理哪个类,比如helloService 2.接口:需要代理的对象具备哪些功能 */ return (T)Proxy.newProxyInstance( serviceInterface.getClassLoader(), new Class<?>[] {serviceInterface}, new InvocationHandler(){ @Override public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{ /*proxy是代理的对象 method是需要代理的方法 args是方法参数列表 */ //客户端向服务端发送请求,请求某一个具体的接口 Socket socket = new Socket(); socket.connect(addr);//addr = ip + port ObjectOutputStream output = newObjectOutputStream(socket.getOutputStream()); //发送:接口名,方法名,方法参数,参数类型 output.writeUTF(serviceInterface.getName()); output.writeUTP(method.getName()); output.writeObject(method.getParameterTypes()); output.writeObject(args); /*----从这里开始-----------*/ //等待服务器处理 //接受服务器处理后的返回值 ObjectInputStream input = new ObjectInputStream(socket.getInputStream); return input.readObject(); } } ) }
最后加个try…catch…finally关掉就可以了
这里的server只能处理一个请求,需要使用多线程来处理多个客户端请求
用线程池,连接池中存在多个连接对象,每一个连接对象都可以处理一个客户请求
可以直接看github,有具体测试步骤
server:
package src; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Server { private static ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); //这个用来存放服务名和对应的接口 private static HashMap<String,Class> serviceRegister = new HashMap<>(); private static int port; private static boolean isRunning = false; public Server(int port){ this.port = port; } public void start() {//while(true){start();} //start ->线程对象 ServerSocket server = null ; try { server = new ServerSocket(); server.bind(new InetSocketAddress(port)); } catch (IOException e1) { e1.printStackTrace(); } isRunning = true ; //服务已经启动 while(true) { //具体的服务内容:接收客户端请求,处理请求,并返回结果 //100 :1 1 1 ...1 -->如果想让多个 客户端请求并发执行 //-> 多线程 System.out.println("start server...."); //客户端每次请求一次连接(发出一次请求),则服务端 从连接池中 //获取一个线程对象去处理 Socket socket = null ; try { socket = server.accept();// 等待客户端连接 } catch (IOException e) { e.printStackTrace(); } //启动线程 去处理客户请求 executor.execute(new ServiceTask(socket) ); } } public void stop() { isRunning = false; executor.shutdown(); } public void register(Class service,Class serviceImpl) { serviceRegister.put(service.getName(), serviceImpl); } private static class ServiceTask implements Runnable{ private Socket socket ; public ServiceTask() {}; public ServiceTask(Socket socket) { this.socket = socket ; } @Override public void run() { ObjectOutputStream output = null; ObjectInputStream input = null; try { input = new ObjectInputStream( socket.getInputStream()); //因为ObjectInputStream对发送数据的顺序严格要求,因此需要参照发送的顺序逐个接受 String serviceName = input.readUTF(); String methodName = input.readUTF(); Class[] parameterTypes = (Class[])input.readObject(); Object[] arguments = (Object[])input.readObject(); //根据客户请求,在map(serviceRegister)找到具体接口 Class ServiceClass = serviceRegister.get(serviceName); Method method = ServiceClass.getMethod(methodName,parameterTypes); //执行该方法,需要类,和参数列表 Object result = method.invoke(ServiceClass.newInstance(),arguments); //将方法执行完毕的返回值,传给客户端 output = new ObjectOutputStream(socket.getOutputStream()); output.writeObject(result); }catch (Exception e) { e.printStackTrace(); }finally { try { if (output != null) output.close(); if (input != null) input.close(); } catch (Exception e) { e.printStackTrace(); } } } } }
client
package src; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.InetSocketAddress; import java.net.Socket; public class Client { @SuppressWarnings("unchecked") public static <T> T getRemoteProxyObj(Class serviceInterface,InetSocketAddress addr) { return (T)Proxy.newProxyInstance( serviceInterface.getClassLoader(), new Class<?>[]{serviceInterface}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Socket socket = new Socket(); ObjectOutputStream output = null; ObjectInputStream input = null; try { socket.connect(addr); output = new ObjectOutputStream(socket.getOutputStream()); output.writeUTF(serviceInterface.getName()); output.writeUTF(method.getName()); output.writeObject(method.getParameterTypes()); output.writeObject(args); /*---等待---*/ input = new ObjectInputStream(socket.getInputStream()); return input.readObject(); }catch (Exception e) { e.printStackTrace(); return null; }finally { if(input!=null) input.close(); if(output!=null) output.close(); } } }); } }
helloServiceInterface
package src;
public interface HelloServiceInterface {
public String sayHi(String name) ;
}
helloService
package src;
public class HelloService implements HelloServiceInterface{
public String sayHi(String name) {
return "hi,"+name ;
}
}
serverTest
package src; public class ServerTest { public static void main(String[] args) { //开启一个线程 new Thread(new Runnable() { @Override public void run() { //服务中心 Server server = new Server(9999); //将HelloService接口及实现类 注册到 服务中心 server.register(HelloServiceInterface.class, HelloService.class); server.start(); } }).start();//start() } }
clientTest
package src;
import java.net.InetSocketAddress;
public class ClientTest {
public static void main(String[] args) throws ClassNotFoundException {
HelloServiceInterface service = Client.getRemoteProxyObj(
Class.forName("src.HelloServiceInterface") ,
new InetSocketAddress("127.0.0.1", 9999)) ;
System.out.println( service.sayHi("zs") ) ;
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。