十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

如何搭建漂亮的 SpringBoot 脚手架?

如何搭建漂亮的 SpringBoot 脚手架? 一个 Boot 项目启动类能跑起来不叫脚手架。真正让人觉得难受的是到了项目写了长达两个月之后的阶段, 里塞的业务存在着这样的状况, 到处都要进行调用, 异常返回呈现出手五花八门的态势, 配置文件在环境区分方面存在问题, 去查询一次在线上的请求, 还必须得从几万行的日志当中去猜测特定信息。这种项目目录看着挺满我一般不太敢接着写。具备长期使用条件的脚手架, 起码得预先锁定目录边界, 还得明确好了 统一返回 这一事项, 异常处理环节也得事先确定, 请求追踪方面同样要提前搞定, 环境配置一块也要一并固定下来。业务代码倒是能够后续补上, 不过这好几块内容可别等出现问题了才去修改。目录不用拆得特别玄学我常用下面这种com.dong.order ├── OrderApplication.java ├── common │ ├── ApiResult.java │ ├── BizException.java │ └── GlobalExceptionHandler.java ├── config │ └── WebConfig.java ├── infrastructure │ ├── persistence │ └── client └── order ├── controller ├── application ├── domain └── repository仅负责收取参数以及返回相应结果, 对于业务详细流程予以负责处理, 并留存置入业务对象, 而数据库以及外部接口则一并统一投入并放置到。才刚开始就去拆解十几个 Maven 模块, 这是不合适的。业务所涉及的表数量还不多, 然而模块却已经嵌套了多层, 多达四层。像这样的架构状况, 除了能使得跳转的路径变得更长之外, 暂时看不到它还有其他任何好处, 实在是没什么作用。接口返回也别让开发人员自由发挥。public record ApiResult( int code, String message, T data, String requestId ) { publicstaticApiResultok(T data){ returnnew ApiResult( 0, success, data, org.slf4j.MDC.get(requestId) ); } publicstatic ApiResultfail(int code, String message){ returnnew ApiResult( code, message, , org.slf4j.MDC.get(requestId) ); } }这儿我会将其直接放置于响应里头。倘若线上用户拿着一条报错前来找人, 那么在这种情况下, 不用再去询问他是在几点进行操作的, 也不用去问他点了哪个按钮, 此时只要复制这个值便能够去查日志了。请求进入系统时生成编号Component publicclassRequestIdFilterextendsOncePerRequestFilter{ privatestaticfinal String HEADER X-Request-Id; Override protectedvoiddoFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain chain )throws ServletException, IOException { String requestId request.getHeader(HEADER); if (requestId || requestId.isBlank) { requestId UUID.randomUUID.toString.replace(-, ); } try { MDC.put(requestId, requestId); response.setHeader(HEADER, requestId); chain.doFilter(request, response); } finally { MDC.remove(requestId); } } }里头的清理是绝对不可以省去的, 线程存在复用情况, 要是不清空 MDC 的话, 接下来的请求极有可能携带着前一次的编号, 如此一来日志就会变得越查越混乱。即便是出现异常情况, 也需要进行集中的收口处理, 在代码里的各个地方都写上try-catch语句, 到最后往往会出现这样的状况, 有的情况是返回了200, 有一些情况则返回的是500, 另外还有一些是把数据库所出现的异常原封不动地抛给前端。RestControllerAdvice publicclassGlobalExceptionHandler{ privatestaticfinal Logger log LoggerFactory.getLogger(GlobalExceptionHandler.class); ExceptionHandler(BizException.class) publicResponseEntity handleBiz(BizExceptionex) { return ResponseEntity.badRequest .body(ApiResult.fail(ex.getCode, ex.getMessage)); } ExceptionHandler(Exception.class) publicResponseEntity handleUnknown(Exceptionex) { log.error(unhandled request error, ex); return ResponseEntity.internalServerError .body(ApiResult.fail(50000, 系统处理失败)); } }对于业务异常, 可要明确告知那调用方, 而系统异常, 仅仅记录日志既可, 千万别把 SQL, 以及表名, 还有服务器路径一同返回出去。配置文件我一般至少拆成三份# application.yml spring: application: name:order-service profiles: active:${APP_ENV:local} server: shutdown:graceful management: endpoints: web: exposure: include:health,info,metrics# application-local.yml spring: datasource: url:jdbc:mysql://127.0.0.1:3306/order_db username:root password:root提交到 Git 的别是生产环境的密码, 要交给环境变量或者配置中心那边。在配置文件里写上一个密码为“临时密码”, 过上半年, 它大概率依旧会是生产密码。连接数据库的连接池, 线程所使用的线程池, 还有HTTP客户端, 都不要在隐藏着默认值的情况下运行。搭建的脚手架不需要预先设定一个看上去很厉害的数字, 但是一定要将关键的参数暴露出来, 使得部署环境能够进行调整。最后, 再额外增添两个限制条件, 其一为禁止字段注入这一行为, 另一个条件是倡导统一采用构造器来予以注入。并且, 明确规定不允许进行直接调用。Service publicclassCreateOrderService{ privatefinal OrderRepository orderRepository; publicCreateOrderService(OrderRepository orderRepository){ this.orderRepository orderRepository; } Transactional public Long create(CreateOrderCommand command){ Order order Order.create( command.userId, command.amount ); orderRepository.save(order); return order.getId; } }一个用于建筑施工的脚手架是否具备美观性, 并非着眼于其所使用组件数量的多少, 而是当有新的人员添加进一个接口之际, 是否能够以自然的方式将代码放置到恰当的位置当在线环境出现错误信息之时, 是否能够凭借某一条途径把调用链发掘出来当业务规模进行扩展之后, 是否能够实现拆分模块操作而非轻易推倒整体并进行重新编写。定这些住了的地方, 继而之后的、Redis, 随之MQ俱都仅仅只系往里面去装些东西。然而骨架却并未立住, 组件装得越多, 项目塌得越快。
返回列表