定义一个User类。java
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对象。spring
public interface IUserService { User findUserById(int id); }
实现该接口,返回User对象。socket
public class IUserServiceImpl implements IUserService { @Override public User findUserById(int id) { return new User(id, "Alice"); } }
定义一个服务端,创建Socket链接,根据传入的ID值返回User对象信息。ide
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(); } }
这时候客户端不须要知道服务端的具体方法名也能取得数据。this
简化客户端的调用方式,引入客户端存根stub。.net
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)); } }
这时候客户端不须要知道服务端的具体方法名也能取得数据。代理
上述版本中,若是服务端方法较多,客户端存根须要提供大量的方法和返回值类型封装,引入动态代理优化相关逻辑。code
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接口,能够知道服务端的具体方法名,也能取得数据。server
上述版本中,客户端不管调用什么方法,服务端均调用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(); } }
上述版本中,客户端和服务端都只支持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")); } }