基础版本
定义一个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"));
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。