人生很短,愿你能胸襟开阔,去容纳山海贫瘠,去挥霍青涩蹉跎,去寄托岁月巍峨,去尽情耗尽所有的爱恨枯竭。
场景描述
- 在进行接口调试的时候,一般都会
使用Postman进行接口调用调试
,即直接填上请求路径,请求参数,然后点击直接对后台发起请求,后台对代码进行一个调试,简单方便。 - 在有对外提供请求接口的情况下当然好用,但是,在
很多情况下方法并不会对外提供接口
,他只是给上游提供请求服务,并不需要在Controller层对外暴露接口。 - 就比如一个付款流程,客户进行一个订单支付操作,订单服务会调用库存服务进行一个扣库存的操作,假如这时候要调试一个库存扣减不正确的问题,于是我们
每次都要发起支付调用订单服务接口
,订单服务又请求库存服务在进行一个代码断点调试,如此反复,烦之又烦… - 你可以在库存服务开发一个Controller对外接口,单独对库存接口进行调试,
很棒
,至少不走那套支付流程和调用订单服务了,但也很蠢
,为了调试接口直接写个对外的方法,实在麻烦,如果忘记删除这段代码上了生产,可想而知有多危险! - 那该如何处理呢?这时候就可以用到
反射
了。
需求分析
- 首先我们
需要对外开放一个请求接口,这个接口具备通用性
,就是说直接调用该接口,经过反射之后可以达到后台调用不同方法的目的。 - 思考一下,我们后台要调用方法,首先要有调用方,以及要调用的方法,还有请求参数。所以,对于这个通用测试接口,我们需要有的参数是:
调用对象,对象调用的方法,方法请求参数封装类以及该类的参数。
实战分析
- 一般情况下,方法调用方都是Spring Bean对象,而获取Bean就可以使用ApplicationContext通过Bean的name获得,所以
第一个参数(方法调用方)只要传BeanName即可。
- 然后要获取该类某个方法的请求参数类,我们只能通过请求参数类全路径获取该类Class类型,所以
第二个参数(方法的请求参数类)需要传入类的全路径名。
- 第一步获得了对象就可以通过
对象.getClass()
的方式获取到该对象的类的Class类型,根据Class类型的getMethod(方法名称, 方法请求参数类型),就能够获取到要调用的Method,这里缺少第三个参数方法名称
,也需要前端传入。 - 第二步只是获取到请求参数的类类型,但是真正的请求参数却还没有放进该类里边,所以需要前端传入
第四个参数,即方法调用的实际参数。
- 最后一步就是
方法的调用
,第三步得到的Method调用invoke()方法进行执行。
代码示例
- 通用调试接口
@RequestMapping(value = "/system/operation", method = RequestMethod.POST)
public Object operation(@RequestBody DubboProxyRequest request) throws Exception{
// 注意只能在非生产环境调用哦
if(environmentHelper.isProductionEnvironment()){
return null;
}
// 获取调用的bean对象
Object invokedFacade = context.getBean(request.getFacadeName());
// 获取请求参数Class类
Class actualRequestClass = Class.forName(request.getActualRequestClassName());
// 获取要调用的方法
Method invokedMethod = invokedFacade.getClass().getMethod(request.getMethodName(), actualRequestClass);
// 封装请求参数到请求参数类中
Object actualRequest = JSON.parseObject(JSON.toJSONString(request.getActualRequestData()), actualRequestClass);
// 方法的执行
return invokedMethod.invoke(invokedFacade, actualRequest);
}
- 通用调试接口的请求参数 DubboProxyRequest
@Data
public class DubboProxyRequest extends BaseRequest {
/**
* BeanName
*/
@NotBlank
private String facadeName;
/**
* 要调用的方法
*/
@NotBlank
private String methodName;
/**
* 请求参数全路径名
*/
@NotBlank
private String actualRequestClassName;
/**
* 实际请求参数
*/
@NotBlank
private Map actualRequestData;
}
总结
- 通过上述通用接口,
根据传入参数的变化,可以达到调用后台不同方法的目的
,从而进行一个很方便的调试。 - 假如客户请求是一个很长的调用链,而要调试某个调用节点的时候,只需要针对该节点(即方法)传入其所需参数进行调试就行了,如此一想,
反射真是太强大和灵活了
!