在公司日常小项目中,会遇到一些小需求,比如:检测服务是否正常运行。
当一个经验不是很足的项目经理,让你写一个接口,然后检测服务是否正常运行啦。
然后你说阿里云有自动检测的接口,还能发短信到你手机上,他说不用。
你说可以用一个定时任务定时给服务发送请求,使用cron可以实现,他也说不用。
然后就用springcloud内部提供的健康监测接口吧,如下说明:
首先说明:使用ping来检测的话,会不可靠的。因为Ping可能会出现错误返回,而用http请求会准确很多
public static void main(String[] args) {
String ipAddress = "Recently.com"; // 替换为实际的服务IP地址
try {
InetAddress inetAddress = InetAddress.getByName(ipAddress);
boolean isReachable = inetAddress.isReachable(5000); // 设置超时时间,单位为毫秒
if (isReachable) {
System.out.println("服务正常运行");
} else {
System.out.println("服务无法访问");
}
} catch (IOException e) {
System.out.println("发生异常: " + e.getMessage());
}
}
部分字段说明:
InetAddress.isReachable()
方法用于检测主机的可达性,而不仅仅是服务的可达性。它通过发送一个特殊的ICMP Echo请求(类似于Ping请求)来测试目标主机是否可达。
然而,请注意,isReachable()
方法在不同的操作系统和网络配置下可能会有不同的行为。在某些情况下,由于操作系统或网络设备的限制,该方法可能会返回错误的结果或被阻塞。
此外,isReachable()
方法的实现也依赖于底层操作系统的特性。在某些操作系统上,可能需要具有管理员权限才能正确使用该方法。
因此,对于监测服务是否正常运行的目的,使用基于Ping的可达性测试并不是一种可靠的方法。更好的方法是通过与服务进行实际的通信,例如发送HTTP请求并检查响应状态码。
使用HttpURLConnection
发送HTTP GET请求到指定的服务URL,并根据响应代码判断服务是否正常。
public class ServiceMonitor {
public static void main(String[] args) {
String serviceUrl = "https://Recently.com:9091/actuator/health";
Boolean flag =true;
while (flag){
try {
URL url = new URL(serviceUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000); // 设置连接超时时间,单位为毫秒
connection.setReadTimeout(5000); // 设置读取超时时间,单位为毫秒
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
System.out.println("服务正常运行");
} else {
System.out.println("服务无法访问,响应代码: " + responseCode);
// 获取错误信息
String errorResponse = getErrorResponse(connection);
System.out.println("错误响应内容: " + errorResponse);
flag = false;
}
Thread.sleep(5000);
} catch (IOException e) {
System.out.println("发生异常: " + e.getMessage());
flag=false;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
// 获取错误响应内容
private static String getErrorResponse(HttpURLConnection connection) throws IOException {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
return response.toString();
}
}
这里需要说明一下,SpringBoot项目中是可以存在非入口类main方法的,也就是说非入口类main方法跟入口类main方法可以同时存在项目中,处理不一样的逻辑内容。
代码中的ServiceMonitor
类包含一个main
方法,用于执行服务监测逻辑。它通过创建URL
对象和HttpURLConnection
对象来与服务进行通信,并设置连接和读取超时时间。然后,通过调用connection.getResponseCode()
方法获取响应代码,根据响应代码判断服务的健康状态。
如果响应代码为HTTP_OK
,表示服务正常运行,输出"服务正常运行"。否则,输出"服务无法访问"以及响应代码,并调用getErrorResponse()
方法获取错误响应内容并输出。
在getErrorResponse()
方法中,它通过读取错误流并将内容存储在字符串中,最后返回错误响应内容。
@Data
@Component
@ConfigurationProperties(prefix = "global.datasource")
public class DataSourceConfig {
private String url;
private String username;
private String password;
}
在应用启动时,Spring容器会读取配置文件中的属性值,并将其绑定到DataSourceConfig
类的对应属性上,可以通过注入DataSourceConfig
类的实例来访问这些属性的值。关于Spring容器会读取配置文件中的属性值的详细说明,在我的另一篇文章中有详细说明:SpringBoot中YML,yaml,properties文件的读取_Recently 祝祝的博客-CSDN博客SpringBoot中YML,yaml,properties文件的读取https://blog.csdn.net/qq_45656077/article/details/129013297?spm=1001.2014.3001.5501
@Controller
@RequestMapping("/actuator")
public class HealthCheckController implements HealthIndicator {
@Autowired
private DataSourceConfig dataSourceConfig;
@Override
public Health health() {
boolean isHealthy = checkHealth(); // 根据实际需求进行健康状态检查
if (isHealthy) {
return Health.up().build();
} else {
return Health.down().build();
}
}
@GetMapping("/health")
public String getHealthStatus() {
Health health = health();
return health.getStatus().getCode(); // 返回健康状态码
}
private boolean checkHealth() {
Connection connection = null;
try {
connection = DriverManager.getConnection(dataSourceConfig.getUrl(),
dataSourceConfig.getUsername(), dataSourceConfig.getPassword());
connection.close();
return true;
} catch (SQLException e) {
return false;
}
}
}
实现了HealthIndicator
接口,该接口定义了一个health()
方法,用于返回应用程序的健康状态。在实现中,它调用了checkHealth()
方法进行实际的健康状态检查。
如果健康检查结果为true
,即服务健康,则通过Health.up().build()
方法返回一个UP
状态的Health
对象。
如果健康检查结果为false
,即服务不健康,则通过Health.down().build()
方法返回一个DOWN
状态的Health
对象。
另外,该类还定义了一个getHealthStatus()
方法,用于处理"/actuator/health"路径的GET请求,并返回健康状态码。它内部调用了health()
方法来获取健康状态,并通过health.getStatus().getCode()
方法获取健康状态码并返回。
在checkHealth()
方法中,它通过使用DriverManager
和DataSourceConfig
中的数据库连接属性来尝试建立数据库连接。如果连接成功,表示数据库可用,返回true
,否则表示数据库不可用,返回false
。
上边我的示例是通过检测数据库时候能够连接成功,并且通过HTTP请求接口服务,来检测服务是否正常,其实还可以通过外部服务依赖检查、磁盘空间检查、内存利用率检查、CPU利用率检查、日志检查、健康指标检查来查看服务健康状态,只有需要在接口checkHealth()方法中添加逻辑即可。
checkHealth()方法根据实际需求编写健康状态检查的逻辑 、以检查数据库连接、外部依赖、服务可用性等 、返回true表示健康,返回false表示不健康