来源这位大佬https://blog.csdn.net/u013374645/article/details/82083414 , 学习之 , 模仿之 , 稳
Rpc是远程调用服务 , 通过Socket来实现时 , 服务是注册在服务端 , 客户端连上服务端实现调用对应服务
创建Service服务
服务接口
public interface ExecCommand {
String exec(String command,int num);
}
服务实现类
import xuyingwx.rpc.service.ExecCommand;
public class ExecCommandImpl implements ExecCommand{
@Override
public String exec(String command,int num) {
System.out.println(String.format("执行:", command));
System.out.println("-------------------------------");
return String.format("执行:%s 完毕", command);
}
}
创建服务端server
server接口
public interface Server {
void stop();//关闭服务端
void start() throws Exception;//启动服务端
void register(Class serviceInterface , Class impl);//注册服务
boolean isRunning();
int port();
}
server实现 , 服务端是有具体的服务实现类
public class ServerImpl implements Server{
//创建线程池
private static ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
//服务注册
private static final HashMap<String,Class> serviceRegistry = new HashMap<>();
private static boolean running = false;
private static int port;
public ServerImpl(int port) {
super();
this.port = port;
}@Override
public void stop() {
// TODO Auto-generated method stub
running = false;
executor.shutdown();
}@Override
public void start() throws Exception {
ServerSocket serverSocker = new ServerSocket();
serverSocker.bind(new InetSocketAddress(port));
System.out.println("start server");
try {
while (true) {
//启动服务端:线程池启动服务端线程,socket等待调用
executor.execute(new ServerThread(serverSocker.accept()));
System.out.println("此次循环结束");
}
} finally {
serverSocker.close();
}
}@Override
public void register(Class serviceInterface, Class impl) {
serviceRegistry.put(serviceInterface.getName(), impl);//注册服务
}@Override
public boolean isRunning() {
return this.running;
}@Override
public int port() {
return this.port;
}
public class ServerThread implements Runnable {
private Socket socket;public ServerThread(Socket accept) {
this.socket = accept;
}@Override
public void run() {
ObjectInputStream input = null;
ObjectOutputStream output = null;
try {
input = new ObjectInputStream(socket.getInputStream());
//1需要和客户端输出的顺序一样
String serviceName = input.readUTF();
String methodName = input.readUTF();
Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
Object[] arguments = (Object[]) input.readObject();
//2根据serviceName获取服务实现class , 然后再通过反射 , 调用对应的method , 实现调用服务功能
Class serviceClass = serviceRegistry.get(serviceName);
if (serviceClass == null) {
throw new ClassNotFoundException(serviceName + " not found");
}
Method method = serviceClass.getMethod(methodName, parameterTypes);
Object result = method.invoke(serviceClass.newInstance(), arguments);
//3将服务调用结果返回给客户端
output = new ObjectOutputStream(socket.getOutputStream());
output.writeObject(result);
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(input);
IOUtils.closeQuietly(output);
IOUtils.closeQuietly(socket);
}
}}
}
创建客户端Client
客户端讲道理,是有依赖到服务的接口类 , 所以知道到想要调用哪个类哪个方法 , 所以每次要调用的时候 , 可以创建socket客户端连上服务端 , 把要调用的服务的信息传到服务端 , 服务端通过反射执行 .
每次调用都要创建socket连上服务端 , 我们有interface , 所以可以通过jdk动态代理来实现 , 然后就是每次创建一个代理对象去调用
jdk动态代理handler , 用于返回代理对象 , invoke就是去创建socket客户端请求服务端
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;import org.apache.commons.io.IOUtils;
public class JdkInvocationHandler implements InvocationHandler{
private Class targetClass;
private InetSocketAddress addr;
public JdkInvocationHandler(Class targetClass,InetSocketAddress addr){
this.targetClass = targetClass;
this.addr = addr;
}
public Object newProxy(){
//返回一个代理对象
return Proxy.newProxyInstance(
this.targetClass.getClassLoader(),
new Class<?>[]{this.targetClass},
this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//通过socket连上服务端去执行对应的方法
Socket socket = null;
socket = new Socket();
socket.connect(addr);
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try {
oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeUTF(targetClass.getName());//classname
oos.writeUTF(method.getName());
oos.writeObject(method.getParameterTypes());
oos.writeObject(args);
ois = new ObjectInputStream(socket.getInputStream());//等待获取socket返回
return ois.readObject();//返回代理对象
} finally {
IOUtils.closeQuietly(socket);
IOUtils.closeQuietly(oos);
IOUtils.closeQuietly(ois);
}
}}
ServiceJdkProxy封装动态代理功能 , 返回JdkInvocationHandler创建的代理对象
import java.net.InetSocketAddress;
public class ServiceJdkProxy{
public static Object getProxyInstance(Class targetClass, final InetSocketAddress addr) {
JdkInvocationHandler jdkInvocationHandler = new JdkInvocationHandler(targetClass,addr);
Object newProxy = jdkInvocationHandler.newProxy();
return newProxy;
}
}
最后是服务提供方和消费方
ProviderRun
import xuyingwx.rpc.service.ExecCommand;
import xuyingwx.rpc.service.impl.ExecCommandImpl;
import xuyingwx.rpc.socket.server.impl.ServerImpl;public class ProviderRun {
public static void main(String[] args) {
//简单创建一个线程创建服务端 , 并注册一个服务
new Thread(new Runnable() {
public void run() {
try {
Server serviceServer = new ServerImpl(8123);
serviceServer.register(ExecCommand.class, ExecCommandImpl.class);
serviceServer.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
ConsumerRun
import java.net.InetSocketAddress;
import xuyingwx.rpc.service.ExecCommand;
import xuyingwx.rpc.socket.client.util.ServiceJdkProxy;public class ConsumerRun {
/**
* 客户端调用服务 , 使用动态代理 , 调用服务时 , 是通过socket连上服务端去执行对应的方法 , 从而实现rpc调用
*/
public static void main(String[] args) {
ExecCommand proxyInstance = (ExecCommand) ServiceJdkProxy.getProxyInstance(ExecCommand.class,new InetSocketAddress(8123));
String exec = proxyInstance.exec("asd",123);
System.out.println(exec);
}
}