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类,代码片段:
Java代码   收藏代码
  1. package com.yale.sys.log;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import org.apache.log4j.HTMLLayout;  
  5. import org.apache.log4j.Layout;  
  6. import org.apache.log4j.Level;  
  7. import org.apache.log4j.helpers.Transform;  
  8. import org.apache.log4j.spi.LocationInfo;  
  9. import org.apache.log4j.spi.LoggingEvent;  
  10. /** 
  11.  * log4j输出到html格式重写 
  12.  * @author yale 
  13.  * 
  14.  */  
  15. public class FormatHTMLLayout extends HTMLLayout {     
  16.         
  17.     public FormatHTMLLayout() {     
  18.     }     
  19. [/size]    
  20.     protected final int BUF_SIZE = 256;     
  21.     
  22.     protected final int MAX_CAPACITY = 1024;     
  23.     
  24.     static String TRACE_PREFIX = "<br>&nbsp;&nbsp;&nbsp;&nbsp;";     
  25.     
  26.     // output buffer appended to when format() is invoked     
  27.     private StringBuffer sbuf = new StringBuffer(BUF_SIZE);     
  28.          
  29.     String title="系统错误日志";     
  30.     
  31.     /**   
  32.      * A string constant used in naming the option for setting the the HTML   
  33.      * document title. Current value of this string constant is <b>Title</b>.   
  34.      */    
  35.     public static final String TITLE_OPTION = "Title";     
  36.     
  37.     // Print no location info by default     
  38.     boolean locationInfo = true;     
  39.          
  40.     public String format(LoggingEvent event) {     
  41.         if (sbuf.capacity() > MAX_CAPACITY) {     
  42.             sbuf = new StringBuffer(BUF_SIZE);     
  43.         } else {     
  44.             sbuf.setLength(0);     
  45.         }     
  46.         sbuf.append(Layout.LINE_SEP + "<tr>" + Layout.LINE_SEP);     
  47.              
  48.      
  49.         sbuf.append("<td>");     
  50.         sbuf.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date()));     
  51.         sbuf.append("</td>" + Layout.LINE_SEP);     
  52.     
  53.    
  54.         sbuf.append("<td title=\"级别\">");     
  55.         if (event.getLevel().equals(Level.FATAL)) {     
  56.             sbuf.append("<font color=\"#339933\">");     
  57.             sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));     
  58.             sbuf.append("</font>");     
  59.         } else if (event.getLevel().isGreaterOrEqual(Level.WARN)) {     
  60.             sbuf.append("<font color=\"#993300\"><strong>");     
  61.             sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));     
  62.             sbuf.append("</strong></font>");     
  63.         } else {     
  64.             sbuf.append("<font color=\"green\">");     
  65.             sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));     
  66.             sbuf.append("</font>");     
  67.         }     
  68.         sbuf.append("</td>" + Layout.LINE_SEP);     
  69.              
  70.   
  71.         if (locationInfo) {     
  72.             LocationInfo locInfo = event.getLocationInformation();     
  73.             sbuf.append("<td title=\"错误\">");   
  74.             sbuf.append("<font color=\"red\">");   
  75.             sbuf.append(Transform.escapeTags(locInfo.getFileName()));    
  76.             sbuf.append(':');    
  77.             sbuf.append(locInfo.getMethodName()).append("()方法中第");  
  78.             sbuf.append(locInfo.getLineNumber()).append("行出现错误");   
  79.             sbuf.append("</font>");   
  80.             sbuf.append("</td>" + Layout.LINE_SEP);    
  81.         }    
  82.             
  83.             
  84.   
  85.             
  86.         sbuf.append("<td title=\"错误信息\">");     
  87.         sbuf.append(Transform.escapeTags(event.getRenderedMessage()));     
  88.         sbuf.append("</td>" + Layout.LINE_SEP);     
  89.         sbuf.append("</tr>" + Layout.LINE_SEP);     
  90.     
  91.         if (event.getNDC() != null) {     
  92.             sbuf.append("<tr><td bgcolor=\"#EEEEEE\" style=\"font-size : xx-small;\" colspan=\"6\" title=\"Nested Diagnostic Context\">");     
  93.             sbuf.append("NDC: " + Transform.escapeTags(event.getNDC()));     
  94.             sbuf.append("</td></tr>" + Layout.LINE_SEP);     
  95.         }     
  96.     
  97.         String[] s = event.getThrowableStrRep();     
  98.         if (s != null) {     
  99.             sbuf.append("<tr><td bgcolor=\"#993300\" style=\"color:White; font-size : xx-small;\" colspan=\"4\">");     
  100.             appendThrowableAsHTML(s, sbuf);     
  101.             sbuf.append("</td></tr>" + Layout.LINE_SEP);     
  102.         }     
  103.         return sbuf.toString();     
  104.     }     
  105.     
  106.     private void appendThrowableAsHTML(String[] s, StringBuffer sbuf) {     
  107.         if (s != null) {     
  108.             int len = s.length;     
  109.             if (len == 0)     
  110.                 return;     
  111.             sbuf.append(Transform.escapeTags(s[0]));     
  112.             sbuf.append(Layout.LINE_SEP);     
  113.             for (int i = 1; i < len; i++) {     
  114.                 sbuf.append(TRACE_PREFIX);     
  115.                 sbuf.append(Transform.escapeTags(s[i]));     
  116.                 sbuf.append(Layout.LINE_SEP);     
  117.             }     
  118.         }     
  119.     }     
  120.     
  121.     /**   
  122.      * Returns appropriate HTML headers.   
  123.      */    
  124.     public String getHeader() {     
  125.         sbuf.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">" + Layout.LINE_SEP);     
  126.         sbuf.append("<html>" + Layout.LINE_SEP);     
  127.         sbuf.append("<head>" + Layout.LINE_SEP);     
  128.         sbuf.append("<title>" + title + "</title>" + Layout.LINE_SEP);     
  129.         sbuf.append("<style type=\"text/css\">" + Layout.LINE_SEP);     
  130.         sbuf.append("<!--" + Layout.LINE_SEP);     
  131.         sbuf.append("body, table {font-family: '宋体',arial,sans-serif; font-size: 12px;}" + Layout.LINE_SEP);     
  132.         sbuf.append("th {background: #336699; color: #FFFFFF; text-align: left;}" + Layout.LINE_SEP);     
  133.         sbuf.append("-->" + Layout.LINE_SEP);     
  134.         sbuf.append("</style>" + Layout.LINE_SEP);     
  135.         sbuf.append("</head>" + Layout.LINE_SEP);     
  136.         sbuf.append("<body bgcolor=\"#FFFFFF\" topmargin=\"6\" leftmargin=\"6\">" + Layout.LINE_SEP);     
  137.         sbuf.append("<table cellspacing=\"0\" cellpadding=\"4\" border=\"1\" bordercolor=\"#224466\" width=\"100%\">" + Layout.LINE_SEP);     
  138.         sbuf.append("<tr>" + Layout.LINE_SEP);     
  139.         sbuf.append("<th>执行时间</th>" + Layout.LINE_SEP);     
  140.         sbuf.append("<th>级别</th>" + Layout.LINE_SEP);     
  141.         if (locationInfo) {     
  142.             sbuf.append("<th>所在行</th>" + Layout.LINE_SEP);     
  143.         }     
  144.         sbuf.append("<th>错误信息</th>" + Layout.LINE_SEP);     
  145.         sbuf.append("</tr>" + Layout.LINE_SEP);     
  146.         sbuf.append("<br></br>" + Layout.LINE_SEP);     
  147.         return sbuf.toString();     
  148.     }     
  149.     
  150. }   

