反射?切面?怎样对公共参数及行为进行封装
现在都是微服务化访问,某系统访问另一系统时,总有一些公用参数需要处理,另外还需要对访问情况进行日志打印。
调用的服务是dubbo服务,如何封装这一些公共参数而不是每次调用方法时都做反复的事呢?
三个方法:
1. 写一个公共方法,在调用rpc方法前和方法后,都进行调用;
简单直接且易读,且想加就加更灵活。不好处就是每个地方都要重复写这两段公用代码,不简洁。
2. 使用反射方法,进行调用dubbo方法,在调用前调用后,都进行参数组装,并将日志打印好。
好处是每次只需调用一个反射封装方法,就能完成所有工作,简单实用。坏处是方法被反射调用后,不直观,无法使用ide的语法检查快速发现潜在问题。
3. 使用切面进行设值处理。
好处是代码无侵入,简洁明了。坏处是新来的同学不易理解一些运行原理,不能很好利用切面辅助,另外,切面规则需要保持一致,否则无法实现处理。
来几个实现的例子吧!
使用公共方法:
// 公用封装参数方法,四处调用,当然这里是不完整的封装,可能还需要更复杂的代码侵入 public static void wrapCommonField(Object param) { ThreadlocalVar session = ThreadlocalVar.getVar(); if (null != param && (param instanceof BaseDTO)) { BaseDTO basePara = (BaseDTO) param; if (null != session) { basePara.setIp(session.getIp()); if(session.getUserId() != null) { basePara.setUserId(session.getUserId()); } } } // ... } // 调用,在调用service方法时,先鲁一段该调用代码 public static void main(String[] args) { RpcServiceA serviceA = new RpcServiceA(); Object param = ...; wrapCommonField(param); // ... }
使用反射:
// 公用反射方法 public static <T> T callMethod(Object service, String mName, Object param) { ThreadlocalVar session = ThreadlocalVar.getVar(); if (null != param && (param instanceof BaseDTO)) { BaseDTO basePara = (BaseDTO) param; if (null != session) { basePara.setIp(session.getIp()); if(session.getUserId() != null) { basePara.setUserId(session.getUserId()); } } } Class<?> rpcServiceClass = service.getClass(); logger.info("call method:{},param:{}", mName, param); try { Method method = rpcServiceClass.getMethod(mName, new Class[] { param.getClass() }); ResponseResult<T> re = (ResponseResult<T>) method.invoke(rpcService, new Object[] { param }); logger.info("result:{}", re); if (null == re || !"1111".equals(re.getCode())) { throw new RuntimeException(re.getCode(), re.getMsg()); } return re.getData(); } catch (NoSuchMethodException | InvocationTargetException e) { logger.error("exception:{}", e); throw e; } catch (SecurityException | IllegalAccessException | IllegalArgumentException e) { logger.error("exception:{}", e); throw e; } } // 调用 public static void main(String[] args) { RpcServiceA serviceA = new RpcServiceA(); Object param = ...; callMethod(serviceA, "giveMeFive", param); // ... }
使用切面:
// 完整切面类,独立 @Order(1) @Component @Aspect public class SignLoginAop { private Logger logger = LoggerFactory.getLogger(getClass()); public static final String CALLAPI_POINT = "execution(* com.xx.api.web.d.*.*(..))"; @Around(CALLAPI_POINT) public Object validSign(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException, KydException { Object retVal = null; Object[] args = pjp.getArgs(); Object param = (null != args && args.length > 0) ? args[0] : null; if (null != param && (param instanceof BaseDTO)) { BaseDTO basePara = (BaseDTO) param; ThreadlocalVar session = ThreadlocalVar.getSession(); BaseDTO basePara = (BaseDTO) param; if (null != session) { basePara.setIp(session.getIp()); if(session.getUserId() != null) { basePara.setUserId(session.getUserId()); } } } Signature signature = pjp.getSignature(); try { logger.info("call method {}, param:{}", signature, args); retVal = pjp.proceed(args); logger.info("end method {}, retVal:{}", signature, retVal); } catch (Exception e) { logger.error("发生了错误:", e); throw e; } //... } } // 使用,独立写业务
性能对比!额,就不去收集对比数据了。第一个自然最快。第二、三个不相伯仲!
封装是为了代码更简洁!哟豁。
不要害怕今日的苦,你要相信明天,更苦!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?