Java分发器技术————励志成为种田达人的渣渣
基于C/S FrameWork 的Java分发器实现
下面我们将从APP层,用户登录这个Action进行说起***,当用户对登录界面进行的登录请求时,其实是在实现request,即资源的请求***,涉及到了c/s framework里面的一系列操作,现在我们将背后发生的故事来给大家逐步分析:
先从app层的登录代码看起(LoginView类里面的代码):
// 这个方法 是被框架调用的,即在鼠标点击按钮的时候才被调用
public void actionPerformed(ActionEvent e) {
// 这里应该将用户账号和密码传输给Server,在服务器上进行验证
String id = jtxtUserName.getText().trim();
String password = new String(jpswPassword.getPassword());
password = String.valueOf(password.hashCode());
jbtnLogin.setEnabled(false);
client.sendRequest("login", new ArgumentMaker()
.addArg("id", id)
.addArg("password", password)
.toString());
}
});
让我们分析一下 点击登录按钮之后到底发生了哪些操作:
<mark>// 客户端 sendRequest 调用了 ClientConversation里面的sendRequest,
// ClientConversation调用了Communication里面的 send方法,Clinet端的dos write()方法被调用,
// Sever端 的dis里read()方法侦听到来自对端的消息,调用ServerConversation里面的
// dealMessage() 从而调用DealNetMassage类里面的 方法 ,
// 利用 反射机制 执行ServerConversation里面的 调用doResponse()方法
// 完成登录</mark>
差不多分析完成了,下来利用反射机制,则就要提到注解喽:
我们对有Action的类,方法,以及方法的参数等都进行注解,这样就能准确地通过反射机制来对方法进行调用。
给出对类进行注解的代码,名为ActionMethod以及ActionPara的注解都是相似的哦。
@Retention(RUNTIME)
@Target(TYPE)
public @interface ActionClass {
}
根据反射机制的需要,我们还需要拥有以下功能的类:
ActionBeanDefinition :
里面给出 Klass以及object,method的get和set方法
ActionBeanFactory:
“工厂”,对于每个有action注解的类进行扫描(包扫描,参看),收集有actionMethod注解的方法,将将 klass、object、method set进去形成ActionBeanDefinition
最终put 进map<actionName, ActionBeanDefinition>里面去
这里类和方法都进行了收集
对于参数的要稍微多思考一些
我们先来给出一个接口:
public interface IActionExecuter {
String doRequest(String action, String para) throws Exception;
void doResponse(String action, String para) throws Exception;
}
当我们的参数也收集好了之后,我们就应该对request进行处理
接下来给出收集参数的类里面主要代码:
private Object[] getParaValues(Method method, String para) throws Exception {
Parameter[] parameters = method.getParameters();
if (parameters.length <= 0) {
return new Object[] {};
}
Object[] res = new Object[parameters.length];
ArgumentMaker am = new ArgumentMaker(para);
// 给出了Map<String, String> paraMap
// 里面的ArgumentMaker addArg(String name, Object value)
// 方法 需要参数 参数名称,以及 参数值 将名字和参数的JSON字符串 put()进去
// getValue 提供函数名称,以及参数的类型 返回JSON字符串
for (int index = 0; index < parameters.length; index++) {
Parameter parameter = parameters[index];
if (!parameter.isAnnotationPresent(ActionParamter.class)) {
throw new Exception("第" + (index+1) + "个参数没有注解!");
}
ActionParamter ap = parameter.getAnnotation(ActionParamter.class);
String paraName = ap.value();
Type paraType = parameter.getParameterizedType();
res[index] = am.getValue(paraName, paraType);
}
return res;
}
既然 有注解的类,方法,以及对应参数都已经找,我们就开始利用反射机制进行执行:
public String doRequest(String action, String para) throws Exception {
ActionBeanDefinition abd = ActionBeanFactory.getActionBean(action);
if (abd == null) {
throw new Exception("action:[" + action + "]未定义!");
}
Method method = abd.getMethod();
Object result = method.invoke(abd.getObject(), getParaValues(method, para));
return gson.toJson(result);
}
public void doResponse(String action, String para) throws Exception {
ActionBeanDefinition abd = ActionBeanFactory.getActionBean(action);
if (abd == null) {
throw new Exception("action:[" + action + "]未定义!");
}
Method method = abd.getMethod();
if (method.getParameters().length > 1) {
throw new Exception("方法[" + method.getName() + "]参数多于1个!");
}
if (para.equals("null")) {
method.invoke(abd.getObject());
return;
}
Object[] paraValues = new Object[1];
Parameter parameter = method.getParameters()[0];
// 因为返回值 最多只有一个
paraValues[0] = gson.fromJson(para, parameter.getParameterizedType());
method.invoke(abd.getObject(), paraValues);
}
好了,我们现在来总体的串一下在点击登录按钮时发生了什么:
客户端:
client.sendRequest("login", new ArgumentMaker()
.addArg("id", id)
.addArg("password", password)
.toString());
客户端的conversation 里面:
sendRequest(String action, String para) { // 向服务器发送“请求” send(new NetMessage() .setCommand(ENetCommand.REQUEST) .setAction(action) .setPara(para)); }
serverConversation里面:
public void dealRequest(NetMessage message) {
String action = message.getAction();
int index = action.indexOf(":");
String requestAction = action.substring(0, index);
String responseAction = action.substring(index + 1);
String para = message.getPara();
// 根据action和APP开发者所配置的,action与相关方法之间的映射关系,定位(反射)相关方法,并反射 执行之。
// 第一步:根据action,映射出类和相关方法;
String result = null;
try {
result = actionExecuter.doRequest(requestAction, para);
} catch (Exception e) {
e.printStackTrace();
}
// 第二步:将String类型的para,转换成该方法执行时所需要的实参;
// 第三步:反射执行这个方法,并取得该方法的返回值;
// 第四步:将这个方法的返回值,转换成字符串,并回传给客户端的会话层。
send(new NetMessage()
.setCommand(ENetCommand.RESPONSE)
.setAction(responseAction)
.setPara(result));
}
同时 反射机制调用 对用方法,方法名生成原则:给命令名前加do 所以这里会调用到上面ActionExcuter里面的doRequest
protected void dealNetMessage(NetMessage message) {
DealNetMessage.dealCommand(this, message);
}