----------------------------耐心点往下看,就要没了 --------------------------------------------------
再来就是错误文件error.html的存储位置,想要放在项目的WebRoot下,于是就写了个servlet,代码片段:
Java代码   收藏代码
  1. package com.yale.sys.log;  
  2. import java.io.FileNotFoundException;  
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. import java.util.Properties;  
  6.   
  7. import javax.servlet.Servlet;  
  8. import javax.servlet.ServletConfig;  
  9. import javax.servlet.ServletException;  
  10. import javax.servlet.http.HttpServlet;  
  11.   
  12.   
  13. import org.apache.log4j.PropertyConfigurator;  
  14.   
  15. /** 
  16.  * 初始化日志错误文件存放的路径 
  17.  */  
  18. public class LogFileSavePathServlet extends HttpServlet {  
  19.     private static final long serialVersionUID = 1L;  
  20.          
  21.     /** 
  22.      * @see HttpServlet#HttpServlet() 
  23.      */  
  24.     public LogFileSavePathServlet() {  
  25.         super();  
  26.         // TODO Auto-generated constructor stub  
  27.     }  
  28.   
  29.     /** 
  30.      * @see Servlet#init(ServletConfig) 
  31.      */  
  32.     public void init() throws ServletException {  
  33.         //获得系统的路径 /WebRoot  
  34.       
  35.         String rootPath = this.getServletContext().getRealPath("/");  
  36.         //获得log4j.properties的输入流  
  37.         InputStream is =this.getClass().getClassLoader().getResourceAsStream("log4j.properties");  
  38.         Properties prop = new Properties();       
  39.         try {  
  40.             prop.load(is);  
  41.         } catch (FileNotFoundException e) {  
  42.             e.printStackTrace();  
  43.         } catch (IOException e) {  
  44.             e.printStackTrace();  
  45.         }   
  46.          //设置日志文件的输出路径     
  47.         prop.setProperty("log4j.appender.F.File",rootPath+prop.getProperty("log4j.appender.F.File"));  
  48.         prop.setProperty("log4j.appender.F.DatePattern",rootPath+prop.getProperty("log4j.appender.F.DatePattern"));  
  49.         //加载配置项     
  50.         PropertyConfigurator.configure(prop);   
  51.         super.init();  
  52.     }  
  53.   
  54.   
  55.   
  56. }  

