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<T> {
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<String,Object> map ,QueryServiceImpl queryService) {
List<EmergencyDefaultConfigModel> 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<EmergencyDefaultConfigModel> dec;
/**
* 过滤满足条件的监控数据
* @param taskModelList
* @param interval
*/
protected abstract boolean toWarning(List<AlarmTaskModel> 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<AlarmTaskModel> getTaskModelList(String interval){
// 获取设置的参数(json格式)
List<AlarmTaskModel> 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<AlarmTaskModel>():setOtherInfo(taskModelList);
}
/**
* 按KEY获取应用基线数据
* @return
*/
public Map<String,List<BaselinePointModel>> 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<AlarmTaskModel> setOtherInfo(List<AlarmTaskModel> taskModelList){
DepartmentOrApp departmentOrApp = null;
try {
for (AlarmTaskModel alarmTaskModel : taskModelList) {
Set<String> alarmMobiles = new HashSet<String>();
Set<String> alarmEmails = new HashSet<String>();
if (alarmTaskModel == null || StringUtil.isEmpty(alarmTaskModel.getAppName())) {
continue;
}
alarmMobiles = StringUtil.isEmpty(alarmTaskModel.getMobiles())?new HashSet<String>():new HashSet<String>(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<String> getWarningEmailAddressByMobileFromCache(Set<String> alarmMobiles,Set<String> alarmEmails){
if(alarmMobiles==null){
return alarmMobiles;
}
try{
Map<String,LdapUserModel> userModelMap = (Map<String,LdapUserModel>) cacheClient.getObjcet(Constant.LDAP_USER_INFO_CACHE);
if(userModelMap!=null){
Set<Map.Entry<String, LdapUserModel>> set = userModelMap.entrySet();
for(Map.Entry<String, LdapUserModel> entry : set){
alarmEmails.add(entry.getValue().getMail());
}
}
}catch (Exception e){
LOG.error("getWarningEmailAddressByMobileFromCache error :",e);
}
return alarmEmails;
}
/**
* 获取当前数据
* @param app
*/
protected Map<String, Integer> getPonitFromCassandraByKey(String type,String app,AlarmTaskTemplate template){
Map<String, Integer> map = new HashMap<String, Integer>();
//获取上次执行AlarmTask的时间戳,用于cassandra查询条件
try {
//查询cassandra AVG表数据
List<List<Map<String, Object>>> 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<Map<String, Object>> 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<AlarmTaskModel> 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<String, Long> 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<String,List<BaselinePointModel>> baselineMaps,String key_,AvgBaseLineConfig c,Map<String, Integer> 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<BaselinePointModel> 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);
}
}
到此 方法模板模型 样例介绍结束,代码量比较大未做过多删减,希望大家能够感受其中精妙之处。