SpringBoot强化篇(六)--lombok+热部署+健康检查+异常处理+响应标准设计

lombok

lombok简介

概述

Lombok是一个第三的Java库,它会自动插入编辑器和构建工具中,Lombok提供了一组有用的注释,用来告诉编译过程中的编译工具,在源代码编译成字节码的过程中,在字节码中添加一些量样板代码。

常用注解分析

  • @Setter 用于为描述的类生成setter方法,不包含final修饰属性。
  • @Getter 用于为描述的类生成getter方法。
  • @ToString 用于为描述的类添加toString方法。
  • @EqualsAndHashCode 用于为描述的类,生成hashCode和equals方法。
  • @NoArgsConstructor 用于为描述的类生成无参的构造方法。
  • @AllArgsConstructor 用于为描述的类生成包含类中所有字段的构造方法。
  • @Data用于为描述的类生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。
  • @Slf4J 用于为描述的类添加一个日志属性对象。

lombok安装

idea中的安装配置

第一步:打开idea的设置窗口,找到plugins菜单,搜索lombok进行安装,如图所示:

第二步:启动注解处理,如图所示:

第三步:重启idea(可选,有的idea版本需要)。

sts中的安装配置

自己百度尝试。

lombok在maven项目中应用

第一步:添加lombok依赖。


   org.projectlombok
   lombok
   annotationProcessor

第二步:在类上应用lombok注解。

@Data 
@NoArgsConstructor 
@AllArgsConstructor 
public class Goods {
    private Long id;
    private String name;
    private String remark;
    private Date createdTime;
}

第三步:编写单元测试类检测Lombok注解应用

@Slf4j
@SpringBootTest
public class GoodsTests{
     @Test
     void testGoods(){
        Goods g=new Goods();
        g.setId(100L);
        g.setName("Lombok");
        log.info("id的值为{}",g.getId());
        log.info("name的值为{}",g.getName());
     }
}

热部署

热部署简介

Spring Boot 开发者为Spring Boot项目中提供了一个热部署(spring-boot-devtools)模块,支持项目的热部署(修改了某些资源以后无需重启服务),以提高开发效率.其底层其实是借助了两个类加载器做了具体实现,一个类加载器加载不变class,一个类加载器加载可能变化类,以提供类的热部署性能.

热部署环境初始化

本次热部署的演示在IDEA开发中进行实现,其它工具可以自己通过搜索引擎进行学习。

IDEA 启动自动编译,如图所示:

IDEA工具中启动注册窗口(按ctrl+shift+alt+/),如图所示:

选择编译构建配置,如图所示:

热部署在项目中应用

在需要热部署的项目或module中添加如下依赖:


   org.springframework.boot
   spring-boot-devtools
   runtime

依赖下载以后,可重启reload项目,然后当我们修改了src/main/java目录下的java文件或修改了src/main/resources目录下的配置文件时,默认都会重启你的web服务器,但是修改了测试类或html文件不会自动重启和部署。

健康检查

健康监控简述

Spring Boot 中actuator模块提供了健康检查,审计、指标收集,HTTP跟踪等功能,可以帮助我们更好的管理和跟踪springboot项目。

健康监控配置实现

在需要使用健康监控的项目或module中,添加如下依赖:


    org.springframework.boot
    spring-boot-starter-actuator

添加完依赖以后,reload项目或module。

健康监控启动分析

启动项目,在浏览器中输入如下地址:(SpringBoot默认打开的监控选项有限)

http://localhost/actuator

其访问结果,如图所示:

还可以在actuator列出的选中中进行点击,例如访问health

http://localhost/actuator/health

其呈现结果,如图所示(其中up状态表示正常):

假如希望查看更多actuator选项,可以在spring boot中配置文件

application.properties中添加如下语句:

management.endpoints.web.exposure.include=*

然后,重启服务器,基于访问http://localhost/actuator地址...)

异常处理

异常处理分析

概述

Java项目中处理异常方式无非两种,要么执行trycatch操作,要么执行throw操作(抛给其它对象处理),无论采用哪种方式,其目的是让我们的系统对异常要有反馈。但现在的问题是我们如何让这种反馈代码的编写即简单又直观、友好。

处理规范

我们在处理异常的过程中通常要遵循一定的设计规范,例如:

  • 捕获异常时与抛出的异常必须完全匹配,或者捕获异常是抛出异常的父类类型。
  • 避免直接抛出RuntimeException,更不允许抛出Exception或者Throwable,应使用有业务含义的自定义异常(例如ServiceException)。
  • 捕获异常后必须进行处理(例如记录日志)。如果不想处理它,需要将异常抛给它的调用者。
  • 最外层的逻辑必须处理异常,将其转化成用户可以理解的内容。
  • 避免出现重复的代码(Don’t Repeat Yourself),即DAY原则。

SpringBoot 工程下的异常处理

准备工作

第一步:创建项目或module,并添加web依赖,代码如下:


    org.springframework.boot
    spring-boot-starter-web

