使用Spring跟踪异常–第2部分–委托模式

在上一个博客中 ,我开始谈论需要弄清楚您的应用程序在生产环境中是否行为异常。 我说过,监视应用程序的一种方法是检查其日志文件是否存在异常,如果发现异常,则采取适当的措施。 显然,日志文件会占用数百兆的磁盘空间,而手动监视它们是不切实际的,而且很无聊。

我还说过,有几种方法可以自动监视日志文件,并提出了一个基于Spring的实用程序,该实用程序每天都会梳理日志文件,并在发现任何异常时向您发送电子邮件。

我只介绍了第一类: FileLocator ,它将在目录及其子目录中搜索日志文件。 找到一个后,将其传递给FileValidator

FileValidator必须对文件执行多项检查。 首先,它必须确定文件是否足够年轻以检查异常。 想法是,由于应用程序定期运行,因此没有必要检查目录中找到的所有文件是否存在错误,我们只希望自应用程序上次运行以来已创建或更新的文件。

这种设计的思想是将同一接口的几种实现组合在一起,创建一个负责验证文件的聚合对象。 鹰眼的读者会注意到,这是Delegate Pattern的实现。

屏幕+拍摄+ 2014-03-08 + at + 16.59.55

在上面的类图中,将RegexValidatorFileAgeValidator实例注入到FileValidator ,并将其验证任务委托给这些类。

依次进行这些操作,并首先处理Validator接口…

public interface Validator { /** The validation method */ public <T> boolean validate(T obj); }

上面的代码演示了Validator接口的简单性。 它具有单个方法validate(T obj) ,这是一个泛型方法调用,可以提高此接口的灵活性和可重用性。 当类实现此接口时,它们可以更改输入参数类型以适合自己的目的……如下面的第一个实现所示:

public class RegexValidator implements Validator { private static final Logger logger = LoggerFactory.getLogger(RegexValidator.class); private final Pattern pattern; public RegexValidator(String regex) { pattern = Pattern.compile(regex); logger.info("loaded regex: {}", regex); } @Override public <T> boolean validate(T string) { boolean retVal = false; Matcher matcher = pattern.matcher((String) string); retVal = matcher.matches(); if (retVal && logger.isDebugEnabled()) { logger.debug("Found error line: {}", string); } return retVal; } 
}

RegexValidator类具有一个带正则表达式字符串的单个参数构造函数。 然后将其转换为Pattern实例变量,并由validate(T string)方法使用它来测试String输入参数是否与原始构造函数arg正则表达式匹配。 如果是这样,那么validate(T string)将返回true。

@Service 
public class FileAgeValidator implements Validator { @Value("${max.days}") private int maxDays; /** * Validate the age of the file. * * @see com.captaindebug.errortrack.Validator#validate(java.lang.Object) */ @Override public <T> boolean validate(T obj) { File file = (File) obj; Calendar fileDate = getFileDate(file); Calendar ageLimit = getFileAgeLimit(); boolean retVal = false; if (fileDate.after(ageLimit)) { retVal = true; } return retVal; } private Calendar getFileAgeLimit() { Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_MONTH, -1 * maxDays); return cal; } private Calendar getFileDate(File file) { long fileDate = file.lastModified(); Calendar when = Calendar.getInstance(); when.setTimeInMillis(fileDate); return when; } }

第二个Validator(T obj)实现是FileAgeValidator显示的FileAgeValidator ,首先要注意的是,整个过程是由max.days属性驱动的。 这被注入到FileAgeValidator@Value注释的maxDays实例变量中。 此变量确定文件的最长使用期限(天)。 该文件早于该值,然后validate(T obj)将返回false。

在此实现中, validate(T obj) 'obj'参数被强制转换为File对象,然后将其用于将文件的日期转换为Calendar对象。 下一行代码将maxDays变量转换为第二个Calendar对象: ageLimit 。 然后将ageLimitfileDate对象进行比较。 如果fileDateageLimit之后,则validate(T obj)返回true。

validator程序包中的最后一个类是FileValidator ,如上所示,它将很多职责委托给其他三个聚合的验证程序:一个FileAgeValidator和两个RegexValidator

