一、前言
现在微服务流行,一个系统可能会被拆分为几个微服务,各个微服务之间也可能要相互调用,有的时候就需要检测服务是不是可用,为什么要检测其他服务的状态呢?(不是自己的我都不信,默认不信赖其他服务),提高本身的可用性。在发送数据前,先检测服务是否可用,如果不可用则发送邮件到相关人员,虽然这个思路是好的,但是实际是存在一个大大的问题的,当你要连接的服务冷启动的时候(重新部署打包等等),或者说服务挂了,服务会停很长一段时间,这个时候如果你的检测程序发现服务不可用就会一直发邮件。这是个大问题啊,邮箱不一会就爆了。
二、思路和代码
默认设置一个标识位为1,代表服务可用,当自己的程序检测到要调用的服务不可用时发送邮件,这个时候检查标识位是否为1,如果为1则发送邮件,代表服务由可用变为了不可用,如果标识位为0,代表服务从不可用到不可用,这个时候就不发送邮件了,避免调用服务长时间不可用一直发送邮件。
设置标识位,当然可用用数据库或者ConcurrentHashMap去维护一个哈希表,但是我觉得有点大材小用了,于是就采用了静态变量的方法。某个的类的实例共享一个变量。
因为前两天写过一个关于检测webservice是否可用的博客,但是里面没有对发送邮件进行限制,所以还是以检测webservice服务是否可用为例。
代码:
工具类
package com.zlc.springcloud..util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* 检验连接是否可用
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2019/12/11 9:49
**/
@Component
public class ConnectionUtil {
private static final Logger log = LoggerFactory.getLogger(ConnectionUtil.class);
// webservice地址默认可用(1),当调用不成功时,设置状态为(0)
private static int webserviceConnectionState = 1;
private MailUtil mailUtil;
public ConnectionUtil(MailUtil mailUtil) {
this.mailUtil = mailUtil;
}
/**
* 验证webservice是否可用
*参数: webserviceUrl webservice地址
*返回值 : 可用返回true,不可用返回false
*@author :zlc(Jacob)
*创建时间:2019/12/11
*/
public boolean webServiceIsAvaiable(String webserviceUrl){
boolean flag = false;
try {
URL url = new URL(webserviceUrl);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setUseCaches(false);
urlConnection.setConnectTimeout(3000);
if (HttpURLConnection.HTTP_OK == urlConnection.getResponseCode()){
flag = true;
ConnectionUtil.webserviceConnectionState = 1;
}
} catch (IOException e) {
e.printStackTrace();
log.error("校验webservice服务不可用,异常信息为" + e.getMessage());
try {
// 当上次服务是可用的时候才会发送邮件,避免服务不可用一直发送邮件
if (ConnectionUtil.webserviceConnectionState == 1){
mailUtil.sendMail("【批处理】webservice服务不可用","webservice地址为:" + webserviceUrl + "异常信息为:" + e.getMessage());
}
ConnectionUtil.webserviceConnectionState = 0;
}catch (Exception e1){
e1.printStackTrace();
log.error("发送邮件异常,异常信息为:"+ e1.getMessage());
}
}
return flag;
}
}
调用测试:
package com.zlc.springcloud.task.executetaskjob;
import com.zlc.springcloud.util.ConnectionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Service;
/**
* @author zlc
* 批处理的入口 通过查询数据库中的状态为启用的任务 ,注册任务
* 添加实现了CommandLineRunner接口的SysJobRunner类
* 当spring boot项目启动前,加载数据库里状态为正常的定时任务。
*/
@Service
public class SysJobRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(SysJobRunner.class);
private ConnectionUtil connectionUtil;
public SysJobRunner( ConnectionUtil connectionUtil) {
this.connectionUtil = connectionUtil;
}
@Override
public void run(String... args) {
for (int i =0; i<10; i++){
String url = "https://www.baidu.com/";
if (i == 2 || i == 5){
url = "http://127.0.0.1:8070";
}
connectionUtil.webServiceIsAvaiable(url);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3)SysJobRunner 这个类实现了 CommandLineRunner,会在springboot程序正常启动前运行。通过在内存中设置一个静态变量webserviceConnectionState来表示服务上次是否为正常,如果服务不可用了,则改为0,表示服务不可用,这样在下次进行服务可用校验的时候就会通过比较内存中的标识位来控制发邮件了。