@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface RPCclass {
boolean auto() default true;
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RPCmethod {
String remoteName();
}
public interface RPClock {
public void wakeUpLock();
}
import java.lang.reflect.Method;
public class RPCMethodDefinition {
//要通过反射调用的类
private Class klass;
//要通过反射执行方法的对象
private Object object;
//要执行的方法
private Method method;
public Class getKlass() {
return klass;
}
public RPCMethodDefinition setKlass(Class klass) {
this.klass = klass;
return this;
}
public Object getObject() {
return object;
}
public RPCMethodDefinition setObject(Object object) {
this.object = object;
return this;
}
public Method getMethod() {
return method;
}
public RPCMethodDefinition setMethod(Method method) {
this.method = method;
return this;
}
}
import com.google.gson.Gson;
import com.mec.rpc.annotation.RPCmethod;
import com.mec.rpc.exception.MethodNotHaveRPCAnnotation;
import com.mec.rpc.exception.RPCNotFoundProxyObject;
import com.mec.rpc.exception.RPCProxyReadOutTimeException;
import com.mec.uitl.GsonUitl;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class RPCProxy {
//RPC服务器IP
private String serverIp;
//RPC服务器端口
private int port;
//可以将对象序列化(实际上是转为json字符串)的一种工具
private static Gson gson;
//设置超时时间
private int waitingTime;
//RPC服务器返回结果后通知的对象(这个是我自己实际工程中的应用,可以忽略)
private Map
import com.google.gson.Gson;
import com.mec.rpc.annotation.RPCclass;
import com.mec.rpc.annotation.RPCmethod;
import com.mec.rpc.exception.ClassNotHaveRPCAnnotation;
import com.mec.rpc.exception.RPCMethodParametersLengthMismatching;
import com.mec.rpc.exception.RPCServiceNotRegister;
import com.mec.rpc.exception.RPCServiceObjectNotLoad;
import com.mec.uitl.GsonUitl;
import com.mec.uitl.PackageScanner;
import com.mec.uitl.TypeUitl;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class RPCServer implements Runnable {
//用来装可以被远程调用的方法
private Map serviceMap;
//控制服务器侦听客户端线程的变量
private volatile boolean goon;
private ServerSocket serverSocket;
//json序列化工具
private static Gson gson;
//用来得到传过来的实参
private static Type type;
static {
gson = GsonUitl.gson; // gson = new GsonBuilder().create();
type = TypeUitl.type; // type = new TypeToken>() {}.getType();
}
public RPCServer() {
serviceMap = new HashMap();
goon = false;
}
//启动RPC服务器
public void start(int port) throws IOException {
serverSocket = new ServerSocket(port);
goon = true;
new Thread(this).start();
}
//关闭服务器
public void stop() {
if(serverSocket == null || serverSocket.isClosed()) {
return;
}
goon = false;
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
serverSocket = null;
}
}
//服务器主线程,侦听到就启动一个线程去处理RPC请求
public void run() {
while (goon) {
try {
Socket socket = serverSocket.accept();
new Thread(new DealRequest(socket)).start();
} catch (IOException e) {
if(goon) {
e.printStackTrace();
} else {
break;
}
}
}
}
//处理远程掉用的请求并返回结果
private class DealRequest implements Runnable {
private Socket socket;
private DataOutputStream dos;
private DataInputStream dis;
public DealRequest(Socket socket) {
this.socket = socket;
try {
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
//这里的读和写与RPCProxy写和读一一对应
public void run() {
try {
//读取远程调用的remoteName
String remoteName = dis.readUTF();
//从RPC服务集合里取出对应的RPCMethodDefinition
RPCMethodDefinition rdf = serviceMap.get(remoteName);
if(rdf == null) {
throw new RPCServiceNotRegister("服务" + remoteName + "未注册");
}
Object object = rdf.getObject();
if(object == null) {
throw new RPCServiceObjectNotLoad("服务" + remoteName + "对象未加载");
}
Method method = rdf.getMethod();
Type[] parameters = method.getGenericParameterTypes();
int parameterCount = parameters.length;
Object result = null;
if(parameterCount <= 0) {
//如果参数为0,直接反射执行该方法
result = method.invoke(object);
} else {
//如果参数不为0.先接收序列化的实参,再进行反序列化
int length = dis.readInt();
byte[] bytes = new byte[length];
dis.readFully(bytes, 0 , length);
String parameter = new String(bytes);
ArrayList parameterList = gson.fromJson(parameter, type);
if(parameterCount != parameterList.size()) {
throw new RPCMethodParametersLengthMismatching("服务" + remoteName + "参数个数不匹配" + parameterCount + " " + parameterList.size());
}
Object[] argus = new Object[parameterCount];
for (int i = 0; i < parameterCount; i++) {
argus[i] = gson.fromJson(parameterList.get(i), parameters[i]);
}
result = method.invoke(object, argus);
}
byte[] bytes= gson.toJson(result).getBytes();
dos.writeInt(bytes.length);
dos.write(bytes);
//确认数据全部发送完毕之后关闭相应资源
dos.flush();
} catch (IOException e) {
e.printStackTrace();
} catch (RPCServiceNotRegister rpcServiceNotRegister) {
rpcServiceNotRegister.printStackTrace();
} catch (RPCServiceObjectNotLoad rpcServiceObjectNotLoad) {
rpcServiceObjectNotLoad.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (RPCMethodParametersLengthMismatching rpcMethodParametersLengthMismatching) {
rpcMethodParametersLengthMismatching.printStackTrace();
} finally {
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//自动扫描指定包下的所有类,当检测到带有RPCclass注解的类时实行自动装入
public void scanPackage(String path) {
//自制的包扫描工具,可以遍历指定包下的所有类
new PackageScanner() {
public void dealClass(Class> klass) {
try {
if (klass.isAnnotationPresent(RPCclass.class)) {
addService(klass);
}
} catch (ClassNotHaveRPCAnnotation classNotHaveRPCAnnotation) {
return;
}
}
}.packageScanner(path);
}
//提供给外部增加RPCmethod的方法,参数为object时,表明该object是其调用对应类的方法时要反射执行方法的对象
public void addService(Object object) throws ClassNotHaveRPCAnnotation {
Class klass = object.getClass();
if(!klass.isAnnotationPresent(RPCclass.class)) {
throw new ClassNotHaveRPCAnnotation("class[" + klass + "]没有RPCclass注解");
}
addService(klass, object);
}
//若只给一个Class对象,如果该对象是自动装载,则自动创造一个新的对象,若该对象是另外装入,则RPCMethodDefinition里的object暂为null
public void addService(Class klass) throws ClassNotHaveRPCAnnotation {
if(!klass.isAnnotationPresent(RPCclass.class)) {
throw new ClassNotHaveRPCAnnotation("class[" + klass + "]没有RPCclass注解");
}
RPCclass rpCclass = (RPCclass) klass.getAnnotation(RPCclass.class);
try {
Object object = rpCclass.auto() ? klass.newInstance() : null;
addService(klass, object);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private void addService(Class klass, Object object) {
Method[] methods = klass.getDeclaredMethods();
for(Method method : methods) {
if(!method.isAnnotationPresent(RPCmethod.class)) {
continue;
}
RPCmethod rpcMethod = method.getAnnotation(RPCmethod.class);
String remoteName = rpcMethod.remoteName();
RPCMethodDefinition rdf = serviceMap.get(remoteName);
//若rdf不为null,则表明是延迟加载的对象,只需设置对应的object就可以
if(rdf != null) {
rdf.setObject(object);
continue;
}
serviceMap.put(remoteName, new RPCMethodDefinition()
.setKlass(klass)
.setMethod(method)
.setObject(object));
}
}
}
import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public abstract class PackageScanner {
private ClassLoader classLoader;
public PackageScanner() {
}
//实参为一个类,则得到其所在包的路径
public void packageScanner(Class> clazz) {
this.packageScanner(clazz.getPackage().getName());
}
//实参为包路径,例如com.mec
public void packageScanner(String rootPackage) {
String rootPath = rootPackage.replace(".", "/");
this.classLoader = Thread.currentThread().getContextClassLoader();
try {
//通过这种可以得到包录路径下所有的类,包括jar包里
Enumeration urls = this.classLoader.getResources(rootPath);
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
String jarProtocol = url.getProtocol();
//普通类的jarProtocol为file,jar包里的类为jar
if (jarProtocol.equals("file")) {
try {
File file = new File(url.toURI());
this.scanPackage(file.getAbsolutePath(), rootPackage);
} catch (URISyntaxException var7) {
var7.printStackTrace();
}
} else if (jarProtocol.equals("jar")) {
this.scanPackage(url);
}
}
} catch (IOException var8) {
var8.printStackTrace();
}
}
//这是抛给外部来处理遍历到到的类的方法
public abstract void dealClass(Class> var1);
//处理不是jar包里的类,利用递归遍历的方法全部过一遍
private void scanPackage(String path, String packageName) {
File curFile = new File(path);
if (curFile.exists()) {
File[] files = curFile.listFiles();
File[] var5 = files;
int var6 = files.length;
for(int var7 = 0; var7 < var6; ++var7) {
File file = var5[var7];
if (file.isDirectory()) {
this.scanPackage(file.getAbsolutePath(), packageName + "." + file.getName());
} else if (file.isFile() && file.getName().endsWith(".class")) {
String fileName = file.getName();
int dotInde = fileName.indexOf(".class");
fileName = fileName.substring(0, dotInde);
String className = packageName + "." + fileName;
try {
Class> klass = Class.forName(className);
this.dealClass(klass);
} catch (ClassNotFoundException var13) {
var13.printStackTrace();
}
}
}
}
}
//扫描jar包里的类
private void scanPackage(URL url) {
try {
JarURLConnection jarURLConnection = (JarURLConnection)url.openConnection();
JarFile jarFile = jarURLConnection.getJarFile();
Enumeration jarEntries = jarFile.entries();
while(jarEntries.hasMoreElements()) {
JarEntry jarEntry = (JarEntry)jarEntries.nextElement();
if (!jarEntry.isDirectory() && jarEntry.getName().endsWith(".class")) {
String className = jarEntry.getName();
int dotIndex = className.indexOf(".class");
className = className.substring(0, dotIndex).replace("/", ".");
if (className.startsWith("com.mec")) {
try {
Class> klass = Class.forName(className);
this.dealClass(klass);
} catch (ClassNotFoundException var9) {
var9.printStackTrace();
}
}
}
}
} catch (IOException var10) {
var10.printStackTrace();
}
}
}
import com.mec.rpc.annotation.RPCclass;
import com.mec.rpc.annotation.RPCmethod;
@RPCclass
public class Student {
private String name;
@RPCmethod(remoteName = "getStudentName")
public String getName() {
return name == null ? "小明" : name;
}
@RPCmethod(remoteName = "setStudentName")
public Student setName(String name) {
this.name = name;
return this;
}
}
import java.io.IOException;
public class ServerTest {
public static void main(String[] args) {
//创建一个RPC服务器并注册一个学生为小绿
RPCServer rpcServer = new RPCServer();
Student student = new Student();
student.setName("小绿");
rpcServer.scanPackage("com.mec.Test");
rpcServer.addService(student);
try {
rpcServer.start(54196);
} catch (IOException e) {
e.printStackTrace();
}
}
}
import com.mec.rpc.core.RPCProxy;
public class ClientTest {
public static void main(String[] args) {
RPCProxy localProxy = new RPCProxy("localhost", 54196, 5000);
Student student = localProxy.getProxy(Student.class);
System.out.println(student.getName());
}
}
如果失败的话输出的应该是小明,输出的是小绿则证明成功。
通过包扫描和注解的方式可以实现自动注入而无须手动添加RPC服务,包扫描技术非常方便的让我们处理类,通过反射可以获得有相应注解的类和方法是关键。
实际上在工程应用中哪个方法是通过RPC服务器调用的方法程序员是非常清楚的,屏蔽的只是是底层的通信细节,因此有时我们需要对方法进行异常处理,不让它影响整体程序的运行。
try {
studentName = student.getName();
}catch (Throwable e) {
if(e instanceof RPCProxyReadOutTimeException) {
System.out.println("成功捕获超时异常");
}
}