定義一個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")); } }