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);
	}


全部评论

相关推荐

过往烟沉:我说什么来着,java就业面就是广!
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务