Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。比如在这里定义了INFO级别,只有等于及高于这个级别的才进行处理,
一、log4j使用步骤(重点在使用过程和初始化):
1.将log4j.jar相关包放到jsp-examplesWEB-INFlib下;
2.在classpath下面建立log4j.properties;
3.完善log4j.properties内容:
- log4j.rootLogger=warn, stdout,A1
- #配置输出到控制台
- log4j.appender.stdout=org.apache.log4j.ConsoleAppender
- log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
- log4j.appender.stdout.layout.ConversionPattern=(%F:%L) - %m%n
- log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
- log4j.appender.A1.layout=org.apache.log4j.HTMLLayout
- log4j.appender.A1.File=${webappHome}/logs/${date}_log.html
- log4j.appender.A1.MaxFileSize= 100KB
具体log4j.properties的配置方法参见http://hi.baidu.com/276668688/blog/item/e8d2fc1fdd8818c1a786698d.html
4.初始化log4j的配置文件:有两种方法
方法一:
a.新建一个初始化类,一般用Servlet或过滤器Log4JInit.java
- package log4j;
- import java.io.*;
- import javax.servlet.*;
- import javax.servlet.http.*;
- import org.apache.log4j.*;
- public class Log4JInit extends HttpServlet {
- public void init() throws ServletException{
- String prefix = getServletContext().getRealPath("/");
- String test = getServletContext().getRealPath("");
- System.out.println(prefix);
- System.out.println(test);
- System.setProperty("webappHome", test);
- String file = getServletConfig().getInitParameter("log4j-config-file");
- System.out.println(prefix+file);
- // 从Servlet参数读取log4j的配置文件
- if (file != null) {
- PropertyConfigurator.configure(prefix + file);
- }
- }
- }
注意:System.setProperty("webappHome", test);”这行代码要出现在“PropertyConfigurator.configure(prefix + file);”这行代码之前;因为这样才给"webappHome"设置值了,log4j.properties文件中的“log4j.appender.A1.file=${webappHome}/logs/tomcat_log_”中的“${webappHome}”这个环境变量才被赋值了,否则无法输出日志文件;
b.配置web.xml文件
- <servlet>
- <servlet-name>log4jinit</servlet-name>
- <servlet-class>log4j.Log4JInit</servlet-class>
- <init-param>
- <param-name> log4j-config-file </param-name>
- <param-value>propertieslog4j.properties</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
注意:上面的load-on-startup应设为1,以便在Web容器启动时即装入该Servlet。log4j.properties文件放在根的properties子目录中,也可以把它放在其它目录中。应该把.properties文件集中存放,这样方便管理。
方法二、使用Spring已经写好的过滤器
a.配置web.xml
- <context-param>
- <param-name>log4jConfigLocation</param-name>
- <param-value>/WEB-INF/config/log4j.properties</param-value>
- </context-param>
- <context-param>
- <param-name>log4jRefreshInterval</param-name>
- <param-value>6000</param-value>
- </context-param>
- <listener>
- <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
- </listener>
5.在webapp中使用log4j
主要建立一个属性private static Logger logger = Logger.getLogger(Log4jTest.class);
public class Hello extends HttpServlet {
private static Logger logger = Logger.getLogger(Hello.class);
@Override
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
System.out.println("Hello world!!");
logger.debug("log4j加载成功!");
}
}
6.在具体使用的时候如果触发了异常,就在生成以日期命名的html日志文件tomcat_log_2007-03-05.html了!
这个日志的格式可以在log4j.properties里面配置.......
====================================================================================================================================================================================================
常用log4j配置
常用log4j配置,一般可以采用两种方式,.properties和.xml,下面举两个简单的例子:
一、 log4j.properties
### 设置org.zblog域对应的级别INFO,DEBUG,WARN,ERROR和输出地A1,A2 ##
log4j.category.org.zblog=ERROR,A1
log4j.category.org.zblog=INFO,A2
log4j.appender.A1=org.apache.log4j.ConsoleAppender
### 设置输出地A1,为ConsoleAppender(控制台) ##
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
### 设置A1的输出布局格式PatterLayout,(可以灵活地指定布局模式)##
log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n
### 配置日志输出的格式##
log4j.appender.A2=org.apache.log4j.RollingFileAppender
### 设置输出地A2到文件(文件大小到达指定尺寸的时候产生一个新的文件)##
log4j.appender.A2.File=E:/study/log4j/zhuwei.html
### 文件位置##
log4j.appender.A2.MaxFileSize=500KB
### 文件大小##
log4j.appender.A2.MaxBackupIndex=1
log4j.appender.A2.layout=org.apache.log4j.HTMLLayout
##指定采用html方式输出
二、 log4j.xml
<?xml version="1.0" encoding="GB2312" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="org.zblog.all" class="org.apache.log4j.RollingFileAppender">
<!-- 设置通道ID:org.zblog.all和输出方式:org.apache.log4j.RollingFileAppender -->
<param name="File" value="E:/study/log4j/all.output.log" /><!-- 设置File参数:日志输出文件名 -->
<param name="Append" value="false" /><!-- 设置是否在重新启动服务时,在原有日志的基础添加新日志 -->
<param name="MaxBackupIndex" value="10" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%p (%c:%L)- %m%n" /><!-- 设置输出文件项目和格式 -->
</layout>
</appender>
<appender name="org.zblog.zcw" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="E:/study/log4j/zhuwei.output.log" />
<param name="Append" value="true" />
<param name="MaxFileSize" value="10240" /> <!-- 设置文件大小 -->
<param name="MaxBackupIndex" value="10" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%p (%c:%L)- %m%n" />
</layout>
</appender>
<logger name="zcw.log"> <!-- 设置域名限制,即zcw.log域及以下的日志均输出到下面对应的通道中 -->
<level value="debug" /><!-- 设置级别 -->
<appender-ref ref="org.zblog.zcw" /><!-- 与前面的通道id相对应 -->
</logger>
<root> <!-- 设置接收所有输出的通道 -->
<appender-ref ref="org.zblog.all" /><!-- 与前面的通道id相对应 -->
</root>
</log4j:configuration>
三、 配置文件加载方法:
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.DOMConfigurator;
public class Log4jApp {
public static void main(String[] args) {
DOMConfigurator.configure("E:/study/log4j/log4j.xml");//加载.xml文件
//PropertyConfigurator.configure("E:/study/log4j/log4j.properties");//加载.properties文件
Logger log=Logger.getLogger("org.zblog.test");
log.info("测试");
}
}
四、 项目使用log4j
在web 应用中,可以将配置文件的加载放在一个单独的servlet中,并在web.xml中配置该servlet在应用启动时候加载。对于在多人项目中,可以给每一个人设置一个输出通道,这样在每个人在构建Logger时,用自己的域名称,让调试信息输出到自己的log文件中。
五、 常用输出格式
# -X号:X信息输出时左对齐;
# %p:日志信息级别
# %d{}:日志信息产生时间
# %c:日志信息所在地(类名)
# %m:产生的日志具体信息
# %n:输出日志信息换行
===============================================================================================
log4j属性含义
2)%t输出当前线程的名称
3)%-5p输出消息的层次。
4)%c 输出category的名称
5)-%m及s是日志消息本身,%n是换行符。
当前在模式字符串中你可以嵌入任何想要输出的字符。
模式字符串中的模式如下:
%m:消息本身
%p:消息的层次
%r:从程序开始执行到当前日志产生时的时间间隔(微秒)
%c:输出当前日志动作所在的category名称。例如:如果category名称是"a.b.c","%c{2}"将会输出"b.c". {2}意谓着输出“以点分隔开的category名称的后两个组件”,如果 {n}没有,将会输出整个category名称.
%t:输出当前线程的名称
%x:输出和当前线程相关联的NDC(具体解释见下文),尤其用到像java servlets这样的多客户多线程的应用中。
%n:输出平台相关的换行符。
%%:输出一个"%"字符
%d:输出日志产生时候的日期,当然可以对日期的格式进行定制。例如:%d{HH:mm:ss,SSSS}或者是%d{dd MMM yyyy HH:mm:ss,SSSS},如果没有指定后面的格式,将会输出ISO8601的格式。
%l:输出位置信息,相当于%C.%M(%F:%L)的组合。
%C:输出日志消息产生时所在的类名,如果类名是“test.page.Class1”%C{1}表示输出类名"Class1",%C{2}输出"page.Class1",而%C则输出"test.page.Class1"。
%M:输出日志消息产生时的方法名称
%F:输出日志消息产生时所在的文件名称
%L:输出代码中的行号
可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如:
1)%20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,默认的情况下右对齐。
2) %-20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,"-"号指定左对齐。
3) %.30c:指定输出category的名称,最大的宽度是30,如果category的名称大于30的话,就会将左边多出的字符截掉,但小于30的话也不会有空格。
4)%20.30c:如果category的名称小于20就补空格,并且右对齐,如果其名称长于30字符,就从左边交远销出的字符截掉。
4)%20.30c:
修改前:
偶们的做法是在action里记录日志,注意这个日志是面向用户的日志,姑且称它为业务日志,至于后台日志,则在此文章中暂不考虑,基本是通过log4j打印到后台日志文件中。看下面一段代码:
2. employeInfoManageService.saveEmploye(vo, authForm.getLoginName());
3.
4. LogVO logVO = new LogVO(Constants.LOG_LEVEL_INFO,
5. Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()
6. + "增加员工成功!");
7. logService.saveLog(logVO);
8. } catch (Exception e) {
9. log.error(e);
10. LogVO logVO = new LogVO(Constants.LOG_LEVEL_ERROR,
11. Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()
12. + "增加员工失败!");
13. try {
14. logService.saveLog(logVO);
15. } catch (Exception e1) {
16. log.error(e1);
17. return messageForward("error", "alert.db.exception",
18. new Object[] {}); }
19. }
这段代码实际上已经将写日志的过程封装起来,开发者只需要传入3个参数:操作者、是前台系统还是后台系统、以及日志的错误等级,其它的如操作者机器IP, 日志时间等信息由系统统一设定,即使是这样,如果一个action里面有多个操作,代码看起来也非常臃肿,而且给开发者增加了工作量,既然有了aop,为 什么不利用一下?看下面改造的代码:
2. Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()
3. + "增加员工");
4. try {
5. employeInfoManageService.saveEmploye(vo, authForm.getLoginName(), logVO);
6. } catch (Exception e) {
7. log.error(e);
8. return messageForward("error", "alert.db.exception",
9. new Object[] {});
10. }
2. <aop:advisor pointcut="execution(* *..*Service.*(..))" advice-ref="txAdvice"/>
3. <aop:advisor pointcut="execution(* *..*Service.save*(..)) || execution(* *..*Service.update*(..)) || execution(* *..*Service.delete*(..))" advice-ref="logAfterAdvice"/>
4. </aop:config>
5.
6. <bean id="logAfterAdvice" class="com.fudannet.framework.aop.LogAfterAdvice"/>
2. Object targetObj) throws Throwable {
3. if(method.getName().equals("saveLog")) return;
4. for(int i = 0; i < args.length; i++){
5. if(args[i] instanceof LogVO){
6. log.info("开始写入日志......");
7. writeLog((LogVO)args[i]);
8. }
9. }
10. }
11.
12. private void writeLog(LogVO vo){
13. try {
14. vo.setDescription(vo.getDescription() + "成功!");
15. logService.saveLog(vo);
16. } catch (RuntimeException e) {
17. log.error(e);
18. }
19.
20. public void setLogService(LogService logService) {
21. this.logService = logService;
22. }
这段代码应该很清楚了,将logService注入到拦截log的advice里,进行正确操作的日志记录,而afterReturning方法里 的第一行判断是由于logService里的写日志的方法是以save开始的。所以,如果拦截器拦截到此方法,不需要记录日志。
正确的日志记录完,当然如果发生异常,我们需要记录操作的失败日志,当然了,我们也是通过aop来做,但是这次是通过实现exception advice来实现,代码如下:
2. if(method.getName().equals("saveLog")) return;
3. for(int i = 0; i < args.length; i++){
4. if(args[i] instanceof LogVO){
5. log.info开始写入日志......");
6. writeLog((LogVO)args[i]);
7. }
8. }
9. }
10.
11. private void writeLog(LogVO vo){
12. try {
13. vo.setDescription(vo.getDescription() + "失败!");
14. logThrowService.saveLog(vo);
15. } catch (RuntimeException e) {
16. log.error(e);
17. }
18. }
19.
20. public void setLogThrowService(LogService logThrowService) {
21. this.logThrowService = logThrowService;
22. }
2. log.info("......");
3. //do something
4. }
--------------------------------------------------------------------------------
其中的封装方式虽然一般,但是还是比较好的解决了问题!对于LogVO类我们可以把他继续扩展下去,比如设定访问用户,IP,seq文等.
Spring AOP与log4j做简单的异常日志处理
1.在网上看了不少例子,下面自己实践了一下。由于系统开发的时候忘记了对异常的日志处理,所以现在考虑加上,经过考虑决定使用spring的aop与log4j来做,这样做的好处就是我不用在每个类里面try{}catch或者抛出异常。因为类已经写了好多好多了。要是一个一个弄工作量是很大的 。
下面说下简单的实现过程,首先啊,在项目工程中的src目录中加入log4j.properties,内容如下:
###设置日志级别###
###这部分是将info信息输出到控制台###
log4j.rootLogger = info,stdout,F
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{1}:%L - %m%n
###错误日志配置###
log4j.appender.F = org.apache.log4j.DailyRollingFileAppender
##输出格式为自定义的HTML##
log4j.appender.F.layout = com.yale.sys.log.FormatHTMLLayout
log4j.appender.F.Threshold = ERROR
log4j.appender.F.Append=true
##错误文件存放位置##
log4j.appender.F.File=error.html
##每天滚动一次文件,即每天产生一个新的文件,文件名字eg:error.html.2012-06-18.html##
log4j.appender.F.DatePattern='.'yyyy-MM-dd'.html'
-------------------------------耐心的看下去 -----------------------------------
其次呢,看上面红色那部分,因为是要将输出日志信息存储到html文件中,所以重写了下log4j中HTMLLayout类,代码片段:
- package com.yale.sys.log;
- import java.text.SimpleDateFormat;
- import org.apache.log4j.HTMLLayout;
- import org.apache.log4j.Layout;
- import org.apache.log4j.Level;
- import org.apache.log4j.helpers.Transform;
- import org.apache.log4j.spi.LocationInfo;
- import org.apache.log4j.spi.LoggingEvent;
- /**
- * log4j输出到html格式重写
- * @author yale
- *
- */
- public class FormatHTMLLayout extends HTMLLayout {
- public FormatHTMLLayout() {
- }
- [/size]
- protected final int BUF_SIZE = 256;
- protected final int MAX_CAPACITY = 1024;
- static String TRACE_PREFIX = "<br> ";
- // output buffer appended to when format() is invoked
- private StringBuffer sbuf = new StringBuffer(BUF_SIZE);
- String title="系统错误日志";
- /**
- * A string constant used in naming the option for setting the the HTML
- * document title. Current value of this string constant is <b>Title</b>.
- */
- public static final String TITLE_OPTION = "Title";
- // Print no location info by default
- boolean locationInfo = true;
- public String format(LoggingEvent event) {
- if (sbuf.capacity() > MAX_CAPACITY) {
- sbuf = new StringBuffer(BUF_SIZE);
- } else {
- sbuf.setLength(0);
- }
- sbuf.append(Layout.LINE_SEP + "<tr>" + Layout.LINE_SEP);
- sbuf.append("<td>");
- sbuf.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date()));
- sbuf.append("</td>" + Layout.LINE_SEP);
- sbuf.append("<td title="级别">");
- if (event.getLevel().equals(Level.FATAL)) {
- sbuf.append("<font color="#339933">");
- sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
- sbuf.append("</font>");
- } else if (event.getLevel().isGreaterOrEqual(Level.WARN)) {
- sbuf.append("<font color="#993300"><strong>");
- sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
- sbuf.append("</strong></font>");
- } else {
- sbuf.append("<font color="green">");
- sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
- sbuf.append("</font>");
- }
- sbuf.append("</td>" + Layout.LINE_SEP);
- if (locationInfo) {
- LocationInfo locInfo = event.getLocationInformation();
- sbuf.append("<td title="错误">");
- sbuf.append("<font color="red">");
- sbuf.append(Transform.escapeTags(locInfo.getFileName()));
- sbuf.append(':');
- sbuf.append(locInfo.getMethodName()).append("()方法中第");
- sbuf.append(locInfo.getLineNumber()).append("行出现错误");
- sbuf.append("</font>");
- sbuf.append("</td>" + Layout.LINE_SEP);
- }
- sbuf.append("<td title="错误信息">");
- sbuf.append(Transform.escapeTags(event.getRenderedMessage()));
- sbuf.append("</td>" + Layout.LINE_SEP);
- sbuf.append("</tr>" + Layout.LINE_SEP);
- if (event.getNDC() != null) {
- sbuf.append("<tr><td bgcolor="#EEEEEE" style="font-size : xx-small;" colspan="6" title="Nested Diagnostic Context">");
- sbuf.append("NDC: " + Transform.escapeTags(event.getNDC()));
- sbuf.append("</td></tr>" + Layout.LINE_SEP);
- }
- String[] s = event.getThrowableStrRep();
- if (s != null) {
- sbuf.append("<tr><td bgcolor="#993300" style="color:White; font-size : xx-small;" colspan="4">");
- appendThrowableAsHTML(s, sbuf);
- sbuf.append("</td></tr>" + Layout.LINE_SEP);
- }
- return sbuf.toString();
- }
- private void appendThrowableAsHTML(String[] s, StringBuffer sbuf) {
- if (s != null) {
- int len = s.length;
- if (len == 0)
- return;
- sbuf.append(Transform.escapeTags(s[0]));
- sbuf.append(Layout.LINE_SEP);
- for (int i = 1; i < len; i++) {
- sbuf.append(TRACE_PREFIX);
- sbuf.append(Transform.escapeTags(s[i]));
- sbuf.append(Layout.LINE_SEP);
- }
- }
- }
- /**
- * Returns appropriate HTML headers.
- */
- public String getHeader() {
- sbuf.append("<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">" + Layout.LINE_SEP);
- sbuf.append("<html>" + Layout.LINE_SEP);
- sbuf.append("<head>" + Layout.LINE_SEP);
- sbuf.append("<title>" + title + "</title>" + Layout.LINE_SEP);
- sbuf.append("<style type="text/css">" + Layout.LINE_SEP);
- sbuf.append("<!--" + Layout.LINE_SEP);
- sbuf.append("body, table {font-family: '宋体',arial,sans-serif; font-size: 12px;}" + Layout.LINE_SEP);
- sbuf.append("th {background: #336699; color: #FFFFFF; text-align: left;}" + Layout.LINE_SEP);
- sbuf.append("-->" + Layout.LINE_SEP);
- sbuf.append("</style>" + Layout.LINE_SEP);
- sbuf.append("</head>" + Layout.LINE_SEP);
- sbuf.append("<body bgcolor="#FFFFFF" topmargin="6" leftmargin="6">" + Layout.LINE_SEP);
- sbuf.append("<table cellspacing="0" cellpadding="4" border="1" bordercolor="#224466" width="100%">" + Layout.LINE_SEP);
- sbuf.append("<tr>" + Layout.LINE_SEP);
- sbuf.append("<th>执行时间</th>" + Layout.LINE_SEP);
- sbuf.append("<th>级别</th>" + Layout.LINE_SEP);
- if (locationInfo) {
- sbuf.append("<th>所在行</th>" + Layout.LINE_SEP);
- }
- sbuf.append("<th>错误信息</th>" + Layout.LINE_SEP);
- sbuf.append("</tr>" + Layout.LINE_SEP);
- sbuf.append("<br></br>" + Layout.LINE_SEP);
- return sbuf.toString();
- }
- }
----------------------------耐心点往下看,就要没了 --------------------------------------------------
再来就是错误文件error.html的存储位置,想要放在项目的WebRoot下,于是就写了个servlet,代码片段:
- package com.yale.sys.log;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.Properties;
- import javax.servlet.Servlet;
- import javax.servlet.ServletConfig;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import org.apache.log4j.PropertyConfigurator;
- /**
- * 初始化日志错误文件存放的路径
- */
- public class LogFileSavePathServlet extends HttpServlet {
- private static final long serialVersionUID = 1L;
- /**
- * @see HttpServlet#HttpServlet()
- */
- public LogFileSavePathServlet() {
- super();
- // TODO Auto-generated constructor stub
- }
- /**
- * @see Servlet#init(ServletConfig)
- */
- public void init() throws ServletException {
- //获得系统的路径 /WebRoot
- String rootPath = this.getServletContext().getRealPath("/");
- //获得log4j.properties的输入流
- InputStream is =this.getClass().getClassLoader().getResourceAsStream("log4j.properties");
- Properties prop = new Properties();
- try {
- prop.load(is);
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- //设置日志文件的输出路径
- prop.setProperty("log4j.appender.F.File",rootPath+prop.getProperty("log4j.appender.F.File"));
- prop.setProperty("log4j.appender.F.DatePattern",rootPath+prop.getProperty("log4j.appender.F.DatePattern"));
- //加载配置项
- PropertyConfigurator.configure(prop);
- super.init();
- }
- }
注意啦,错误文件存储的路径不允许空格上面乱码七糟的,一定要注意哦。
写完这个servlet,我们不能忘记初始化,您说对不对啊,所以啊,web.xml就像下面这个样子了:
- <!DOCTYPE web-app PUBLIC
- "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
- "http://java.sun.com/dtd/web-app_2_3.dtd" >
- <web-app>
- <!-- 日志文件存储路径初始化-->
- <servlet>
- <servlet-name>LogFileSavePathServlet</servlet-name>
- <display-name>LogFileSavePathServlet</display-name>
- <description></description>
- <servlet-class>com.peoplespot.sys.log.LogFileSavePathServlet</servlet-class>
- <load-on-startup>0</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>LogFileSavePathServlet</servlet-name>
- <url-pattern>/LogFileSavePathServlet</url-pattern>
- </servlet-mapping>
- </web-app>
--------------------------------下面就开始和spring aop相关啦,看吧,看吧-----------------------
再一次首先,写一个系统异常日志拦截器类,您看:
- package com.yale.sys.log;
- import org.apache.log4j.Logger;
- import org.aspectj.lang.ProceedingJoinPoint;
- /**
- * 系统异常日志拦截器
- * @author yale
- *
- */
- public class LogInterceptor {
- static Logger logger = Logger.getLogger(LogInterceptor.class);
- public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {
- StringBuffer sb = new StringBuffer();
- try{
- Object result = joinPoint.proceed();
- return result;
- }catch(Exception e){
- sb.append("开始方法:"+joinPoint.getTarget().getClass() + "." + joinPoint.getSignature().getName()+ "() ");
- sb.append("错误信息如下:["+e.getMessage()+"]");
- logger.error(sb.toString());
- }
- return "error";//因为用到了strut2,所以出现异常会返回到<result name="error">/erreo.jsp</result>这个页面中,当然啦,你也可以配置成全局的异常返回页。
- }
- }
上面这个类,主要用到了aspectj中的ProceedingJoinPoint,支持的是<aop:around />。
类写完了,但是spring配置文件applicationContext.xml还没有搞啊,所以搞一下:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
- <!-- 配置日志拦截器 -->
- <bean id="logInterceptor" class="com.yale.sys.log.LogInterceptor"></bean>
- <aop:config proxy-target-class="true">
- <aop:aspect id="logAspectSYS" ref="logInterceptor">
- <aop:around method="invoke" pointcut="execution(public * com.yale.live.action..*.*(..))" />
- </aop:aspect>
- <aop:aspect id="logAspectDNA" ref="logInterceptor">
- <aop:around method="invoke" pointcut="execution(public * com.yale.sys.action..*.*(..))" />
- </aop:aspect>
- </aop:config>
- </beans>
小插曲:看见<aop:config>节点中proxy-target-class="true"这个属性了吧,当我不加的时候,启动项目,访问action代码,就比如是LoginAction中的login()方法,不幸的是他报错了,类似于
java.lang.NoSuchMethodException: $Proxy54.login(),可是回去一看,有写过这个login方法啊, $Proxy54又是怎么回事呢?因为你加入aop功能了,可是spring是这么干的,默认啊实现的是接口注入,关联的实现类。这里实现注入类,所以出现了异常。要怎么解决呢,于是就要加上proxy-target-class="true"属性,接下来启动项目吧,你会发现不幸的事情又发生了,又报错了:
org.springframework.aop.framework.AopConfigException: Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces.
提示的很明显,少jar包了,所以就加吧,但是加jar的时候也要注意了:
需要导入的jar包是cglib-nodep-2.1_3.jar(这里面整合了asm)或者(asm-2.2.3.jar和cglib-2.2.jar 。)因为cglib需要asm的支持。
到此完成。
启动项目开始运行吧,模拟了下一个异常,输出到html最终这样啦: