根底版本
定义一个User类。
import java.io.Serializable;public class User implements Serializable { private static final long serialVersionUID = 1L; int id; String name; public User(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; }}
定义一个接口,返回User对象。
public interface IUserService { User findUserById(int id);}
实现该接口,返回User对象。
public class IUserServiceImpl implements IUserService { @Override public User findUserById(int id) { return new User(id, "Alice"); }}
定义一个服务端,建设Socket连贯,依据传入的ID值返回User对象信息。
import com.zebro.IUserService;import com.zebro.IUserServiceImpl;import com.zebro.User;import java.io.DataInputStream;import java.io.DataOutputStream;import java.net.ServerSocket;import java.net.Socket;public class Server { private static boolean running = true; public static void main(String[] args) throws Exception { ServerSocket server = new ServerSocket(8888); //循环监听 while(running){ Socket client = server.accept(); process(client); client.close(); } server.close(); } public static void process(Socket socket) throws Exception { DataInputStream dis = new DataInputStream(socket.getInputStream()); DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); //读取客户端传入的ID int id = dis.readInt(); IUserService service = new IUserServiceImpl(); User user = service.findUserById(id); dos.writeInt(user.getId()); dos.writeUTF(user.getName()); dos.flush(); }}
编写一个客户端,用于发送ID和接管返回的User对象信息。
import java.io.*;import java.net.Socket;public class Client { public static void main(String[] args) throws Exception { Socket socket = new Socket("127.0.0.1", 8888); ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); //发送给服务端 dos.writeInt(123); socket.getOutputStream().write(baos.toByteArray()); socket.getOutputStream().flush(); //接管服务端返回的后果 DataInputStream dis = new DataInputStream(socket.getInputStream()); int id = dis.readInt(); String name = dis.readUTF(); //组装 User user = new User(id,name); System.out.println(user); dos.close(); socket.close(); }}
这时候客户端不须要晓得服务端的具体方法名也能获得数据。
优化版本1
简化客户端的调用形式,引入客户端存根stub。
import java.io.ByteArrayOutputStream;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import java.net.Socket;public class Stub { public User findUserById(int id) throws IOException { Socket socket = new Socket("127.0.0.1", 8888); ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); //发送给服务端 dos.writeInt(id); socket.getOutputStream().write(baos.toByteArray()); socket.getOutputStream().flush(); //接管服务端返回的后果 DataInputStream dis = new DataInputStream(socket.getInputStream()); int idtmp = dis.readInt(); if(idtmp != id) System.out.println("error"); String name = dis.readUTF(); User user = new User(id,name); return user; }}
import java.io.IOException;public class Client { public static void main(String[] args) throws IOException { Stub stub = new Stub(); System.out.println(stub.findUserById(123)); }}
这时候客户端不须要晓得服务端的具体方法名也能获得数据。
优化版本2
上述版本中,如果服务端办法较多,客户端存根须要提供大量的办法和返回值类型封装,引入动静代理优化相干逻辑。
import com.zebro.User;import com.zebro.IUserService;import java.io.ByteArrayOutputStream;import java.io.DataInputStream;import java.io.DataOutputStream;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.net.Socket;public class Stub { public static IUserService getStub(){ InvocationHandler h = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Socket socket = new Socket("127.0.0.1", 8888); ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); dos.writeInt((Int)args); //发送给服务端 socket.getOutputStream().write(baos.toByteArray()); socket.getOutputStream().flush(); //接管服务端返回的后果 DataInputStream dis = new DataInputStream(socket.getInputStream()); int id = dis.readInt(); String name = dis.readUTF(); Object user = new User(id,name); return user; } }; //通过动静代理,实例化一个代理对象 Object o = Proxy.newProxyInstance(IUserService.class.getClassLoader(), new Class[]{IUserService.class}, h); System.out.println(o.getClass().getName()); System.out.println(o.getClass().getInterfaces()[0]); return (IUserService) o; }}
import com.zebro.IUserService;public class Client { public static void main(String[] args) { IUserService stub = Stub.getStub(); System.out.println(stub.findUserById(123)); }}
这时候客户端通过IUserService接口,能够晓得服务端的具体方法名,也能获得数据。
优化版本3
上述版本中,客户端无论调用什么办法,服务端均调用findUserById解决逻辑并返回User对象,批改为动静办法优化相干逻辑。
import java.io.*;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.net.Socket;public class Stub { static IUserService getStub(){ InvocationHandler h = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Socket socket = new Socket("127.0.0.1", 8888); ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //反对动静办法名 oos.writeUTF(method.getName()); oos.writeObject(method.getParameterTypes()); oos.writeObject(args); oos.flush(); //接管服务端返回的后果,object读入 ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); User user = (User)ois.readObject(); oos.close(); socket.close(); return user; } }; Object o = Proxy.newProxyInstance(IUserService.class.getClassLoader(), new Class[]{IUserService.class}, h); System.out.println(o.getClass().getName()); System.out.println(o.getClass().getInterfaces()[0]); return (IUserService) o; }}
import com.zebro.IUserService;import com.zebro.IUserServiceImpl;import com.zebro.User;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Method;import java.net.ServerSocket;import java.net.Socket;public class Server { private static boolean running = true; public static void main(String[] args) throws Exception { ServerSocket server = new ServerSocket(8088); while(running){ Socket client = server.accept(); process(client); client.close(); } server.close(); } public static void process(Socket socket) throws Exception { ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //服务端反对动静办法和参数的调用 String methodName = ois.readUTF(); Class[] parameterTypes = (Class[]) ois.readObject(); Object[] parameters = (Object[]) ois.readObject(); //服务类型临时还是写死的,不够灵便 IUserService service = new IUserServiceImpl(); Method method = service.getClass().getMethod(methodName, parameterTypes); User user = (User)method.invoke(service, parameters); oos.writeObject(user); oos.flush(); }}
优化版本4
上述版本中,客户端和服务端都只反对IUserService的办法调用,并且返回User对象,批改为反对任意接口办法的调用优化相干逻辑。
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.Socket;public class Stub { static Object getStub(Class c){ InvocationHandler h = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Socket socket = new Socket("127.0.0.1", 8888); ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //服务类型 oos.writeUTF(c.getName()); oos.writeUTF(method.getName()); oos.writeObject(method.getParameterTypes()); oos.writeObject(args); oos.flush(); //接管服务端返回的后果,object读入 ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Object obj = ois.readObject(); //改为返回通用对象 return obj; } }; //这里要写成通用的c,而不是固定的接口 Object o = Proxy.newProxyInstance(c.getClassLoader(), new Class[]{c}, h); System.out.println(o.getClass().getName()); System.out.println(o.getClass().getInterfaces()[0]); return o; }}
import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Method;import java.net.ServerSocket;import java.net.Socket;import java.util.HashMap;public class Server { private static boolean running = true; private static HashMap<String,Class> registerTable = new HashMap<>(); static{ registerTable.put(IUserService.class.getName(),IUserServiceImpl.class); registerTable.put(IProductService.class.getName(), IProductServiceImpl.class); } public static void main(String[] args) throws Exception { ServerSocket server = new ServerSocket(8888); while(running){ Socket client = server.accept(); process(client); client.close(); } server.close(); } public static void process(Socket socket) throws Exception { ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //为了适应客户端通用化而做的改变 String clazzName = ois.readUTF(); String methodName = ois.readUTF(); Class[] parameterTypes = (Class[]) ois.readObject(); Object[] parameters = (Object[]) ois.readObject(); //从注册表中查到服务类,如果应用spring甚至还能够间接依据配置注入bean而后依据bean查找。 Object service = registerTable.get(clazzName).newInstance(); Method method = service.getClass().getMethod(methodName, parameterTypes); Object o = method.invoke(service, parameters); oos.writeObject(o); oos.flush(); }}
import com.zebro.IProductService;import com.zebro.IUserService;public class Client { public static void main(String[] args) { IUserService userService = (IUserService) Stub.getStub(IUserService.class); IProductService productService = (IProductService)Stub.getStub(IProductService.class); System.out.println(userService.findUserById(123)); System.out.println(productService.findProductByName("Bob")); }}