Spring AOP+Log4j記錄項目日志


轉載請注明出處:http://www.cnblogs.com/Joanna-Yan/p/6567672.html 

項目日志記錄是項目開發、運營必不可少的內容,有了它可以對系統有整體的把控,出現任何問題都有蹤跡可尋。

如果用純OOP思想進行日志處理,會發現每個邏輯部分總會混入日志處理的代碼,顯得純OOP思想的設計不倫不類。如果日志的類型需求有變動,則需要去每個邏輯單元中修改Java代碼。需求再變更的話這將是一個非常繁瑣的工作。因此,日志處理應該是項目中單獨的一部分,我們在進行系統開發時,不應該再來考慮日志處理。而AOP可以讓我們更加專注於項目的業務編碼,無需顧慮日志問題。

首先簡單介紹下AOP(Aspect Oriented Programming):

AOP是OOP的延續,是一種分散關注的編程方法,將“關注”封裝在切面中,實現了調用者與被調用者之間的解耦合。

分散關注:將通用需求功能從不相關的類中分離出來,同時能夠使得多個類共享一個行為,一旦行為發生改變,不必修改很多類,只需要修改這個行為就可以。

面向對象是縱向結構的,它能夠使系統的邏輯單元更加清晰。

面向切面是橫切結構的,它針對業務邏輯層的切面進行提取。比如切面完成一個功能,這一功能卻在每個模塊中都有涉及,他就像刀切豆腐一樣切進系統,能夠對系統完成同一控制。

疑慮:donet程序部署在服務器就能運行,而Java程序卻多一道工序,非得部署在容器里面才能運行呢?J2EE為什么要除非J2EE容器和J2EE應用系統呢?

答案:J2EE容器實際上是分離一般應用系統中通用的部分。像事務、安全、數據庫連接池等等這些功能,將這些分離出來做成一個通用的框架。這些功能機制的設計開發有一定的難度,同時運行的穩定性和快速性都非常重要,必須經過長時間調試和運行經驗積累而成,慢慢才形成了像Tomcat、JBoss、WebLogic等J2EE容器服務產品。簡單來說,J2EE中分出的容器,就是將大多數軟件中都會用到的東西拿了出來,時間長了慢慢的就成了產品。

從J2EE系統划分為容器和應用系統兩個方面,我們可以看到一種分散關注的思路。

實現過程:

1.涉及的jar包:

spring.jar

log4j-1.2.16.jar

aspectjrt.jar

aspectjweaver.jar

commons-logging.jar

2.面向切面的Log類:

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class LogAspect {
    Logger logger=Logger.getLogger(LogAspect.class);
    String logStr=null;
    /**
     * 前置通知:在某連接點之前執行的通知,但這個通知不能阻止連接點前的執行
     * @param jp 連接點:程序執行過程中的某一行為
     */
    public void doBefore(JoinPoint jp){
        logStr=jp.getTarget().getClass().getName()+"類的"
                +jp.getSignature().getName()+"方法開始執行******Start******";
        logger.info(logger);
    }
    /**
     * 環繞通知:包圍一個連接點的通知,可以在方法的調用前后完成自定義的行為,也可以選擇不執行。
     * 類似web中Servlet規范中Filter的doFilter方法。
     * @param pjp 當前進程中的連接點
     * @return
     */
    public Object doAround(ProceedingJoinPoint pjp){
        long Time=System.currentTimeMillis();
        Object result=null;
        try {
            result=pjp.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
            logStr="方法:"+pjp.getTarget().getClass()+"."+pjp.getSignature().getName()+"()";
            logStr=logStr+"錯誤信息如下:["+e+"]";
            logger.info(logStr);
        }
        return result;
    }
    /**
     * 后置通知
     * @param jp
     */
    public void doAfter(JoinPoint jp){
        logStr=jp.getTarget().getClass().getName()+"類的"
                +jp.getSignature().getName()+"方法執行結束******End******";
        logger.info(logStr);            
    }
}

3.spring配置文件ApplicationContext.xml中配置AOP相關日志

<!--AOP類日志  -->
    <bean id="logAspect" class="yan.joanna.log.LogAspect"></bean>
    <aop:config>
        <aop:aspect id="aspect" ref="logAspect">
            <!--對哪些方法進行日志記錄,此處屏蔽action內的set get方法  -->
            <aop:pointcut id="logService" expression="(execution(* yan.joanna.*.*.*(..)) ) and (!execution(* yan.joanna.action.*.set*(..)) ) and (!execution(* yan.joanna.action.*.get*(..)) )" />
            <aop:before pointcut-ref="logService" method="doBefore"/>
            <aop:after pointcut-ref="logService" method="doAfter"/>
            <aop:around pointcut-ref="logService" method="doAround"/>
        </aop:aspect>
    </aop:config>
    <!-- 配置Action -->
    <bean id="UserAction" class="yan.joanna.action.UserAction" scope="prototype">
        <property name="userDAO" ref="UserDAO"></property>
        <property name="maindeviceDAO" ref="MaindeviceDAO"></property>
        <property name="amountDAO" ref="AmountDAO"></property>
        <property name="deviceUsingDAO" ref="DeviceUsingDAO"></property>
    </bean>