@Service 
public class FileValidator implements Validator { private static final Logger logger = LoggerFactory.getLogger(FileValidator.class); @Value("${following.lines}") private Integer extraLineCount; @Autowired @Qualifier("scan-for") private RegexValidator scanForValidator; @Autowired(required = false) @Qualifier("exclude") private RegexValidator excludeValidator; @Autowired private FileAgeValidator fileAgeValidator; @Autowired private Results results; @Override public <T> boolean validate(T obj) { boolean retVal = false; File file = (File) obj; if (fileAgeValidator.validate(file)) { results.addFile(file.getPath()); checkFile(file); retVal = true; } return retVal; } private void checkFile(File file) { try { BufferedReader in = createBufferedReader(file); readLines(in, file); in.close(); } catch (Exception e) { logger.error("Error whilst processing file: " + file.getPath() + " Message: " + e.getMessage(), e); } } @VisibleForTesting BufferedReader createBufferedReader(File file) throws FileNotFoundException { BufferedReader in = new BufferedReader(new FileReader(file)); return in; } private void readLines(BufferedReader in, File file) throws IOException { int lineNumber = 0; String line; do { line = in.readLine(); if (isNotNull(line)) { processLine(line, file.getPath(), ++lineNumber, in); } } while (isNotNull(line)); } private boolean isNotNull(Object obj) { return obj != null; } private int processLine(String line, String filePath, int lineNumber, BufferedReader in) throws IOException { if (canValidateLine(line) && scanForValidator.validate(line)) { List<String> lines = new ArrayList<String>(); lines.add(line); addExtraDetailLines(in, lines); results.addResult(filePath, lineNumber, lines); lineNumber += extraLineCount; } return lineNumber; } private boolean canValidateLine(String line) { boolean retVal = true; if (isNotNull(excludeValidator)) { retVal = !excludeValidator.validate(line); } return retVal; } private void addExtraDetailLines(BufferedReader in, List<String> lines) throws IOException { for (int i = 0; i < extraLineCount; i++) { String line = in.readLine(); if (isNotNull(line)) { lines.add(line); } else { break; } } } }

FileValidatorvalidate(T obj)File作为参数。 它的首要职责是验证文件的年龄。 如果该验证器返回true,则它将通知Report类它已找到一个新的有效文件。 然后,它检查文件中是否有错误,并将找到的任何内容添加到Report实例。 它通过使用BufferedReader依次检查文件的每一行来做到这一点。 在检查某行是否包含错误之前,它会检查该行是否未从检查中排除-即,它与排除的异常或我们不感兴趣的异常不匹配。如果该行与排除的异常不匹配异常,然后使用RegexValidator的第二个实例检查是否需要查找异常。 如果该行确实包含错误,则会将其添加到List<String>对象。 然后从添加到列表的文件中读取以下几行,以使报告更具可读性。

因此,文件解析将继续,一次检查每一行以查找错误并建立报告,以便以后处理。

该封面的验证文件使用委托模式添加了发现到Report任何异常,但是此Report对象如何工作? 我没有提到它,输出是如何产生的? 下次再说。

  • 该博客的代码可在Github上找到: https : //github.com/roghughe/captaindebug/tree/master/error-track 。

参考: 使用Spring跟踪异常–第2部分–在Captain Debug的Blog博客上,由我们的JCG合作伙伴 Roger Hughes 委托模式 。

翻译自: https://www.javacodegeeks.com/2014/03/tracking-exceptions-with-spring-part-2-delegate-pattern.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/364836.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

aix java home_java程序员工作日子一(java_home 配置)

安装 JDK 和设置 JAVA_HOME如果您尚未在系统中安装 Java Development Kit (JDK) 和/或尚未设置 JAVA_HOME&#xff0c;则在尝试安装 Java CAPS 之前&#xff0c;需要安装 JDK 并设置 JAVA_HOME。以下任务提供了在 UNIX 或 Windows 系统上安装 JDK 和设置 JAVA_HOME 所需的信息。…

MySQL 开启远程访问权限 | 宝塔系统

1.进入 MySQL 管理菜单 2.选择权限为所有人 转载于:https://www.cnblogs.com/Skrillex/p/10728681.html

基于vue实现百度离线地图

基于vue实现百度离线地图 1. 百度地图API文件获取 有网络 的情况下&#xff0c;需引入百度地图API文件。如下&#xff1a; <script type"text/javascript" src"http://api.map.baidu.com/api?v3.0&ak您的密钥"></script> 无网络 的情况下…

日期插件rolldate.js的使用

日期插件rolldate.js的使用 下载地址&#xff1a;http://www.jq22.com/jquery-info19834 效果&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" …

Java8中 Parallel Streams 的陷阱 [译]

转载自https://www.cnblogs.com/imyijie/p/4478074.html Java8 提供了三个我们渴望的重要的功能:Lambdas 、 Stream API、以及接口的默认方法。不过我们很容易滥用它们甚至破坏自己的代码。 今天我们来看看Stream api&#xff0c;尤其是 parallel streams。这篇文章概述了其中的…

ObjectStreamClass:监视Java对象的序列化

ObjectStreamClass可以是有用的类&#xff0c;用于分析JVM中加载的序列化类的序列化特征。 这篇文章介绍了此类提供的有关已加载序列化类的一些信息。 ObjectStreamClass提供了两个用于查找类的静态方法&#xff1a; lookup&#xff08;class&#xff09;和lookupAny&#xff…

00005在java结果输出_Java-005-运算符详解

计算机的最基本用途之一就是执行数学运算,作为一门计算机语言Java也提供了套丰富的运算符来操纵变量, 可以把运算符分成以下几组算术运算符、关系运算符、位运算符、逻辑运算符、赋值运算符、其他运算符。①算术运算符用在数学表达式中它们的作用和在数学中的作用一样 表格中的…

鼠标拖动改变DIV等网页元素的大小的最佳实践

1.初次实现 1.1 html代码 <html xmlns"http://www.w3.org/1999/xhtml" xml:lang"en" lang"en"><head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /><title>div change wid…