第二步:修改项目访问端口为80,例如

server.port=80

第三步:定义Controller类,代码如下:

package com.cy.pj.arithmetic.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class ArithmeticController {

  @RequestMapping("doCompute/{n1}/{n2}")
  @ResponseBody
  public String doCompute(@PathVariable  Integer n1, 
  @PathVariable Integer n2){
          Integer result=n1/n2;
          return "Result is "+result;
  }
}

第四步启动项目进行访问测试

在浏览器地址栏输入http://localhost/doCompute/10/2,检测输出结果。

Result is 5

默认异常处理

在浏览器地址栏输入http://localhost/doCompute/10/0,检测输出结果。

对于这样的默认异常处理(spring boot提供),用户体验不太友好,为了呈现更加友好的异常信息,我们通常要对异常进行自定义处理。

自己try异常处理

在控制层方法中,我们可以进行try catch处理,例如:

 @RequestMapping("doCompute/{n1}/{n2}")
  @ResponseBody
  public String doCompute(@PathVariable  Integer n1, 
  @PathVariable Integer n2){
          try{
          Integer result=n1/n2;
          return "Result is "+result;
          }catch(ArithmeticException e){
          return "exception is "+e.getMessage();
          }
  } 

一个Controller类中通常会有多个方法,这样多个方法中都写try语句进行异常处理会带来大量重复代码的编写,不易维护。

Controller内部定义异常处理方法

在Controller类中添加异常处理方法,代码如下:

@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public String doHandleArithmeticException(ArithmeticException e){
    e.printStackTrace();
    return "计算过程中出现了异常,异常信息为"+e.getMessage();
}

@ExceptionHandler注解描述的方法为异常处理方法(注解中的异常类型为可处理的异常类型),假如Controller类中的逻辑方法中出现异常后没有处理异常,则会查找Controller类中有没有定义异常处理方法,假如定义了,且可以处理抛出的异常类型,则由异常处理方法处理异常。

控制层中的全局异常处理类及方法定义

当项目由多个控制层类中有多个共性异常的处理方法定义时,我们可以将这些方法提取到公共的父类对象中,但是这种方式是一种强耦合的实现,不利于代码的维护。我们还可以借助spring框架中web模块定义的全局异常处理规范进行实现,例如定义全局异常处理类,代码如下:

package com.cy.pj.common.web;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ArithmeticException.class)
    public String doHandleArithmeticException(ArithmeticException e){
        e.printStackTrace();
        return  "计算过程中出现了异常,异常信息为"+e.getMessage();
    }
} 

其中,@RestControllerAdvice 注解描述的类为全局异常处理类,当控制层方法中的异常没有自己捕获,也没有定义其内部的异常处理方法,底层默认会查找全局异常处理类,调用对应的异常处理方法进行异常处理。如图所示:

响应标准设计

响应标准设计

在响应数据标准化设计时,首先要对响应数据进行分析,哪些数据要响应到客户端,对这些数据进行怎样的状态设计等。假如现在响应的业务数据包含三部分:状态,消息,具体数据。我们可以这样设计,例如:

package com.cy.pj.common.pojo;

/**
 * 基于此对象封装服务端响应到客户端的数据
 */
public class ResponseResult {
    /**响应状态码(有的人用code)*/
    private Integer state=1;//1表示ok,0表示error,.....
    /**状态码对应的信息*/
    private String message="ok";
    /**正确的响应数据*/
    private Object data;

    public ResponseResult(){}

    public ResponseResult(String message){//new ResponseResult("delete ok"),
        this.message=message;
    }
    public ResponseResult(Object data){//new ResponseResult(list);
        this.data=data;
    }
    public ResponseResult(Throwable e){//new ResponseResult(e);
        this.state=0;
        this.message=e.getMessage();
    }

    public Integer getState() {
        return state;
    }

    public void setState(Integer state) {
        this.state = state;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

响应数据的封装

在Controller类的逻辑方法中进行正常的响应数据封装,例如:

package com.cy.pj.module.controller;

import com.cy.pj.common.pojo.ResponseResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ArithmeticController {

      @RequestMapping("/doCompute/{n1}/{n2}")
      public ResponseResult doCompute(@PathVariable  Integer n1, @PathVariable Integer n2){
          Integer result=n1/n2;
          ResponseResult r=new ResponseResult("计算结果:"+result);
          r.setData(result);
          return r;
      }
}

在全局异常处理对象中进行异常响应数据的封装,例如:

package com.cy.pj.common.web;

import com.cy.pj.common.pojo.ResponseResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@RestControllerAdvice
public class GlobalExceptionHandler {
      private static final Logger log= LoggerFactory.getLogger(GlobalExceptionHandler.class);//2
      @ExceptionHandler(ArithmeticException.class)
      public ResponseResult doHandleArithmeticException(ArithmeticException e){
          e.printStackTrace();
          log.info("exception {}",e.getMessage());
          return new ResponseResult(e);//封装异常结果
      }
}

你可能感兴趣的