(本章主要讲解Java里面比较核心的一块内容——异常处理,Java异常处理机制,一致都是比较复杂的一块,而很多时候如果写程序的时候能够适当地注意对应的一些异常处理情况,那么就会在开发过程节省一大部分时间,最常见的情况就是辅助进行调试以及维护工作以及提高系统的容错性和稳定性。这一章和前边类和对象章节不一样,这一章可能涵盖的内容没有前边那章多,但是我会尽量保证在整篇文章里面把开发过程中需要注意到的与异常有关的细节问题以及对应的开发经验写入本文,而本章的出发点是异常处理,核心内容还涵盖了测试、调试、以及部署等相关内容以及。如果有笔误的地方,请来Email指点:silentbalanceyh@126.com,谢谢)
本章目录
1.Java异常处理
2.异常处理心得
3.断言的使用
4.Java中的日志(JDK1.4 Logging Framework)
5.第三方日志库(Log4j、Commons Logging Framework)
5.第三方日志库(Log4j,Commons Logging Framework)
前边介绍了官方的日志框架JDK 1.4 Logging Framework,接下来介绍两个第三方的日志框架Log4j和Commons Logging Framework,这三个日志框架也是整个Java界使用最多的日志框架。
下载地址:【直接复制就可下载】
http://labs.xiaonei.com/apache-mirror/logging/log4j/1.2.15/apache-log4j-1.2.15.zip
http://apache.etoak.com/logging/log4j/1.2.15/apache-log4j-1.2.15.zip
i.Log4j:
1)基本简介:
Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。 此外,通过Log4j其他语言接口,您可以在C、C++、.Net、PL/SQL程序中使用Log4j,其语法和用法与在Java程序中一样,使得多语言分布式系统得到一个统一一致的日志组件模块。而且,通过使用各种第三方扩展,您可以很方便地将Log4j集成到J2EE、JINI甚至是SNMP应用中。
整体上讲,Log4j中有三个最主要的核心组件:Logger、Appender和Layout,不仅仅如此,它同样允许开发人员自定义多个Logger,每个Logger有自己的名字,Logger之间通过名字来表示隶属关系。但是有一个Logger称为Root,这个Logger不能通过名字来检索,但是可以直接使用Logger.getRootLogger()获取,其他的Logger都可以使用Logger.getLogger(String name)方法获取
Logger:
在执行应用程序时,接收日志语句生成的日志请求。它是一种重要的日志处理组件, 可以通过 log4j API 的 logger 类对其进行访问。它的方法有:debug、info、warn、error、fatal 和 log。这些方法用于记录消息。
Appender:
管理日志语句的输出结果。执行日志语句时,Logger 对象将接收来自日志语句的记录请求。此请求是通过 logger 发送至 appender 的。然后,Appender 将输出结果写入到用户选择的目的地。对于不同的日志目的地,提供不同的 appender 类型。这些 appender 包括:用于文件的 file appender、用于数据库的 JDBC appender 和用于 SMTP 服务器的 SMTP appender。
Layout:
Layout:
用于指定 appender 将日志语句写入日志目的地所采用的格式。appender 可以用来格式化输出结果的各种布局包括:简单布局、模式布局和 HTML 布局。
org.apache.log4j.config:用来设置或者获取某些组件的相关属性
从上图可以知道,只有当日志记录器Logger的日志级别高于或者等于输出消息的等级的时候,该日志消息才会被输出。默认情况下,Logger的级别是Debug,如果我们需要创建一个Logger,有以下几种方式:
[1]先看看Log4j的包目录结构:
org.apache.log4j:log4j主要的类、接口以及特殊的Appender类、Layout、Level和Logger
org.apache.log4j.spi:包含了针对SPI的一部分扩展【SPI——System Programming Interface】
org.apache.log4j.chainsaw:基于Java Swing的一个GUI日志查看器:
org.apache.log4j.helpers:仅仅被log4j库内联使用的多个Class的集合,一般情况下不对外
org.apache.log4j.jdbc:一个Appender用来记录JDBC连接的相关事件
org.apache.log4j.jmx:在JMX开发的时候可以配置的基于JMX的日志记录,但是目前该包里面的类还不是特别稳定
org.apache.log4j.lf5:【目前很少用,我也不知道这部分用途,没用过】
org.apache.log4j.net:用来进行远程日志记录的Appender,主要用于JMS、SMTP以及基于Socket的日志记录,用于向一个log4j服务器发送日志进行远程的日志记录
org.apache.log4j.nt:Java本地接口的应用【JNI】,接口用Java,实现用C代码,用来记录Windows NT系统事件日志的Appender组件
org.apache.log4j.or:根据对象类型来对对象进行Render操作的帮助类
org.apache.log4j.performance:性能测试代码
org.apache.log4j.xml:包含了多个XML组件,使用DOM Tree的结构在Log4j环境里面用来记录XML格式的日志
org.apache.log4j.varia:包含了多个Appender以及Filters和其他相关组件
[2]Log4j的安装:
Log4j下载下来过后需要进行简单的安装,先保证原来的系统环境和Java环境是正常的:
- 下载log4j的jar包,上边已经提供了下载地址
- 将这些包解压到一个目录里面,【*:一般对于开发人员最好将jar的包分类放在不同的目录下边方便使用。】
- 将包下边的log4j-1.2.15.jar放入开发的CLASSPATH里面,关于Java里面CLASSPATH的一些问题留到开发用Java里面去讲解
- 还需要下载两个辅助解析XML的jar,下载地址http://archive.apache.org/dist/xml/xerces-j/,这里我下载的最新版本2.9.0,取出里面的xercesImpl.jar和xml-apis.jar两个jar文件放到CLASSPATH里面。【*:在IDE环境下有专程针对CLASSPATH的设置,这种情况防止jar冲突最好的方式就是保持CLASSPATH里面只有java标准的环境】
2)Log4j的核心概念:
[1]Log4j中的Logger:
Logger在Log4j中是一个很核心的概念,它是日志进程里面的核心组件,在Log4j里面,Logger总共分为六个日志记录级别,其定义位于org.apache.log4j.Level类里:
- TRACE:这种细粒度信息时间不仅仅针对调试,
- DEBUG:指出细粒度信息事件对调试应用程序是非常有帮助的,该级别的日志主要用于辅助开发人员调试;
- INFO:该级别表明消息上细粒度上突出强调了应用程序的运行过程
- WARN:表明有可能会出现潜在错误的情形
- ERROR:表明虽然程序发生了错误事件,但是仍然不影响系统的继续运行
- FATAL:该级别表明了每个严重的错误时间,将会导致应用程序的退出。
根据API里面的描述还存在两个很特殊的级别:
- ALL:这是最低级别,用于打开所有的日志记录
- OFF:这是最高级别,用于关闭所有的日志记录
一般情况下,推荐开发过程只使用ERROR、WARN、INFO、DEBUG四个级别,下图说明了这几个级别相互之间的关系:
创建根日志器:
Logger logger = Logger.getRootLogger();
创建一个新的日志器:
Logger logger =newLogger("MyLogger");
创建一个基于类的日志器:
Logger logger =newLogger(MyClass.class);
在Log4j里面设置一个日志的级别使用语句:
logger.setLevel(Level.DEBUG);
【*:在1.2版本之前,Log4j里面没有使用Logger类,主要是使用Category类,从版本1.2开始才使用Logger类,就上边的方式创建Logger】
这里先看一段代码,然后对Category进行一个详细说明,实际上从版本1.2开始Category和Logger是父子关系,Logger从Category类继承而来;在该版本之前我们一般使用Category来创建日志记录器,在前边的版本里面Category就等同于现在我们所见到的Logger。在版本1.2中,Category被标记为deprecated,而直接使用Logger替代它,一般情况下Java里面被标记为deprecated的方法和类都有替代方法以及类来进行对应功能的版本更新,我们一般在开发过程中尽量避免使用标记为deprecated的类或者方法。下边的代码是升级的改动:
// 被抛弃的代码形式:
Category cat = Category.getInstance("foo.bar");
// 目前使用的创建Logger的形式:
Logger logger = Logger.getInstance("foo.bar");
为了使得上边的图形里面的内容更加容易理解,这里提供另外一段代码:
packageorg.susan.java.logging;
importorg.apache.log4j.Level;
importorg.apache.log4j.Logger;
classFoo{}
public classLog4jLevelTester {
public static voidmain(Stringargs[]){
Logger logger = Logger.getLogger(Foo.class);
logger.setLevel(Level.INFO);
// 该请求是被允许的,因为WARN >= INFO
logger.warn("Low fuel level.");
// 该请求时背禁止的,因为DEBUG < INFO
logger.debug("Starting search for nearest gas station.");
}
}
上边这段代码很好说明了logger在对待LEVEL的时候的用法,在setLevel的时候Logger设置了日志器本身的Level,然后在使用里面对应的warn、debug方法的时候会判断使用的方法和日志记录器设置的Level进行详细的比较,当满足上边图示的判断条件的时候才会输出日志信息。在这里还有一点需要注意的是方法warn和debug,这两个方法都不是Logger类所具有的方法,而是从它的父类继承过来的Category的方法,在使该方法的时候会针对我们最初设置的日志的Level进行一个比较和判断,最终决定是否要被记录下来。那么在环境配置好的情况下,我们执行该程序。
【异常】这里会遇到一个初学Log4j的常见问题,我们会发现控制台只有这句话输出:
log4j:WARN No appenders could be found for logger (org.susan.java.logging.Foo).
log4j:WARN Please initialize the log4j system properly.
这句话的意思是在系统环境里面没有找到我们所需要的配置文件,一般理解是缺乏log4j.properties属性文件,在此处,如果我们不使用配置文件的方式就将下边的代码修改成:
packageorg.susan.java.logging;
importorg.apache.log4j.BasicConfigurator;
importorg.apache.log4j.Level;
importorg.apache.log4j.Logger;
classFoo{}
public classLog4jLevelTester {
public static voidmain(Stringargs[]){
BasicConfigurator.configure();
Logger logger = Logger.getLogger(Foo.class);
logger.setLevel(Level.INFO);
// 该请求是被允许的,因为WARN >= INFO
logger.warn("Low fuel level.");
// 该请求时背禁止的,因为DEBUG < INFO
logger.debug("Starting search for nearest gas station.");
}
}
修改成上边这段代码过后,我们就可以直接在没有log4j.properties配置文件的情况下直接运行上边的程序,该代码将会有以下输出:
0 [main] WARN org.susan.java.logging.Foo - Low fuel level.
通过这里我们就可以知道Log4j里面的Level的排序为:DEBUG < INFO < WARN < ERROR < FATAL,等到后边再来分析上边的代码如果不使用BasicConfigurator.configure();而是使用我们开发常用的属性文件log4j.properties
进行日志记录的相关配置,关于配置文件的详细内容等介绍完Layout和Appender了过后再说明。
[2]Log4j中的Appender:
[2]Log4j中的Appender:
Log4j里面的Appender类似于JDK 1.4 Logging Framework里面的Handler组件,其主要目的是管理我们日志记录的结果,描述了这些日志怎样进行输出,下边列举了比较常用的一些Appender的快照:
- ConsoleAppender:这种Appender会管理我们的日志消息,将日志事件记录到控制台以System.out或者System.err作为输出机制,它默认的输出为System.out;
- RollingFileAppender:这种Appender从FileAppender继承过来,大部分属性和FileAppender是类似的,当日志记录的文件到达文件容量的最大值的时候,会自动创建一个新的日志文件
- FileAppender:将日志输出到普通文本文件【这里有点需要说明,好像从版本1.2开始该Appender将会标记为禁用,替代的方案为该类的类:WriterAppender和ConsoleAppender】
- DailyRollingFileAppender:该Appender从FileAppender继承而来,能够按照一定的频度滚动日志记录文件
- WriterAppender:根据用户的选择将日志的信息以数据流的方式发送到任何用户指定的地方
- SMTPAppender:在特殊的事件日志发生的时候,发送一封Email到指定的邮件地址,一般情况下是针对ERROR级别以及FATAL级别的错误进行这种Appender的配置
- SocketAppender:将发送一个LoggingEvent对象到一个远程的日志服务器,一般情况下是一个SocketNode对象
- SocketHubAppender:将发送一个LoggingEvent对象的集合到一个远程的日志服务器,一般情况下是一个SocketNodes
- SyslogAppender:将日志记录消息发送到配置好的一个syslog远程服务器上
- TelnetAppender:该Appender和SocketHubAppender类似,也是向服务器发送日志信息,但是不是一个SocketNode对象或者SocketNode对象列,一般发送的是Category【1.1版】输出的结果。
整个org.apache.log4j包结构里面,Appender的结构图如下:[I]标识接口,[A]标识抽象类,[C]标识具体类
接口:
Appender[I]
类层次结构:
AppenderSkeleton[A]
|—AsyncAppender[C]
|—org.apache.log4j.jdbc.JDBCAppender[C]
|—org.apache.log4j.net.JMSAppender[C]
|—org.apache.log4j.lf5.LF5Appender[C]
|—org.apache.log4j.nt.NTEventAppender[C]
|—org.apache.log4j.varia.NullAppender[C]
|—org.apache.log4j.net.SMTPAppender[C]
|—org.apache.log4j.net.SocketAppender[C]
|—org.apache.log4j.net.SocketHubAppender[C]
|—org.apache.log4j.net.SyslogAppender[C]
|—org.apache.log4j.net.TelnetAppender[C]
|—WriterAppender[C]
|—ConsoleAppender[C]
|—FileAppender[C]
|—RollingFileAppender[C]
|—org.apache.log4j.varia.ExternallyRolledFileAppender[C]
|—DailyRollingFileAppender[C]