java编程之方法模板模型

2019-04-14 18:35发布

java编程之方法模板模型

在日常开发过程中,难免遇到相对独立的功能模块的开发,如 监控告警 功能 ,
如何将此部分代码有效的管理起来,保证代码的可读性及易维护性是我们经常需要考虑的问题。 下面为大家介绍一种简单有效的编程模型-
方法模板模型,现以 监控告警 这个功能作为样例,为大家介绍‘方法模板模型’的使用。

  • 监控告警功能-方法模板关系模型Visio
  • 代码部分

方法模板关系模型Visio

这里写图片描述

代码部分

由于监控维度较多,以下只以AVG基线监控告警为例
/** * 监控告警任务上下文 */ public class TaskContext { private AlarmConfig ac; public TaskContext(AlarmConfig alarmConfig){ this.ac = alarmConfig; } public TaskContext(){} public boolean getResult(String message){ return ac.warning(message); } public AlarmConfig getAc() { return ac; } public void setAc(AlarmConfig ac) { this.ac = ac; } } /** * 监控告警 配置 方法模板 */ public interface AlarmConfig { String getType(); String getIntervalTime(); String getConfigJson(); boolean warning(String message); } /** * AVG基线监控配置类: * @author xiaoxiangxu * */ public class AvgBaseLineConfig implements AlarmConfig{ private String type = AlarmTypeEnum.AVG_BASELINE_LIMIT.getType(); /** 下降百分比*/ private Long threshold; private int numberOfTimes; //告警时间间隔 private Integer warningIntervalTime; private String intervalTime; private String configJson; @Override public String getConfigJson() { return configJson; } public void setConfigJson(String configJson) { this.configJson = configJson; } @Override public String getType() { return type; } @Override public boolean warning(String message) { return false; } public AvgBaseLineConfig(LinkedTreeMap map ,QueryServiceImpl queryService) { List dec = queryService.queryAllEmergencyConfigModel(); if(map!=null && map.size() > 0){ NumberFormat formatter = new DecimalFormat("0"); this.setThreshold(Long.parseLong(formatter.format(map.get("threshold")))); this.setNumberOfTimes(ParmsUtils.getSafeValue_Integer(formatter.format(map.get("numberOfTimes")))); this.setIntervalTime((String) map.get("intervalTime")); this.setConfigJson((String)map.get("configJson")); } if(dec!=null && dec.size() >0) { EmergencyDefaultConfigModel config = dec.get(0); if (!StringUtil.isEmpty(config.getDefultConfigJson())) { String jsonParm = config.getDefultConfigJson().trim(); WarningDefaultConfigJsonBean depts = new Gson().fromJson(jsonParm, WarningDefaultConfigJsonBean.class); this.setWarningIntervalTime(depts.getAvgBaseLineConfig().getWarningIntervalTime()); } } } public AvgBaseLineConfig(WarningDefaultConfigJsonBean.AvgBaseLineConfig_ t) { this.setConfigJson(t.getConfigJson()); this.setIntervalTime(t.getIntervalTime()); this.setWarningIntervalTime(t.getWarningIntervalTime()); this.setThreshold(NumberUtil.toLong(String.valueOf(t.getThreshold()))); this.setNumberOfTimes(t.getNumberOfTimes()); } public void setType(String type) { this.type = type; } public long getThreshold() { return threshold; } public void setThreshold(long threshold) { this.threshold = threshold; } public int getNumberOfTimes() { return numberOfTimes; } public void setNumberOfTimes(int numberOfTimes) { this.numberOfTimes = numberOfTimes; } public Integer getWarningIntervalTime() { return warningIntervalTime; } public void setWarningIntervalTime(Integer warningIntervalTime) { this.warningIntervalTime = warningIntervalTime; } @Override public String getIntervalTime() { return intervalTime; } public void setIntervalTime(String intervalTime) { this.intervalTime = intervalTime; } public AvgBaseLineConfig() {} } /** * Created by xiaoxiangxu on 2015/12/14. */ @Component public abstract class AlarmTaskTemplate { private static final Logger LOG = new Logger(AlarmTaskTemplate.class); public static final int DEFAULT_BATCH_SIZE = 1;//默认一个批次数量 private String CQL_RESULT_QUERY = "select b_content from test.baseline_result where b_id='_KEY'"; @Resource protected CacheDomain cacheDomain; @Resource protected SearchDomain searchDomain; @Resource protected CacheClient cacheClient; @Resource protected QueryServiceImpl queryService; protected ReadWriteLock lock = new ReentrantReadWriteLock(false); private String warningKey = ""; private AlarmTaskModel tm ; private Long startTime; private Long endTime; private List dec; /** * 过滤满足条件的监控数据 * @param taskModelList * @param interval */ protected abstract boolean toWarning(List taskModelList,String interval); /** * 告警信息 * @param * @param config * @param yearMonthIndex * @param searchModel * @return */ protected abstract String getAlarmMessage(Object config, String yearMonthIndex, SearchModel searchModel) ; /** * 获取基线key * @param * @param key * @return */ protected abstract String getBaselineKey(String key) ; /** * 开始执行JOB * @param scheduleContext * @return * @throws Exception */ public String getIntervalTime(ScheduleContext scheduleContext) throws Exception { return scheduleContext.getTaskGetResponse().getParameter().get("interval"); } /** * 根据type获取默认告警时间间隔,默认1分钟 * @param type * @return */ public int getDefaultIntervalTime(String type){ if(dec==null || dec.size() ==0) { dec = queryService.queryAllEmergencyConfigModel(); } try { Validate.notEmpty(dec, "warning : warningDefaultConfig has not config , please config default config as soon as possible !"); EmergencyDefaultConfigModel config = dec.get(0); if (!StringUtil.isEmpty(config.getDefultConfigJson())) { WarningDefaultConfigJsonBean depts = new Gson().fromJson(config.getDefultConfigJson().trim(), WarningDefaultConfigJsonBean.class); if (type.equals(AlarmTypeEnum.FAILURES.getType())) { return depts.getFailuresConfig().getWarningIntervalTime(); } else if (type.equals(AlarmTypeEnum.AVG_BASELINE_LIMIT.getType())) { return depts.getAvgBaseLineConfig().getWarningIntervalTime(); } else if (type.equals(AlarmTypeEnum.AVG_TIME.getType())) { return depts.getAvgTimeConfig().getWarningIntervalTime(); } else if (type.equals(AlarmTypeEnum.LOWERLIMIT_MONITOR.getType())) { return depts.getLowerLimitConfig().getWarningIntervalTime(); } else if (type.equals(AlarmTypeEnum.RET_CODE_MONITOR.getType())) { return depts.getRetCodeConfig().getWarningIntervalTime(); } else if (type.equals(AlarmTypeEnum.TIME_OUT.getType())) { return depts.getTimeOutConfig().getWarningIntervalTime(); } else if (type.equals(AlarmTypeEnum.TP_MONITOR.getType())) { return depts.getTpConfig().getWarningIntervalTime(); } else if (type.equals(AlarmTypeEnum.TPS_BASELINE_LIMIT.getType())) { return depts.getTpsBaseLineConfig().getWarningIntervalTime(); } } }catch (Exception e){ LOG.error(e.getMessage()); return 1; } return 1; } /** * ES 查询条件 * @param att * @return */ protected SearchModel searchModel(AlarmTaskTemplate att){ try { SearchModel searchModel = new SearchModel(); if (att != null) { searchModel.setStartTime(att.getStartTime()); searchModel.setEndTime(att.getEndTime()); searchModel.setAppName(att.getTm().getAppName()); searchModel.setServiceName(att.getTm().getServiceName()); searchModel.setMethodName(att.getTm().getMethodName()); } return searchModel; }catch (Exception e){ LOG.error("CacheDomain saveWarningInterval() error : ", e); return null; } } /** * 获取配制的监控数据列表 * @return */ protected List getTaskModelList(String interval){ // 获取设置的参数(json格式) List taskModelList= null; //如 缓存中间隔时间列表为空,则查全部监控数据,否则按间隔时间查询 if(isEmpty(interval)) { taskModelList = searchDomain.queryAllAlarmTaskModel(); }else { AlarmTaskModel alarmTaskModel = new AlarmTaskModel(); alarmTaskModel.setCronExpression(interval); taskModelList = searchDomain.queryAlarmTaskModelByInterval(alarmTaskModel); } return taskModelList==null?new ArrayList():setOtherInfo(taskModelList); } /** * 按KEY获取应用基线数据 * @return */ public Map> getBaseLineByKey(String key){ LOG.info("按KEY获取应用基线数据" ,key); Validate.notEmpty(key, "key is empty"); return searchDomain.searchBaselineByKey(key, CQL_RESULT_QUERY.replace("_KEY",getBaselineKey(key))); } /** * 增加告警邮箱与手机号 * @param taskModelList * @return */ protected List setOtherInfo(List taskModelList){ DepartmentOrApp departmentOrApp = null; try { for (AlarmTaskModel alarmTaskModel : taskModelList) { Set alarmMobiles = new HashSet(); Set alarmEmails = new HashSet(); if (alarmTaskModel == null || StringUtil.isEmpty(alarmTaskModel.getAppName())) { continue; } alarmMobiles = StringUtil.isEmpty(alarmTaskModel.getMobiles())?new HashSet():new HashSet(Arrays.asList(alarmTaskModel.getMobiles().split(","))); departmentOrApp = searchDomain.getAppCenterInfo(alarmTaskModel.getAppName()); if (departmentOrApp == null || departmentOrApp.getUser() == null) { continue; } //来源:appCenter for (AlamUser alamUser : departmentOrApp.getUser()) { alarmMobiles.add(alamUser.getPhone()); alarmEmails.add(alamUser.getMail()); } //来源:默认配置 for(String defaultEmailAddress : Constant.BASELINE_DEFAULT_EMAIL_ADDRESS.split(",")){ alarmEmails.add(defaultEmailAddress); } alarmTaskModel.setMobiles(new Gson().toJson(alarmMobiles)); alarmTaskModel.setEmails(new Gson().toJson(getWarningEmailAddressByMobileFromCache(alarmMobiles,alarmEmails))); } }catch (Exception e){ LOG.error("setOtherInfo error : ",e); } return taskModelList; } /** * 通过告警手机号,查询缓存中对应的email地址 * @param alarmMobiles * @param alarmEmails */ public Set getWarningEmailAddressByMobileFromCache(Set alarmMobiles,Set alarmEmails){ if(alarmMobiles==null){ return alarmMobiles; } try{ Map userModelMap = (Map) cacheClient.getObjcet(Constant.LDAP_USER_INFO_CACHE); if(userModelMap!=null){ Set> set = userModelMap.entrySet(); for(Map.Entry entry : set){ alarmEmails.add(entry.getValue().getMail()); } } }catch (Exception e){ LOG.error("getWarningEmailAddressByMobileFromCache error :",e); } return alarmEmails; } /** * 获取当前数据 * @param app */ protected Map getPonitFromCassandraByKey(String type,String app,AlarmTaskTemplate template){ Map map = new HashMap(); //获取上次执行AlarmTask的时间戳,用于cassandra查询条件 try { //查询cassandra AVG表数据 List>> result = searchDomain.getAppDataForWarning(app,type, cacheClient.getData(template.getWarningKey()), TimeUtils.getNowDay()); if (result == null || result.size() == 0) { return map; } for (int i = 0; i < result.size(); i++) { List> eachAppDateList = result.get(i); if(eachAppDateList==null || eachAppDateList.size()== 0){ continue; } for (int j = 0; j < eachAppDateList.size(); j++) { map.put(TimeUtils.dateFormatForHH_MM_SS((Long) eachAppDateList.get(j).get("t")), (Integer) eachAppDateList.get(j).get("_")); } } } catch (Exception e) { LOG.error(e.getMessage(), e); return null; } return map; } public AlarmTaskTemplate() {} public AlarmTaskTemplate(String warningKey, AlarmTaskModel tm, Long startTime, Long endTime) { lock.writeLock().lock(); this.warningKey = warningKey; this.tm = tm; this.startTime = startTime; this.endTime = endTime; lock.writeLock().unlock(); } public SearchDomain getSearchDomain() { return searchDomain; } public void setSearchDomain(SearchDomain searchDomain) { this.searchDomain = searchDomain; } public CacheDomain getCacheDomain() { return cacheDomain; } public void setCacheDomain(CacheDomain cacheDomain) { this.cacheDomain = cacheDomain; } public CacheClient getCacheClient() { return cacheClient; } public void setCacheClient(CacheClient cacheClient) { this.cacheClient = cacheClient; } public QueryServiceImpl getQueryService() { return queryService; } public void setQueryService(QueryServiceImpl queryService) { this.queryService = queryService; } public String getWarningKey() { return warningKey; } public void setWarningKey(String warningKey) { this.warningKey = warningKey; } public AlarmTaskModel getTm() { return tm; } public void setTm(AlarmTaskModel tm) { this.tm = tm; } public Long getStartTime() { return startTime; } public void setStartTime(Long startTime) { this.startTime = startTime; } public Long getEndTime() { return endTime; } public void setEndTime(Long endTime) { this.endTime = endTime; } } /** * 报警任务 - 平均响应时间 * * @author */ @Component public class AVGBaselineAlarmTask extends AlarmJobTemplate implements SchedulerJob { private static final Logger LOG = new Logger(AVGBaselineAlarmTask.class); private AVGBaselineAlarmTask avg; @Override public void doJob(ScheduleContext scheduleContext) throws Exception { //告警入口 long startTime = System.currentTimeMillis(); LOG.info("# AVGBaselineAlarmTask do job start "); String interval = getIntervalTime(scheduleContext); toWarning(getTaskModelList(interval), interval); LOG.info("# AVGBaselineAlarmTask do job end, use ", System.currentTimeMillis() - startTime, " ms"); } /** * 过滤满足条件的监控数据 * @param taskModelList * @param interval */ @Override protected boolean toWarning(List taskModelList,String interval){ if(taskModelList==null || taskModelList.size()==0){ return false; } LOG.info("Alarm step2: taskModelList.size(): ",taskModelList.size(),",interval :",interval); AvgBaseLineConfig ac; try{ for (AlarmTaskModel taskModel : taskModelList) { //解析监控规则 JSON 串 if (taskModel.getType().contains(AlarmTypeEnum.AVG_BASELINE_LIMIT.getType())) { //获取查询时间区间 Map map = TimeUtils.getTimeRangesAddOffsetTime(IntervalTimeEnum.getTimeUnitByTimeFlag(interval), Constant.getOFFSETS_TIME()); //告警任务:告警关键字,告警对象,开始时间,结束时间 **avg =new AVGBaselineAlarmTask(taskModel.getType() + "-" + taskModel.getAppName() + "-" + taskModel.getServiceName() + "-" + taskModel.getMethodName() + "-" + taskModel.getType(),taskModel,map.get("startTime"), map.get("endTime") ); //告警参数配置 //ac = new AvgBaseLineConfig(AlarmUtil.findAlarmConfigFromList(AlarmTypeEnum.AVG_BASELINE_LIMIT.getType(), new Gson().fromJson(taskModel.getRuleParameters(), List.class)),queryService){ ac = new AvgBaseLineConfig( new Gson().fromJson(taskModel.getRuleParameters(), WarningDefaultConfigJsonBean.AvgBaseLineConfig_.class)){ //告警入口 @Override public boolean warning(String message) { //告警方法:缓存对象,告警内容,告警任务模板对象,告警间隔时间 return AlarmUtil.sendAlarmMessage(cacheDomain,message,avg,getDefaultIntervalTime(AlarmTypeEnum.AVG_BASELINE_LIMIT.getType()));** } }; //通过告警上下文触发告警动作 return new TaskContext(ac).getResult(getAlarmMessage(ac, "", this.searchModel(avg))); } } }catch (Exception e){ LOG.info("AvgBaseLineConfig run error ",e); }finally { if( !StringUtil.isEmpty(interval)){ //缓存执行规则interval,作为对应用监控类型下拉选项 cacheDomain.saveWarningInterval(AlarmTypeEnum.AVG_BASELINE_LIMIT.getType(),interval); } } return false; } /** * @param searchModel * @return * @description avg基线报警 */ @Override protected String getAlarmMessage(Object ac,String yearMonthIndex ,SearchModel searchModel) { Validate.notNull(ac, "warning object - ac is null"); String message = ""; AvgBaseLineConfig c = (AvgBaseLineConfig)ac; try { String key = searchModel.getAppName(); if(!StringUtil.isEmpty(searchModel.getServiceName())){ key+=":"+searchModel.getServiceName(); if(!StringUtil.isEmpty(searchModel.getMethodName())){ key+=":"+searchModel.getMethodName(); } } //通过比对基线与当前值进行比较获取告警信息 message = this.getWarningMessage(getBaseLineByKey(key),key,c,this.getPonitFromCassandraByKey(Constant.AVG_BASE_LINE,key,avg)); } catch (Exception e) { LOG.error(e.getMessage(), e); } return isEmpty(message)?"": "【" + message + "】"; } @Override protected String getBaselineKey(String key) { return Constant.AVG_BASE_LINE+key+TimeUtils.getBeforeDateForDay(1); } /** * 根据基线值获取告警信息 * @param key_ * @param baselineMaps 基线值 * @param currentMap 当前值 * @param c 告警值 * @return */ public String getWarningMessage(Map> baselineMaps,String key_,AvgBaseLineConfig c,Map currentMap){ if(baselineMaps == null || baselineMaps.size() ==0 || currentMap==null || currentMap.size() ==0){ return ""; } LOG.info("Alarm step3: AVGBaselineAlarmTask getWarningMessage currentKey:",key_,",baseline.size():",baselineMaps.size(),",currentMap.size():"+currentMap.size()); List baselineList = baselineMaps.get(key_); if(baselineList == null || baselineList.size() == 0){ return ""; } int times_ = 0 ; int total = 0; for(BaselinePointModel baselinePointModel : baselineList){ if(!currentMap.containsKey(baselinePointModel.getK())){ continue; } int temp = currentMap.get(baselinePointModel.getK()) - baselinePointModel.getV(); //如果平均响应时间大于基线 if(temp > 0 && temp / Double.valueOf(baselinePointModel.getV()) * 100 > NumberUtil.toInt(String.valueOf(c.getThreshold()), DEFAULT_BATCH_SIZE)){ times_ ++; } total++; } if(times_ >= c.getNumberOfTimes() && total>0){ return "AVG基线告警:KEY名称为:" + key_ + ",平均响应时间突破基线阈值:" + c.getThreshold() + ",超出阈值:" + times_ + "次,占比为" + new DecimalFormat("######0.00").format((times_ / NumberUtils.toDouble(String.valueOf(total))) * 100) + "%"; } return ""; } /** * 求AVG 占比 * @param * @param key * @param value * @return */ private long getBaseLinePointValue(BaselinePointModel baselinePointModel,String key,String value){ try { Long totalValue = ParmsUtils.getSafeValue_Long(String.valueOf(baselinePointModel.getV())); Integer pointValue = ParmsUtils.getSafeValue_Integer(value); return totalValue - pointValue; }catch (Exception e){ return 0L; } } /** * 获取pointMap key * @param key_ * @return */ private String getPonitKey(Object key_){ return ParmsUtils.getSafeValue_String(key_); } /** * 求占比 * @param numerator * @param denominator * @return */ private int getPercent(int numerator,int denominator){ NumberFormat formatter = new DecimalFormat("0"); Double quotient=new Double(Double.valueOf(numerator)/Double.valueOf(denominator)); return ParmsUtils.getSafeValue_Integer(formatter.format(quotient)); } public AVGBaselineAlarmTask() { super(); } public AVGBaselineAlarmTask(String warningKey, AlarmTaskModel tm, Long startTime, Long endTime) { super(warningKey, tm, startTime, endTime); } }
到此 方法模板模型 样例介绍结束,代码量比较大未做过多删减,希望大家能够感受其中精妙之处。