注意啦,错误文件存储的路径不允许空格上面乱码七糟的,一定要注意哦。
写完这个servlet,我们不能忘记初始化,您说对不对啊,所以啊,web.xml就像下面这个样子了:
Java代码   收藏代码
  1. <!DOCTYPE web-app PUBLIC  
  2.  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"  
  3.  "http://java.sun.com/dtd/web-app_2_3.dtd" >  
  4. <web-app>  
  5. <!-- 日志文件存储路径初始化-->  
  6.     <servlet>  
  7.         <servlet-name>LogFileSavePathServlet</servlet-name>  
  8.         <display-name>LogFileSavePathServlet</display-name>  
  9.         <description></description>  
  10.     <servlet-class>com.peoplespot.sys.log.LogFileSavePathServlet</servlet-class>  
  11.         <load-on-startup>0</load-on-startup>   
  12.     </servlet>  
  13.       <servlet-mapping>  
  14.         <servlet-name>LogFileSavePathServlet</servlet-name>  
  15.         <url-pattern>/LogFileSavePathServlet</url-pattern>  
  16.     </servlet-mapping>  
  17. </web-app>  

--------------------------------下面就开始和spring aop相关啦,看吧,看吧-----------------------
再一次首先,写一个系统异常日志拦截器类,您看:
Java代码   收藏代码
  1. package com.yale.sys.log;  
  2.   
  3. import org.apache.log4j.Logger;  
  4. import org.aspectj.lang.ProceedingJoinPoint;  
  5.   
  6. /** 
  7.  * 系统异常日志拦截器 
  8.  * @author yale 
  9.  * 
  10.  */  
  11. public class LogInterceptor {  
  12.       
  13.      static Logger logger = Logger.getLogger(LogInterceptor.class);  
  14.      public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {    
  15.          StringBuffer sb = new StringBuffer();  
  16.         try{    
  17.             Object result = joinPoint.proceed();    
  18.             return result;    
  19.         }catch(Exception e){    
  20.             sb.append("开始方法:"+joinPoint.getTarget().getClass() + "." + joinPoint.getSignature().getName()+ "()  ");  
  21.             sb.append("错误信息如下:["+e.getMessage()+"]");  
  22.             logger.error(sb.toString());   
  23.         }  
  24.         return "error";//因为用到了strut2,所以出现异常会返回到<result name="error">/erreo.jsp</result>这个页面中,当然啦,你也可以配置成全局的异常返回页。  
  25.     }    
  26. }  

上面这个类,主要用到了aspectj中的ProceedingJoinPoint,支持的是<aop:around />。
类写完了,但是spring配置文件applicationContext.xml还没有搞啊,所以搞一下:
Java代码   收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.     xsi:schemaLocation="   
  6.         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd   
  7.         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd   
  8.         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">  
  9.   
  10. <!-- 配置日志拦截器 -->  
  11.     <bean id="logInterceptor" class="com.yale.sys.log.LogInterceptor"></bean>  
  12.       
  13.     <aop:config proxy-target-class="true">  
  14.         <aop:aspect id="logAspectSYS" ref="logInterceptor">  
  15.             <aop:around method="invoke" pointcut="execution(public * com.yale.live.action..*.*(..))" />  
  16.         </aop:aspect>  
  17.             <aop:aspect id="logAspectDNA" ref="logInterceptor">  
  18.             <aop:around method="invoke" pointcut="execution(public * com.yale.sys.action..*.*(..))" />  
  19.         </aop:aspect>  
  20.     </aop:config>  
  21. </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最终这样啦:

1,pointcut既可以定义在一个接口上面(表示实现该接口的类方法将被拦截),同时也可以定义在一个类上面(无接口的情
   况,需要强制使用cglib)。在接口上面定义pointcut时无需关心接口实现类的具体位置,只需要定义被拦截的接口及方
   法位置。

2,常见的情况:
x.y.service..*Service.*(..)
x.y.service —— 包“x.y.service”
x.y.service.. —— 包“x.y.service”及其子包例如:“x.y.service.abc”,“x.y.service.def”,“x.y.service.ghi”,“x.y.service.jkl”。。。
*Service —— 定义接口(或没有实现接口的类,需要使用cglib代理)表达式;所有以Service结尾的类或接口,注意不是所有以Service结尾的包名。
*(..) —— 定义方法名,方法参数表达式;任意方法的名称,任意方法参数。

com.xyz.service.*.*(..)
com.xyz.service —— 包“com.xyz.service”
*.*(..) —— 任意接口(或没有实现接口的类,需要使用cglib代理),任意方法,任意参数
在service包下定义的任意方法的执行。

com.xyz.service..*.*(..)
com.xyz.service —— 包“com.xyz.service”
com.xyz.service.. ——包“com.xyz.service”及其子包
*.*(..) —— 任意接口(或没有实现接口的类,需要使用cglib代理),任意方法,任意参数







  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值