Java項目啟動成功、失敗信息實時反饋提醒問題(郵件或者短信)
在開發(fā)的流程中必須涉及的項目的部署發(fā)布,這個過程也肯定會有成功失敗,在不同的公司里采用的提醒方式不同。
在說明下面的方案前,需要首先說明一下基本應用的場景。
場景說明
1、純后臺應用,現(xiàn)在項目基本都是前后端分離,因為一個前端服務可能會對應多個后端服務的支持,隨著整個開發(fā)大環(huán)境的完善和技術的成熟,之前那種前后端耦合的應用很少,這里不在做具體的考慮。
2、項目的基本架構是Spring+Spring MVC+Mybatis,其實主要是Spring+Spring MVC,因為下面的實現(xiàn)方式在這種模式下模擬,其他環(huán)境可以根據(jù)這個模式仿照,但是照搬可能存在問題,因為現(xiàn)在很多公司都開始使用SpringBoot相關的前沿技術。
3、環(huán)境說明
- 本地測試環(huán)境,就是IDEA的啟動測試,不多說;
- 開發(fā)測試環(huán)境,這個環(huán)境基本用來聯(lián)調,開發(fā)人員發(fā)布項目使用的;
- 測試環(huán)境,這個是測試人員來用,將開發(fā)的代碼拉到測試環(huán)境,進行各種姿勢的測試;
- 演示環(huán)境,這個環(huán)境看各個公司的定義可能不同,也就是上線前的最后一個環(huán)境,基本模擬線上環(huán)境,最終驗證項目的完整性,有時候所說的灰度、冒煙測試都會在這個環(huán)境執(zhí)行;
- 線上環(huán)境,不解釋。
4、下面的內容數(shù)據(jù)自己歪歪,如果存在問題,歡迎提建議。
簡單實現(xiàn)的幾種方式
在項目中添加一個主頁,當發(fā)布完成后,訪問該頁面是OK就表示發(fā)布成功,反之就是失敗,但是這樣存在很多問題,比如在線上環(huán)境,這個頁面可能就訪問不到(純后臺應用可能不會提供這個訪問功能)。在本地測試和開發(fā)環(huán)境可以湊合使用。
定時任務請求項目,這個不僅能監(jiān)控到項目啟動是否成功,也可以監(jiān)控服務器宕機問題,但是也存在問題,那就是要重新開一個項目,用于發(fā)送請求,另外當項目啟動的時候,剛好定時任務發(fā)起,此時是請求不通的,系統(tǒng)會誤報啟動失敗或者宕機,其實不是這樣。
日志掃描,通過對日志的分析查看日志中的異常,并做分析,給予開發(fā)或者維護人員一個通知,可以通過Python腳本等方式執(zhí)行,設計到整體項目架構的問題,不做太多的討論,也不是這個博客的主要討論范疇,不做太多贅述。
項目中添加邏輯代碼,用于捕獲項目啟動加載是否正常,從而判斷項目是否啟動成功。(主要討論)
項目啟動反饋提醒實現(xiàn)
web.xml文件中的配置
<servlet>
<servlet-name>spring-dispatcher</servlet-name>
<servlet-class>com.minuor.service.notice.LocalDispatcherServletDemo</servlet-class>
<!-- 配置SpringMVC需要加載的配置文件 spring-xxx.xml -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-web.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-dispatcher</servlet-name>
<!--默認匹配所有的請求 -->
<url-pattern>/</url-pattern>
</servlet-mapping>正常應該配置spring默認的DispatcherServlet,這里需要改為加載重新后的LocalDispatcherServletDemo。
LocalDispatcherServletDemo類代碼
package com.minuor.service.notice;
import com.minuor.common.utils.JavaMailSendUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.i18n.LocaleContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* @Author: Joker
* @Date: 2018/3/19
* @Desc: 重寫DispatcherServlet,做系統(tǒng)啟動成功失敗監(jiān)控并通知
*/
@Slf4j
public class LocalDispatcherServletDemo extends DispatcherServlet {
public LocalDispatcherServletDemo() {
super();
}
public LocalDispatcherServletDemo(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
}
@Override
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext webApplicationContext;
try {
webApplicationContext = super.initWebApplicationContext();
sendMsg(Boolean.TRUE);
log.info(">>>>>>>webApplicationContext初始化成功~");
} catch (Exception e) {
sendMsg(Boolean.FALSE);
webApplicationContext = new XmlWebApplicationContext();//設置臨時值,避免重復初始化
log.info(">>>>>>>webApplicationContext初始化失敗~");
}
return webApplicationContext;
}
/**
* 發(fā)送郵件
*
* @param flag
*/
private void sendMsg(boolean flag) {
try {
JavaMailSendUtil sender = new JavaMailSendUtil();
//成功失敗信息
String result = "FAIL";
if (flag) result = "SUCCESS";
//模塊名
String ip = InetAddress.getLocalHost().getHostAddress();
String userDir = System.getProperty("user.dir");
String tempStr = userDir.substring(0, userDir.indexOf(File.separator + "bin"));
String userDirModel = tempStr.substring(tempStr.lastIndexOf(File.separator) + 1);
//組裝并推送信息
String mailTest = "發(fā)布系統(tǒng):" + "Minuor個人博客系統(tǒng)" + "<br/>" +
"發(fā)布環(huán)境:" + ip + "<br/>" +
"模塊名稱:" + userDirModel + "<br/>" +
"發(fā)布時間:" + new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date()) + "<br/>" +
"發(fā)布結果:" + result + "<br/>" +
"溫馨提示:" + "此郵件僅為系統(tǒng)發(fā)布通知郵件,請勿回復!";
sender.sendEmail("個人博客系統(tǒng)發(fā)布結果提醒", mailTest, "xxxx@163.com");
} catch (Exception e) {
log.info(">>>>>個人博客系統(tǒng)發(fā)布結果預警郵件推送失??!異常信息:{}", e);
}
}
@Override
public void setDetectAllHandlerMappings(boolean detectAllHandlerMappings) {
super.setDetectAllHandlerMappings(detectAllHandlerMappings);
}
@Override
protected void initFrameworkServlet() throws ServletException {
super.initFrameworkServlet();
}
@Override
public void setDetectAllHandlerAdapters(boolean detectAllHandlerAdapters) {
super.setDetectAllHandlerAdapters(detectAllHandlerAdapters);
}
@Override
public void setDetectAllHandlerExceptionResolvers(boolean detectAllHandlerExceptionResolvers) {
super.setDetectAllHandlerExceptionResolvers(detectAllHandlerExceptionResolvers);
}
@Override
public void setDetectAllViewResolvers(boolean detectAllViewResolvers) {
super.setDetectAllViewResolvers(detectAllViewResolvers);
}
@Override
public void setThrowExceptionIfNoHandlerFound(boolean throwExceptionIfNoHandlerFound) {
super.setThrowExceptionIfNoHandlerFound(throwExceptionIfNoHandlerFound);
}
@Override
public void setCleanupAfterInclude(boolean cleanupAfterInclude) {
super.setCleanupAfterInclude(cleanupAfterInclude);
}
@Override
protected void onRefresh(ApplicationContext context) {
super.onRefresh(context);
}
@Override
protected void initStrategies(ApplicationContext context) {
super.initStrategies(context);
}
@Override
protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {
return super.getDefaultStrategy(context, strategyInterface);
}
@Override
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
return super.getDefaultStrategies(context, strategyInterface);
}
@Override
protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
return super.createDefaultStrategy(context, clazz);
}
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
super.doService(request, response);
}
@Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
super.doDispatch(request, response);
}
@Override
protected LocaleContext buildLocaleContext(HttpServletRequest request) {
return super.buildLocaleContext(request);
}
@Override
protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
return super.checkMultipart(request);
}
@Override
protected void cleanupMultipart(HttpServletRequest request) {
super.cleanupMultipart(request);
}
@Override
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
return super.getHandler(request);
}
@Override
protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
super.noHandlerFound(request, response);
}
@Override
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
return super.getHandlerAdapter(handler);
}
@Override
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
return super.processHandlerException(request, response, handler, ex);
}
@Override
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
super.render(mv, request, response);
}
@Override
protected String getDefaultViewName(HttpServletRequest request) throws Exception {
return super.getDefaultViewName(request);
}
@Override
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
return super.resolveViewName(viewName, model, locale, request);
}
}重新所有的方法,直接調用父類DispatcherServlet內的邏輯,實際LocalDispatcherServletDemo中沒有具體的邏輯,只有構造方法、initWebApplicationContext、sendMsg短信發(fā)送邏輯的修改和創(chuàng)建。
JavaMailSendUtil郵件發(fā)送邏輯代碼
package com.minuor.common.mail;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
/**
* @Author: Joker
* @Date: 2018/3/19
* @Desc: 發(fā)送郵件服務
*/
@Slf4j
public class JavaMailSendUtil {
/**
* 發(fā)送郵件
*/
public void sendEmail(String subject, String mailText, String rStr) {
try {
// 1.創(chuàng)建一個程序與郵件服務器會話對象 Session
Properties props = new Properties();
props.setProperty("mail.smtp.host", "smtp.163.com");
props.setProperty("mail.smtp.port", "25");
// 指定驗證為true
props.setProperty("mail.smtp.auth", "true");
// 驗證賬號及密碼,密碼需要是第三方授權碼
Authenticator auth = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(
"xxxx@163.com", "123456");
}
};
Session session = Session.getInstance(props, auth);
// 2.創(chuàng)建一個Message,它相當于是郵件內容
Message message = new MimeMessage(session);
// 設置發(fā)送者
message.setFrom(new InternetAddress("xxxxx@163.com"));
// 設置發(fā)送方式與接收者
if (StringUtils.isBlank(rStr)) return;
String[] rStrs = rStr.split(",");
InternetAddress[] address = new InternetAddress[rStrs.length];
int index = 0;
for (String str : rStrs) {
address[index] = new InternetAddress(str);
index++;
}
message.setRecipients(MimeMessage.RecipientType.TO, address);
// 設置主題
message.setSubject(subject);
// 設置內容
message.setContent(mailText, "text/html;charset=utf-8");
// 3.創(chuàng)建 Transport用于將郵件發(fā)送
Transport.send(message);
log.info(">>>>>>>發(fā)送郵件成功<<<<<<<");
} catch (Exception e) {
log.error(">>>>>>>發(fā)送郵件異常:{}", e);
}
}
}封裝的最簡單的發(fā)送方式,只為實現(xiàn)簡單的郵件推送功能。
具體說明
在重新initWebApplicationContext內,對調用父類的initWebApplicationContext方法加了異常捕捉,在catch捕捉中添加了郵件處理邏輯,也將異常吃點不再打印出來;
郵件推送分為兩個部分,一個是項目啟動成功,一個是項目啟動失敗,兩個部分都會給開發(fā)或者維護人員提供相應的郵件提醒;
最主要的一點,這里涉及到的郵件發(fā)送工具類,重寫類LocalDispatcherServletDemo都不能交給spring管理,因為在spring加載失敗的時候,這些類對應的bean是不能創(chuàng)建成功的,更不用說對象的注入以及具體邏輯的實現(xiàn)。
總結
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
webuploader 實現(xiàn)圖片批量上傳功能附實例代碼
這篇文章主要介紹了webuploader 實現(xiàn)圖片批量上傳功能,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-11-11
java自定義動態(tài)鏈接數(shù)據(jù)庫示例
這篇文章主要介紹了java自定義動態(tài)鏈接數(shù)據(jù)庫示例,需要的朋友可以參考下2014-02-02
淺談Spring框架中@Autowired和@Resource的區(qū)別
最近review別人代碼的時候,看到了一些@Autowired不一樣的用法,覺得有些意思,下面這篇文章主要給大家介紹了關于Spring框架中@Autowired和@Resource區(qū)別的相關資料,需要的朋友可以參考下2022-10-10
SpringBoot利用validation實現(xiàn)優(yōu)雅的校驗參數(shù)
數(shù)據(jù)的校驗是交互式網(wǎng)站一個不可或缺的功能,如果數(shù)據(jù)庫中出現(xiàn)一個非法的郵箱格式,會讓運維人員頭疼不已。本文將介紹如何利用validation來對數(shù)據(jù)進行校驗,感興趣的可以跟隨小編一起學習一下2022-06-06
SpringBoot整合FastDFS中間件實現(xiàn)文件分布管理
FastDFS是一個開源的輕量級分布式文件系統(tǒng),它對文件進行管理,功能包括:文件存儲、文件同步、文件上傳、文件下載等,解決了大容量存儲和負載均衡的問題,本文介紹了SpringBoot整合FastDFS中間件實現(xiàn)文件分布管理,需要的朋友可以參考下2024-08-08
Java HttpURLConnection超時和IO異常處理
這篇文章主要介紹了Java HttpURLConnection超時和IO異常處理的相關資料,需要的朋友可以參考下2016-09-09