[WC2006]水管局长

水管局长 题目链接&#xff1a;https://www.luogu.org/problemnew/show/P4172#sub LCT 显然两个点的路径上的边最大要最小在该图最小生成树上 正删倒加&#xff0c;倒着做变成加边操作 加边时判断一下是否能形成更优的生成树&#xff0c;用LCT删除和连接操作即可 1 #include<…

JDBC 4.0鲜为人知的Clob.free()和Blob.free()方法

在会议上谈论jOOQ时&#xff0c;我总是展示此幻灯片&#xff0c;其中包含许多人们经常犯的非常常见的JDBC错误&#xff1a; 此图中的六个常见的JDBC错误 您可以找到错误吗&#xff1f; 其中一些是显而易见的&#xff0c;例如&#xff1a; 第4行&#xff1a;由于第3行的连接…

反沙箱——SetErrorMode

目录 1.前言 2.原理讲解 3.代码实现 4.参考 1.前言 利用SetErrorMode进行反沙箱的技术&#xff0c;在2010年就有被提出&#xff0c;但是之前搜了很久都没有相关内容&#xff0c;这里简单的说一下这个反沙箱的实现。反沙箱参考GandCrab5.2。 2.原理讲解 首先讲一下SetErrorMode这…

使用MyBatis和Spring构建Java Web应用程序

这篇文章将展示如何在Spring环境中使用带有MyBatis框架的MYSQL DB创建学生注册应用程序。 这是一个简单的应用程序&#xff0c;旨在在注册期间从用户收集输入详细信息&#xff0c;将详细信息保存在MYSQL DB中&#xff0c;并在登录期间对它们进行身份验证。 1.使用Maven模板创建…

codeforces 1136E-Nastya Hasn't Written a Legend

传送门&#xff1a;QAQQAQ 题意&#xff1a;有一个数组a和一个数组k&#xff0c;数组a一直保持一个性质&#xff1a;a[i 1] > a[i] k[i]。有两种操作&#xff1a;1&#xff0c;给某个元素加上x&#xff0c;但是加上之后要保持数组a的性质。比如a[i]加上x之后&#xff0c;a…

将Spring MVC RESTful Web服务迁移到Spring 4

1引言 Spring 4为MVC应用程序带来了一些改进 。 在这篇文章中&#xff0c;我将重点介绍宁静的Web服务&#xff0c;并通过采用Spring 3.2实现的项目并将其升级到Spring 4来尝试这些改进。以下几点总结了本文的内容&#xff1a; 从Spring 3.2迁移到Spring 4.0 变化中的Response…

java scrollpane 设置透明_java swing 之 JScrollPane(滚动面板)的使用

/*** java swing 之JScrollPane面板* 在设置界面时&#xff0c;可能会遇到在一个较小的容器窗体中显示一个较大部分的内容&#xff0c;这时可以使用* JScrollPane面板&#xff0c;JscrollPane面板是带滚动条的面板&#xff0c;也是一种容器&#xff0c;但是常用于布置单个* 控件…

软件工程(2019)第三次个人作业

目录 软件工程第三次作业问题描述分析并设计程序程序流程图选择覆盖标准并设计测试样例软件工程第三次作业 项目地址 问题描述 题目(1)&#xff1a;最大连续子数组和&#xff08;最大子段和&#xff09; 背景 问题&#xff1a; 给定n个整数&#xff08;可能为负数&#xff09;组…

Flutter - 创建侧滑菜单

侧滑菜单在安卓App里面非常常见&#xff0c;比如Gmail&#xff0c;Google Play&#xff0c;Twitter等。看下图 网上也有很多创建侧滑菜单的教程&#xff0c;我也来记录一下&#xff0c;自己学习创建Drawer的过程。 1. 创建一个空的App import package:flutter/material.dart;cl…

java框架白话_Java NIO框架Netty教程(二) 白话概念

"Hello World"的代码固然简单&#xff0c;不过其中的几个重要概念(类)和 Netty的工作原理还是需要简单明确一下&#xff0c;至少知道其是负责什。方便自己以后更灵活的使用和扩展。声明&#xff0c;笔者一介码农&#xff0c;不会那么多专业的词汇和缩写&#xff0c;只…

luogu4770 [NOI2018]你的名字 后缀自动机 + 线段树合并

其实很水的一道题吧.... 题意是&#xff1a;每次给定一个串\(T\)以及\(l, r\)&#xff0c;询问有多少个字符串\(s\)满足&#xff0c;\(s\)是\(T\)的子串&#xff0c;但不是\(S[l .. r]\)的子串 统计\(T\)本质不同的串&#xff0c;建个后缀自动机 然后自然的可以想到&#xff0c…

团队计划会议

跟航哥想了挺多要做什么&#xff0c;要完成什么&#xff0c;以什么为主要功能 提出了几个想法&#xff0c;并做了投票 最后决定一起做一个跑腿软件 最初的任务量&#xff1a; 跟航哥商量两个人一人负责两个模块 航哥负责管理员和下单 我负责接单跟其他琐碎的小功能 呐&#xff…