对于这篇文章,如果有什么地方简述有误,还请多多指教!!!
//这是服务器端的方法
protected void dealNetMessage(NetMessage netMessage) {
ENetCommand command = netMessage.getCommand();
//客户端发送一个REQUEST命令,服务器端获得该命令,然后执行相应的方法。
if (command.equals(ENetCommand.REQUEST)) {
//action(动作)由request 以及 & 和response三部分组成,根据不同的动作服务器有不同的响应
String action = netMessage.getAction();
int colonIndex = action.indexOf('&');
//获得请求命令
String request = action.substring(0, colonIndex);
try {
//根据请求和参数,利用注解包扫描,并且利用反射机制,反射执行
String result = server.getActioner()
.executeRequest(request, netMessage.getPara());
send(new NetMessage()
.setCommand(ENetCommand.RESPONSE)
.setAction(action)
//把执行完的结果当成参数传给客户端
//这里的result是执行完动作对应的方法的结果的返回值
.setPara(result));
} catch (Exception e) {
e.printStackTrace();
}
return;
}
try {
CommandDispatcher.dispatcherCommand(this, netMessage);
} catch (Exception e) {
e.printStackTrace();
}
}
//根据Action对应出相应的方法
public class ActionDefinition {
//对应的方法在哪个类里
private Class<?> klass;
//该action对应的方法
private Method method;
//要反射执行一个方法必须要一个对象
private Object object;
//需要若干个参数,所以需要一个List来存储参数
private List<ActionParameter> parameterList;
ActionDefinition() {
parameterList = new ArrayList<>();
}
List<ActionParameter> getParameterList() {
return parameterList;
}
Class<?> getKlass() {
return klass;
}
void setKlass(Class<?> klass) {
this.klass = klass;
}
Method getMethod() {
return method;
}
/**
* 将包扫描时扫描到的方法设置给该类,并且将该方法的参数保存到List列表里面
* @param method
* @throws Exception
*/
void setMethod(Method method) throws Exception {
this.method = method;
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
//扫描该方法的注解
//注释Para是否在parameter上,是返回true,否返回false
if (!parameter.isAnnotationPresent(Para.class)) {
throw new Exception("方法[]的第" + (i+1) + "个参数无注解!");
}
Para para = parameter.getAnnotation(Para.class);
parameterList.add(new ActionParameter()
.setName(para.name())
.setType(parameter.getType()));
}
}
Object getObject() {
return object;
}
void setObject(Object object) {
this.object = object;
}
}
//解决action反射对应的方法的参数问题
public class ActionParameter {
//参数名称
private String name;
//参数类型
private Class<?> type;
ActionParameter() {
}
ActionParameter setName(String name) {
this.name = name;
return this;
}
String getName() {
return name;
}
ActionParameter setType(Class<?> type) {
this.type = type;
return this;
}
//将字符串json转换为对象
Object getValue(Gson gson, String json) {
return gson.fromJson(json, type);
}
}
//这里我们需要定义一个接口,给定一个方法
public interface IActionFactory {
String executeRequest(String action, String para) throws Exception;
}
//这和类需要实现上面那个接口,实现定义的方法
public class ActionFactory implements IActionFactory {
private static final Type type;
//map存放的是action所对应的方法名和ActionDefinition对象
private static final Map<String, ActionDefinition> actionMap;
private static final Gson gson;
//静态块是线程安全的
static {
actionMap = new HashMap<>();
//将Map的字符串转换为Map类型所需的类型
type = new TypeToken<Map<String, String>>() {}.getType();
gson = new GsonBuilder().create();
}
//根据包扫描得到想要找的类,然后处理该类
private static void processClass(Class<?> klass) {
try {
//根据类,实例化一个对象
Object object = klass.newInstance();
//得到该类里所有的方法,包括private修饰的方法
Method[] methods = klass.getDeclaredMethods();
for (Method method : methods) {
//如果该方法没有注解,就继续
if (!method.isAnnotationPresent(Actioner.class)) {
continue;
}
//根据注解得到相应的动作
Actioner actioner = method.getAnnotation(Actioner.class);
ActionDefinition ad = new ActionDefinition();
ad.setKlass(klass);
ad.setObject(object);
//保存方法和参数
ad.setMethod(method);
//以action动作为键,以ActionDefinition对象为值保存到Map里
actionMap.put(actioner.action(), ad);
}
} catch (Exception e) {
e.printStackTrace();
}
}
//包扫描方法
public static void scanActioner(String packageName) {
//实例化包扫描那个类
new PackageScanner() {
@Override
public void dealClass(Class<?> klass) {
//包扫描的时候只扫描带有注解的类,其余的类不扫描
if (klass.isInterface() || klass.isPrimitive()
|| klass.isArray() || klass.isAnnotation()
|| klass.isEnum()
|| !klass.isAnnotationPresent(MecAction.class)) {
return;
}
try {
//扫描到该类调用处理类方法
processClass(klass);
} catch (Exception e) {
e.printStackTrace();
}
}
//将要扫描的包当作实参传递过去
}.scannerPackage("com.mec");
}
/**
* 根据action的取值,映射出对应的method
*/
//这里的参数para是一个map,保存了用户的账号和密码,键为参数名,值为对象类型的字符串
@Override
public String executeRequest(String action, String para) throws Exception {
ActionDefinition ad = actionMap.get(action);
if (ad == null) {
throw new Exception("action:[" + action + "]没有配置!");
}
Object object = ad.getObject();
Method method = ad.getMethod();
//用反射机制提供的parameter方法只能得到参数的类型,不能得到参数的名称,因此这里需要对参数另做处理
List<ActionParameter> paras = ad.getParameterList();
//将Map字符串转换成对应的Map类型
Map<String, String> paraMap = gson.fromJson(para, type);
Object result = null;
//反射机制调用无参的方法
if (paras.size() <= 0) {
result = method.invoke(object);
} else {
Object[] values = new Object[paras.size()];
int i = 0;
for (ActionParameter parameter : paras) {
//根据参数名在map里找到字符串类型的参数对象类型的字符串,
//然后利用getValue方法将参数对象类型字符串类型转换为对象,得到该参数值
values[i] = parameter.getValue(gson,
paraMap.get(parameter.getName()));
}
result = method.invoke(object, values);
}
//将反射机制调用执行的方法后的结过通过字符串的形式返回
return gson.toJson(result);
}
}
//带有注解的类和方法,方便包扫描能找到
@MecAction
public class UserAction {
public UserAction() {
}
//给方法带注解
@Actioner(action="login")
public UserModel userLogin(
//给参数带注解
@Para(name="user") String user,
@Para(name="password") String password) {
UserModel stu = new UserModel();
return stu;
}
}