基于注解搭建WebService框架的反射使用

此次搭建的WebApi平台思路如下;

1.对拦截到的Action请求统一构建context对象,用于组装请求所携带的参数。

2.构建统一的响应对象reponse

3.调用checkSecurity检查模块检查请求的安全性和可用性,如有错误,则退出处理并写入response错误信息

4.对通过check的context对象进行反射调用,并根据相应结果组装response对象

5.response对象通过Marshaller模块返回指定的响应报文

注:其中的3和5过程都需要提供可继承的接口方便用户自定义策略

在编码过程中遇到的较大难题主要是反射调用这一块,也是我觉得有价值的地方,特记录如下。

先复习一下spring.beans包的主要内容


spring beans

总结如下:

1.Loading XML bean definitions

2.实例化BeanFactoryPostProcessor,调用工厂方法

3.实例化BeanPostProcessor构造器

4.实例化InstantiationAwareBeanPostProcessorAdapter

5.调用postProcessBeforeInstantiation方法,构造目标bean实例。再调用postProcessPropertyValues方法,为目标bean注入属性

6.BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改!

7.【init-method】调用的init-method属性指定的初始化方法

8.BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改!

9.InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法

10.容器初始化成功


其中可以看出,beanPostProcessor接口对spring接管的每个实体类都会调用postProcessBeforeInitialization,postProcessAfterInitialization这两个方法。

为了实现让spring反射知道调用的是哪个方法,我需要在缓存中记住每个带有

@BopServiceMethod(method = "sayHelloTest", args = {"webctx","name","data"}, message = "哼哈嘿")

注解的service方法,并读取其中指定的method,args,message信息进行缓存。

为此,我们只要实现BeanPostProcessor接口,在postProcessAfterInitialization中判断①该方法所在的类是否是service ②该类中的方法是否带有@BopServoceMethod注解就行了

AnnotationUtils.findAnnotation(proClass, org.springframework.stereotype.Service.class);

使用findAnnotation方法判断一个类上是否有@service注解。proClass表示目标类的class

Method[] methods = ReflectionUtils.getAllDeclaredMethods(proClass);

若是service类,则使用getAllDeclaredMethods方法获得该类的所有方法组成数组

BopServiceMethod bopService = AnnotationUtils.findAnnotation(method, BopServiceMethod.class);

遍历所有方法,获得注解类,当注解类bopService不为空时,即说明该方法上标注了该注解。此时,再用过method对象和bopService对象获取需要的信息就易如反掌了。


在Spring中,凡是标注了@Transactional(事务)注解的方法都会使用spring事务进行处理,spring框架使用过jdkDynamicProxy动态代理进行处理的。或者是自己篇日志Aop动态代理的的方法,在通过BeanPostProcessor接口时获取的bean对象统统都是代理对象,这时直接使用bean.class作为参数拿到的Service类一定是Null

于是在此做如下处理:

Class proClass;

if (AopUtils.isJdkDynamicProxy(bean)) {

proClass = AopUtils.getTargetClass(bean);

} else {

proClass = bean.getClass();

}

该段代码的含义是,通过AopUtils工具判断是何种动态代理方式(这里我只判断是否是jdk动态代理),如果是,则使用getTargetClass获取其代理目标类的class。若不是,则直接获得bean.class

除去使用这种方式以外,还可以通过以下这种方式获得代理类的class

DirectFieldAccessor ads = new DirectFieldAccessor(Proxy.getInvocationHandler(bean));

AdvisedSupport advised = (AdvisedSupport) ads.getPropertyValue("advised");

clazz = advised.getTargetClass();

获取invocationHandler对象,再构建DirectFieldAccessor实例,通过属性方法获得advised的实例,再从advised对象中获取目标类的class;


接下来讲一讲具体反射的使用思路

首先是缓存中拿到我们需要的各种属性

类名、方法名和参数类型数组

Method mh = ReflectionUtils.findMethod(SpringContextUtil.getBean(className).getClass(), methodName, argsType);

使用ReflectionUtils.findMethod获取反射的方法对象

然后,就是重点【参数转换】

Object[] param = new Object[mh.getParameterCount()];

Class[] mhTypes = mh.getParameterTypes();

String[] argsName = (String[]) m.get("argsName");

① 首先,要通过mh.getParameterCount()取得参数的数量,并以此新建参数数组object[]

②通过mh.getParameterTypes()方法获得所有的参数类型数组,class<?>[]

③从缓存中取出我们之前缓存的参数名数组String[]

④提供参数转换策略。遍历对象进行替换!

由于我使用的context对象将所有参数都封装成了json字符串,所以提供的转换策略里需要JsonUtil工具类去转换成各种需要的参数对象。

最后,反射调用:

Object result = ReflectionUtils.invokeMethod(mh, SpringContextUtil.getBean(className), param);

完事。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容