1. 程式人生 > >採用AOP+log4j記錄專案日誌

採用AOP+log4j記錄專案日誌

關於AOP,我之前對AOP和OOP進行過對比Spring——閒扯AOP與OOP,在巨集觀上對AOP部分知識有了一個較清晰的瞭解。但是AOP的應用只在宣告式事務處理時用過。還不能夠對AOP進行靈活運用。人盡言AOP是OOP的補充,下面就通過AOP處理log4j記錄日誌的例子,學習AOP。

首先,AOP處理日誌是必需的,不使用AOP處理日誌有諸多不便。

日誌處理是每個專案當中一個非常重要的內容。沒有了日誌,也就失去了對系統的可控性。沒有日誌,系統出現任何問題,都會沒有蹤跡可尋,這對一個資訊系統而言是非常危險的。

然而,使用純OOP思想進行日誌處理,我們會發現,每個邏輯部分中總會混入日誌處理的程式碼,導致純OOP思想的設計略顯不倫不類。同時,如果記錄日誌的型別需求有變更,那麼我們就要去每個邏輯單元中修改Java程式碼。另外,如果需求今天變了明天再變的話,我想這將是一個非常繁重並且惹人厭的工作。

其實日誌處理應該是軟體系統中單獨的一大部分,開發人員在進行系統開發時,不應該再來考慮日誌處理。AOP能夠做到這一點,讓開發人員更加專注於系統的業務編碼,而無需顧慮日誌問題(這一點大家可以聯絡宣告式事務處理的方式,配置好了處理事務的配置檔案,編寫Manager或者action時,都無需顧慮事務)。

然後,介紹例子中的程式碼實現。

1、引入jar包:

               

2、切面Aspect程式碼:

package com.lzq.spring.aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import com.lzq.spring.test.AOPTest;
/**
 * 切面
 * @author lzq
 *
 */
public class Aspect {
	
	Logger logger = Logger.getLogger(AOPTest.class);
	String strLog = null ;
	
	/**
	 * 前置通知:在某連線點之前執行的通知,但這個通知不能阻止連線點前的執行
	 * @param jp 連線點:程式執行過程中的某一行為,例如,AServiceImpl.barA()的呼叫或者丟擲的異常行為
	 */
	public void doBefore(JoinPoint jp) {
		strLog = "log Begining method: "
				+ jp.getTarget().getClass().getName() + "."
				+ jp.getSignature().getName();
		logger.warn(strLog);
	}
    /**
     * 環繞通知:包圍一個連線點的通知,可以在方法的呼叫前後完成自定義的行為,也可以選擇不執行
     * 類似Web中Servlet規範中的Filter的doFilter方法。
     * @param pjp 當前程序中的連線點
     * @return
     * @throws Throwable
     */
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        long time = System.currentTimeMillis();
        Object retVal = pjp.proceed();
        time = System.currentTimeMillis() - time;
        System.out.println("process time: " + time + " ms");
        return retVal;
    }
    /**
     * 丟擲異常後通知 : 在方法丟擲異常退出時執行的通知。
     * @param jp 連線點:程式執行過程中的某一行為,例如,AServiceImpl.barA()的呼叫或者丟擲的異常行為
     */
    public void doAfter(JoinPoint jp) {
    	strLog ="doAfter:log Ending method: "
    			+ jp.getTarget().getClass().getName() + "."
    			+ jp.getSignature().getName(); 
    	logger.warn(strLog);
    }
}

3、業務程式碼:

業務邏輯介面:

package com.lzq.spring.service;

/**
 * 介面 AService
 */
public interface AService {
    public void cool(String _msg);
    public void cool();
}

業務介面的實現:

package com.lzq.spring.service;

/**
 * 介面的實現
 * @author lzq
 *
 */
public class AServiceImpl implements AService {
	@Override
	public void cool() {
		System.out.println("哇,樓主好帥!"); 
	}
	@Override
	public void cool(String name) {
		System.out.println("哇,樓主"+name+",你好帥啊!");
	}
}

4、測試AOPTest:

package com.lzq.spring.test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.lzq.spring.service.AService;

public class AOPTest{
	public static void main(String[] args){
		BeanFactory factory = new ClassPathXmlApplicationContext("ApplicationContext.xml");
		AService aService = (AService)factory.getBean("aService");
		aService.cool();
		aService.cool("泉浴五江");
	}
}

5、Spring配置檔案ApplicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	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" 
			default-autowire="autodetect">
	 <aop:config>  
        <aop:aspect id="aspect" ref="aspectBean">  
            <!--配置com.lzq.spring.service包下所有類或介面的所有方法-->  
            <aop:pointcut id="logService"  
                expression="execution(* com.lzq.spring.service.*.*(..))" />  
            <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>  
    <bean id="aspectBean" class="com.lzq.spring.aop.Aspect" />  
    <bean id="aService" class="com.lzq.spring.service.AServiceImpl" />  
</beans>

6、log4j的properties檔案主要配置:

### direct log messages to stdout ###
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.file=org.apache.log4j.FileAppender
log4j.appender.file.File=d:/test_log.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.rootLogger=warn, stdout,file
log4j.logger.org.hibernate.type=info
log4j.logger.org.hibernate.tool.hbm2ddl=debug
com.lzq.spring.service = debug


7、顯示結果:

Console視窗


檔案位置:


日誌檔案內容:


最後總結一下這個例子。

本文從通過記錄日誌的Demo,簡單實現了記錄日誌的功能。相信通過宣告式事務與本文中的例子,您對AOP的理解將會更上一層樓。