基于注解搭建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);

完事。

你可能感兴趣的:(基于注解搭建WebService框架的反射使用)