【Java】用注解实现分发器
在C/S中,客户端会向服务器发出各种请求,而服务器就要根据请求做出对应的响应。
实际上就是客户机上执行某一个方法,将方法返回值,通过字节流的方式传输给服务器,服务器找到该请求对应的响应方法,并执行,将结果再次通过字节流的方式传输给客户机!
下面搭建一个简单的Request和Response分发器:
类标识的注解,只有带有该标识,才进行之后方法的扫描,否则不进行:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Service {
}
方法的注解, 必须对注解中的action赋值,往后我们是要将action的值作为map中的键:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Actioner {
String action();
}
方法参数的注解,同样要对其name赋值,为了以后能够找到对应的参数,完成赋值:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface AParameter {
String name();
}
我们需要将方法抽象成一个类,封装起来:
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.List; public class ActionDefination {
private Class<?> klass; // 该方法所对应的类
private Object object; // 执行该方法的对象
private Method method; // 该方法
private List<Parameter> paramerterList; // 该方法的所有参数 protected ActionDefination(Class<?> klass, Object object, Method method, List<Parameter> paramerterList) {
this.klass = klass;
this.object = object;
this.method = method;
this.paramerterList = paramerterList;
} protected Class<?> getKlass() {
return klass;
} protected Object getObject() {
return object;
} protected Method getMethod() {
return method;
} protected List<Parameter> getParamerterList() {
return paramerterList;
} }
所有准备工作都做好了,我们就需要通过包扫描的方式,找到带有Service 注解的类,然后找到其中带有Actioner 注解的方法,并且得到带有注解的所有参数,若其某一参数没有带注解,则应该异常处理!
扫描包下符合要求的所有内容,最后形成一张map
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; public class ActionFactory {
private static final Map<String, ActionDefination> actionDefinationMap = new HashMap<String, ActionDefination>(); // 单例模式
private ActionFactory() {
}
public static ActionFactory newInstance() {
return creatNewInstance.actionFactory;
} private static class creatNewInstance {
private static final ActionFactory actionFactory = new ActionFactory();
} // 通过类,扫描其所在包下的所有文件
public void scanAction(Class<?> klass) {
scanAction(klass.getPackage().getName());
} // 通过包名称,扫描其下所有文件
public void scanAction(String packageName) {
// 包扫描,在我的上一篇博客有该方法的实现
new PackageScanner() { @Override
public void dealClass(Class<?> klass) {
// 只处理带有Service注解的类
if (!klass.isAnnotationPresent(Service.class)) {
return;
}
try {
// 直接由反射机制产生一个对象,将其注入
Object object = klass.newInstance();
// 扫描改类下的所有方法
scanMethod(klass, object);
} catch (Exception e) {
e.printStackTrace();
}
}
}.scanPackage(packageName);
} // 通过对象,扫描其所有方法
public void scanAction(Object object) {
try {
scanMethod(object.getClass(), object);
} catch (Exception e) {
e.printStackTrace();
}
} private void scanMethod(Class<?> klass, Object object) throws Exception {
// 得到所有方法
Method[] methods = klass.getDeclaredMethods(); // 遍历所有方法,找到带有Actioner注解的方法,并得到action的值
for (Method method : methods) {
if (!method.isAnnotationPresent(Actioner.class)) {
continue;
}
Actioner actioner = method.getAnnotation(Actioner.class);
String action = actioner.action(); // 判断action是否已经定义
if (actionDefinationMap.get(action) != null) {
throw new ActionHasDefineException("方法" + action + "已定义!");
} // 得到所有参数,并判断参数是否满足要求
Parameter[] parameters = method.getParameters();
List<Parameter> parameterList = new ArrayList<Parameter>();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
if (!parameters[i].isAnnotationPresent(AParameter.class)) {
throw new MethodParameterNotDefineException("第" + (i+1) + "个参数未定义!");
} parameterList.add(parameter);
}
// 将得到的结果添加到map中
addActionDefination(action, klass, object, method, parameterList);
}
} private void addActionDefination(String action, Class<?> klass, Object object, Method method, List<Parameter> parameterList) {
ActionDefination actionDefination = new ActionDefination(klass, object, method, parameterList);
actionDefinationMap.put(action, actionDefination);
} protected ActionDefination getActionDefination(String action) {
return actionDefinationMap.get(action);
} }
上述的ActionFactory可以帮助我们扫描到包下所有符合要求的方法,接下来就是通过传递参数执行这些方法。
要注意,这套工具的出发点是搭载在网络上,所以传递的参数就只能是字符串或者字节流的形式,所以,我们应该对传递的参数进行处理,将其生成能供我们识别的形式。
这里我们将参数转换为字符串的形式,我会用到gson,方便我们将对象转换为gson字符串:
import java.util.HashMap;
import java.util.Map; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; public class ArgumentMaker {
// 注解AParameter中name的值 + 参数对象转换成的gson字符串所形成的map
private Map<String, String> argumentMap;
private Gson gson; public ArgumentMaker() {
gson = new GsonBuilder().create();
argumentMap = new HashMap<String, String>();
} // 其name就是注解AParameter中name的值,value就是参数的具体值
public ArgumentMaker add(String name, Object value) {
// 通过gson将参数对象转换为gson字符串
argumentMap.put(name, gson.toJson(value));
return this;
} // 将得到的name + 参数对象转换成的gson字符串map再次转换成gson字符串,以便于进行传输
public String toOgnl() {
if (argumentMap.isEmpty()) {
return null;
} return gson.toJson(argumentMap);
} }
接下来就是处理具体的action
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map; import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken; public class Addition {
private static final Gson gson;
private static final Type type; static {
gson = new GsonBuilder().create();
// 可以得到带有泛型的map类型
type = new TypeToken<Map<String, String>>(){}.getType();
} public String doRequest(String action, String parameter) throws Exception {
ActionDefination ad = ActionFactory.newInstance().getActionDefination(action); if (ad == null) {
throw new ActionNotDefineException("方法" + action + "未定义!");
} Object object = ad.getObject();
Method method = ad.getMethod(); Object[] parameters = getParameterArr(parameter, ad.getParamerterList());
Object result = method.invoke(object, parameters); return gson.toJson(result);
} private Object[] getParameterArr(String parameterString, List<Parameter> parameterList) {
Object[] results = new Object[parameterList.size()];
// 将字符串形式的参数,转换成map
Map<String, String> parameterStringMap = gson.fromJson(parameterString, type); int index = 0;
for (Parameter parameter : parameterList) {
// 得到参数的注解AParameter中name的值
String key = parameter.getAnnotation(AParameter.class).name(); // 以name的值为键,找到参数map中value,再通过gson将其从字符串转换成具体的对象
Object value = gson.fromJson(parameterStringMap.get(key),
// 得到参数的具体类型
parameter.getParameterizedType()); results[index++] = value;
} return results;
}
演示如何使用
@Service
public class Demo { @Actioner(action="one")
public void fun() {
System.out.println("执行无参的fun方法");
} @Actioner(action="two")
public void fun(@AParameter(name="1")int parameter) {
System.out.println("执行单参的fun方法: parameter = " + parameter);
} @Actioner(action="three")
public void fun(@AParameter(name="1")int one,
@AParameter(name="2")String two,
@AParameter(name="3")boolean three) {
System.out.println("执行三参的fun方法: one = " + one + " two = " + two + " three = " + three);
} private static class Student {
private String name;
private int age;
private boolean sex; private Student(String name, int age, boolean sex) {
this.name = name;
this.age = age;
this.sex =sex;
} @Override
public String toString() {
return "name = " + name + ", age = " + age + ", sex = " + (sex ? "男" : "女");
}
} @Actioner(action="four")
public void fun(@AParameter(name="1")Student student) {
System.out.println("执行复杂类型参数的fun方法 :" + student);
} public static void main(String[] args) throws Exception {
// 扫描包,这里直接扫描Demo所在的包
ActionFactory.newInstance().scanAction(Demo.class); Addition addition = new Addition(); addition.doRequest("one", null); addition.doRequest("two", new ArgumentMaker()
.add("1", 3)
.toOgnl()); addition.doRequest("three",new ArgumentMaker()
.add("3", true)
.add("1", 3)
.add("2", "这是第二个参数")
.toOgnl()); Student student = new Student("小明", 15, true);
addition.doRequest("four", new ArgumentMaker()
.add("1", student)
.toOgnl());
} }
运行结果

【Java】用注解实现分发器的更多相关文章
- java自定义注解知识实例及SSH框架下,拦截器中无法获得java注解属性值的问题
一.java自定义注解相关知识 注解这东西是java语言本身就带有的功能特点,于struts,hibernate,spring这三个框架无关.使用得当特别方便.基于注解的xml文件配置方式也受到人们的 ...
- java自定义注解实现前后台参数校验
2016.07.26 qq:992591601,欢迎交流 首先介绍些基本概念: Annotations(also known as metadata)provide a formalized way ...
- 黑马程序员_高新技术之javaBean,注解,类加载器
----------- android培训.java培训.java学习型技术博客.期待与您交流! ---------- 第一部分 javaBean 一,由内省引出javaBean 1,内省: 内省对应 ...
- 左右JAVA示例代码事件分发和监督机制来实现-绝对原创有用
文章标题:左右JAVA示例代码事件分发和监督机制来实现 文章地址: http://blog.csdn.net/5iasp/article/details/37054171 作者: javaboy201 ...
- JAVA配置&注解方式搭建简单的SpringMVC前后台交互系统
前面两篇文章介绍了 基于XML方式搭建SpringMVC前后台交互系统的方法,博文链接如下: http://www.cnblogs.com/hunterCecil/p/8252060.html htt ...
- saltstack主机管理项目:计主机管理项目命令分发器(三)
一.开发目标命令格式如下: 二.目录结构 三.代码注解 01.salt.py 只是一个入口,没干什么事情 #!/usr/bin/env python # -*- coding:utf-8 -*- # ...
- [1] 注解(Annotation)-- 深入理解Java:注解(Annotation)基本概念
转载 http://www.cnblogs.com/peida/archive/2013/04/23/3036035.html 深入理解Java:注解(Annotation)基本概念 什么是注解(An ...
- Java自定义注解源码+原理解释(使用Java自定义注解校验bean传入参数合法性)
Java自定义注解源码+原理解释(使用Java自定义注解校验bean传入参数合法性) 前言:由于前段时间忙于写接口,在接口中需要做很多的参数校验,本着简洁.高效的原则,便写了这个小工具供自己使用(内容 ...
- java基础—注解annotation
一.认识注解 注解(Annotation)很重要,未来的开发模式都是基于注解的,JPA是基于注解的,Spring2.5以上都是基于注解的,Hibernate3.x以后也是基于注解的,现在的Struts ...
随机推荐
- Chrome书签添加到百度网盘
一:Chrome是最干净的浏览器了,但是无奈国内的环境导致书签不方便保存到云端,如果保存到本地那么就要经常自己备份之类的: 二:由以上的需求背景终于找到了可以将chrome打开的网页保存到百度网盘里[ ...
- Day03(黑客成长日记)
#猜数游戏 != 是不等于 # import random # secret = random.randint(,) # gwea = # tries = # : # guess = int(inpu ...
- docker安装镜像
CMD 容器启动命令 CMD指令用于为执行容器提供默认值.每个Dockerfile只有一个CMD命令,如果指定了多个CMD命令,那么只有最后一条会被执行,如果启动容器的时候指定了运行的命令,则会覆盖掉 ...
- xpath和lxml类库
1. xpath和lxml lxml是一款高性能的 Python HTML/XML 解析器,我们可以利用XPath,来快速的定位特定元素以及获取节点信息 2. 什么是xpath XPath (XML ...
- ESP32 windows开发环境的搭建(官方方法)
首先保证电脑中的已经下载了git客户端,没有的自行去https://git-scm.com/下载 STEP1: 获得编译工具链 Windows没有内置的“make”环境,所以安装工具链你将需要一个兼容 ...
- Linux 防火墙相关
1.SELinux 防火墙 1.1 查看SELinux状态: 1) /usr/sbin/sestatus -v ##如果SELinux status参数为enabled即为开启状态 bamb ...
- Python之旅Day2 元组 字符串 字典 集合
元组(tuple) 元组其实跟列表差不多,也是存一组数,与列表相比,元组一旦创建,便不能再修改,所以又叫只读列表. 语法: names = ("Wuchunwei","Y ...
- 【WPF】【UWP】借鉴 asp.net core 管道处理模型打造图片缓存控件 ImageEx
在 Web 开发中,img 标签用来呈现图片,而且一般来说,浏览器是会对这些图片进行缓存的. 比如访问百度,我们可以发现,图片.脚本这种都是从缓存(内存缓存/磁盘缓存)中加载的,而不是再去访问一次百度 ...
- nginx 502 bad gateway 问题处理集锦
一般看来, 这种情况可能是由于nginx默认的fastcgi进程响应的缓冲区太小造成的, 这将导致fastcgi进程被挂起, 如果你的fastcgi服务对这个挂起处理的不好, 那么最后就极有可能导致5 ...
- 背水一战 Windows 10 (85) - 文件系统: 获取文件夹和文件, 分组文件夹, 排序过滤文件夹和文件, 搜索文件
[源码下载] 背水一战 Windows 10 (85) - 文件系统: 获取文件夹和文件, 分组文件夹, 排序过滤文件夹和文件, 搜索文件 作者:webabcd 介绍背水一战 Windows 10 之 ...