4.log4j的log4j.properties文件的主要配置

log4j.rootLogger = info, stdout, R

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 = %p %d{yyyy-MM-dd HH:mm:ssS} || %c{1} || %m%n

log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=d:/UTrainFileLib/logs/utrain.log
log4j.appender.R.Append=true

log4j.appender.R.layout=org.apache.log4j.PatternLayout  
log4j.appender.R.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} [%c]-[%p] [%t] (%F\:%L) ->%m %n
log4j.appender.R.Threshold=INFO
log4j.appender.R.DatePattern='.'yyyy-MM-dd

5.在開發或者運行初期,我們可能想打印一些業務邏輯,參數值等,並控制它的打印級別

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class JYLog {
    private static final Log log = LogFactory.getLog(JYLog.class);
    
    public static void printLog(String msg){
        if(log.isInfoEnabled()){
            log.info(msg);
        }
    }
    
    public static void errorLog(String msg,Exception e){
        log.error(msg, e);
    }
    
    public static void errorLog(String msg){
        log.error(msg);
    }
}

6.業務日志的打印,eg:UserAction中的登錄方法:

  /**
     * 登錄
     * @throws IOException 
     */
    public void login() throws IOException{
        HttpServletRequest req=ServletActionContext.getRequest();
        HttpServletResponse resp=ServletActionContext.getResponse();
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        String tel=req.getParameter("tel");
        JYLog.printLog("login()-登錄-Timestamp-"+new Timestamp(System.currentTimeMillis())+
                ";tel-"+tel);
        
        PrintWriter out=resp.getWriter();
        JSONObject json=new JSONObject();
        JSONObject dataJson=new JSONObject();
        String message="";
        int errorcode=0;
        
        if(!"".equals(tel)){
            User user=userDAO.findByAccount(tel);
            if(user==null){
                userDAO.save(new User(tel, new Timestamp(System.currentTimeMillis()),new Timestamp(System.currentTimeMillis()), 1));
                user=userDAO.findByAccount(tel);
                amountDAO.save(new Amount(user, 100,0));    
            }else{
                userDAO.updateLoginTime(user);
            }
            dataJson.put("id", user.getId());
            dataJson.put("account", user.getAccount());
            dataJson.put("type", user.getType());
            message="登錄成功";
            errorcode=0;
        }else{
            message="手機號不合法";
            errorcode=10002;
        }
        
        json.put("data", dataJson);
        json.put("message", message);
        json.put("errorcode", errorcode);
        out.print(json);
        out.flush();
        out.close();
        JYLog.printLog("login()-登錄-json-"+json.toString());
    }

7.日志打印文件內容部分顯示:

[yan.joanna.log.JYLog]-[INFO] [http-bio-59500-exec-56] (JYLog.java:11) ->login()-登錄-Timestamp-2017-04-01 08:10:08.972;tel-15515123456 
2017-04-01 08:10:08 [yan.joanna.log.LogAspect]-[INFO] [http-bio-59500-exec-56] (LogAspect.java:14) ->org.apache.log4j.Logger@10fb78e 
2017-04-01 08:10:08 [yan.joanna.log.LogAspect]-[INFO] [http-bio-59500-exec-56] (LogAspect.java:34) ->yan.joanna.dao.UserDAO類的findByAccount方法執行結束******End****** 
2017-04-01 08:10:08 [yan.joanna.log.LogAspect]-[INFO] [http-bio-59500-exec-56] (LogAspect.java:14) ->org.apache.log4j.Logger@10fb78e 
2017-04-01 08:10:08 [yan.joanna.log.LogAspect]-[INFO] [http-bio-59500-exec-56] (LogAspect.java:34) ->yan.joanna.dao.UserDAO類的updateLoginTime方法執行結束******End****** 
2017-04-01 08:10:09 [yan.joanna.log.JYLog]-[INFO] [http-bio-59500-exec-56] (JYLog.java:11) ->login()-登錄-json-{"data":{"id":68,"account":"15515123456","type":1},"message":"登錄成功","errorcode":0} 
2017-04-01 08:10:09 [yan.joanna.log.LogAspect]-[INFO] [http-bio-59500-exec-56] (LogAspect.java:34) ->yan.joanna.action.UserAction類的login方法執行結束******End****** 

如果此文對您有幫助,微信打賞我一下吧~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM