1. 程式人生 > >Spring Aop+註解實現日誌記錄

Spring Aop+註解實現日誌記錄

系統業務操作日誌記錄是每個系統必不可少的一部分,但通常的做法是在每個需要記錄日誌的地方,呼叫新增日誌的Service方法,這樣做主要是顯的麻煩。
我們可以使用Spring AOP結合註解來實現這一功能。

1、首先定義一個註解類,如下:

@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
    String module() default "";
    String desc() default "";
}

註解類有2個屬性,module是操作的模組,desc為具體記錄的日誌資訊。

2、定義切面類:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestAttributes;
import
org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.lang.reflect.Method; /** * Created by Administrator on 2017/6/2. */ @Aspect
public class LogAspect { private final Logger logger = LoggerFactory.getLogger(LogAspect.class); private long timeStart; @Before(value = "execution(* aop.service..*.*(..))") public void doBefore(JoinPoint joinPoint) { timeStart = System.currentTimeMillis(); } @After(value = "execution(* aop.service..*.*(..))") public void doAfter(JoinPoint joinPoint) { long timeEnd = System.currentTimeMillis(); logger.info("方法:" + joinPoint.getTarget().getClass().getSimpleName()+"."+joinPoint.getSignature().getName() + "執行結束。耗時:" + (timeEnd-timeStart)+"ms."); Method proxyMethod = ((MethodSignature)(joinPoint.getSignature())).getMethod(); try { Method sourceMethod = joinPoint.getTarget().getClass().getMethod(proxyMethod.getName(), proxyMethod.getParameterTypes()); SysLog sysLog = sourceMethod.getAnnotation(SysLog.class); if (sysLog != null) { String module = sysLog.module(); String desc = sysLog.desc(); // 這裡獲取登陸使用者資訊 /** * 1.獲取request資訊 * 2.根據request獲取session * 3.從session中取出登入使用者資訊 */ RequestAttributes ra = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes sra = (ServletRequestAttributes)ra; HttpServletRequest request = sra.getRequest(); HttpSession session = request.getSession(); // 從session中獲取使用者資訊 String loginInfo = (String) session.getAttribute("username"); String username = "admin"; logger.info(username + "在[" + module + "]" + desc); } } catch (NoSuchMethodException e) { e.printStackTrace(); } } }

3、spring配置檔案加入:

<aop:aspectj-autoproxy proxy-target-class="true" />
<bean id="aspectEventLog" class="aop.LogAspect" />

4、maven依賴:

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.1</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.6.12</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.10</version>
</dependency>
<dependency>
    <groupId>${spring.groupId}</groupId>
    <artifactId>spring-test</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
</dependency>

5、測試service:

@Service
public class TestService {
    @SysLog(module = SysConstant.MODULE_USER_MGR,desc = "新增使用者")
    public void test() {
        System.out.println("執行了test()方法,username=" + username);
        try {
            Thread.sleep((long) (Math.random()*3000L));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

執行結果:

執行了test()方法
12:39:30,355  INFO main aop.LogAspect:33 - 方法:TestService.test執行結束。耗時:1601ms.
12:39:30,356  INFO main aop.LogAspect:44 - admin[系統管理]新增使用者

最後說明一下,這種事沒法很具體的,比如某個人添加了某個使用者,這種級別做不到。
上面拿到httpservletrequest後當然可以拿到所有的請求引數,如果要更具體,就需要在每個請求上攜帶特定的引數。

比如使用者AA添加了使用者BB,BB就得放到固定名字的引數中。如果不用註解,就是把模組名和具體的日誌資訊都放到request中,在切面中從request獲取,不過這樣就比較麻煩了。

如果只是需要具體到模組,並記錄IP之類的,上面的就可以滿足了。