Spring AOP攔截Service實現日誌管理(自定義註解的方式)

最近項目中用到AOP方式進行Service操作方法日誌管理,特爲之記!

1、先說理論和採用的方法

採用註解的方式,其中包括以下註解:@Aspect(類註解)和@AfterReturning(方法註解),其中需要用的Maven庫如下:

"org.aspectj:aspectjrt:1.8.9",

"org.aspectj:aspectjweaver:1.8.9",

org.springframework spring-aop 4.0.5.RELEASE

其中該兩個註解的主要用法爲:

@Aspect:Spring AOP支持的AspectJ切入點指示符

@AfterReturning:使用@AfterReturning可修飾AfterReturning增強處理,AfterReturning增強處理將在目標方法正常完成後被織入。
使用@AfterReturning註解可指定如下兩個常用屬性。
1)        pointcut/value:這兩個屬性的作用是一樣的,它們都屬於指定切入點對應的切入表達式。一樣既可以是已有的切入點,也可直接定義切入點表達式。當指定了pointcut屬性值後,value屬性值將會被覆蓋。
2)        returning:該屬性指定一個形參名,用於表示Advice方法中可定義與此同名的形參,該形參可用於訪問目標方法的返回值。除此之外,在Advice方法中定義該形參(代表目標方法的返回值)時指定的類型,會限制目標方法必須返回指定類型的值或沒有返回值。

2、樣例:

2.1 在spring-app-config.xml中聲明啓動aop

<!--配置aop自動創建代理-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <bean id="customerAspectLogger" class="com.XXX.dsppt.aop.CustomerAspectLogger"></bean>
    <bean id="systemAspectLogger" class="com.VVVV.dsppt.aop.SystemAspectLogger"></bean>

2.2 編寫日誌切面類

package com.XXX.dsppt.aop;

import com.XXX.dsppt.entity.SystemLog;
import com.XXX.dsppt.entity.User;
import com.XXX.dsppt.entity.meta.SystemOperateType;
import com.XXX.dsppt.security.SecurityConstants;
import com.XXX.dsppt.service.ILogService;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Date;

/**
 * Created by nongdapeng on 17/5/4.
 */
@Aspect
public class SystemAspectLogger {

    private static final Logger logger = Logger.getLogger(SystemAspectLogger.class);

    @Resource
    private ILogService logService;

    /**
     * 創建日誌
     * @param point
     * @throws Throwable
     */
    @AfterReturning(value = "execution (* com.XXX.dsppt.service.*.add*(..))", returning = "returnObj")
    public void endAddTransaction(JoinPoint point, Object returnObj) throws Throwable {
        //獲取方法名
        String methodName = point.getSignature().getName();
        User user = getUser();
        HttpServletRequest request = getRequest();
        if (user != null) {
            SystemLog systemLog = new SystemLog(user,new Date(), SystemOperateType.ADD);
            logService.createSystemLog(systemLog);
        }
    }

    /**
     * 更新日誌
     * @param point
     * @throws Throwable
     */
    @AfterReturning(value = "execution (* com.XXX.dsppt.service.*.update*(..))", returning = "returnObj")
    public void endUpdateTransaction(JoinPoint point, Object returnObj) throws Throwable {
        //獲取方法名
        String methodName = point.getSignature().getName();
        User user = getUser();
        HttpServletRequest request = getRequest();
        if (user != null) {
            SystemLog systemLog = new SystemLog(user,new Date(), SystemOperateType.UPDATE);
            logService.createSystemLog(systemLog);
        }
    }

    /**
     * 刪除日誌
     * @param point
     * @throws Throwable
     */
    @AfterReturning(value = "execution (* com.XXX.dsppt.service.*.remove*(..))", returning = "returnObj")
    public void endRemoveTransaction(JoinPoint point, Object returnObj) throws Throwable {
        //獲取方法名
        String methodName = point.getSignature().getName();
        User user = getUser();
        HttpServletRequest request = getRequest();
        if (user != null) {
            SystemLog systemLog = new SystemLog(user,new Date(), SystemOperateType.REMOVE);
            logService.createSystemLog(systemLog);
        }
    }

    /**
     * 導出日誌
     * @param point
     * @throws Throwable
     */
    @AfterReturning(value = "execution (* com.XXX.dsppt.service.*.export*(..))", returning = "returnObj")
    public void endExportTransaction(JoinPoint point, Object returnObj) throws Throwable {
        //獲取方法名
        String methodName = point.getSignature().getName();
        User user = getUser();
        HttpServletRequest request = getRequest();
        if (user != null) {
            SystemLog systemLog = new SystemLog(user,new Date(), SystemOperateType.EXPORT);
            logService.createSystemLog(systemLog);
        }
    }

    private User getUser() {
        User user = null;
        try {
            ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
            HttpSession session = attr.getRequest().getSession(true);
            user = (User) session.getAttribute(SecurityConstants.LOGIN_SESSION);
        } catch (Exception ignored) {
            ignored.printStackTrace();
            logger.error("獲取當前登陸用戶時發生錯誤:" + ignored.getMessage());
        }
        return user;
    }

    private HttpServletRequest getRequest() {
        HttpServletRequest request = null;
        try {
            ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
            request = attr.getRequest();
        } catch (Exception ignored) {
            ignored.printStackTrace();
            logger.error("獲取當前用戶ip錯誤:" + ignored.getMessage());
        }
        return request;
    }
}

其中,一些相關概念: Aspect - 切面
Pointcut - 切入點
Joinpoint - 連接點
Pointcut Designators (PCD)
Spring AOP中, 切入點(Pointcut)註釋符在使用execution方法時以下的連接點(joinpoint)是可用的。
•    execution
•    within
•    this
•    target
•    args
•    @target
•    @args
•    @within
•    @annotation
•    bean
 
以下的切入點(pointcut)僅支持基於XML的Spring AOP配置,不支持AspectJ註釋形式。如使用將會導致IllegalArgumentException異常。他們是:
•    call
•    get
•    set
•    preinitialization
•    staticinitialization
•    initialization
•    handler
•    adviceexecution
•    withincode
•    cflow
•    cflowbelow
•    if
•    @this

•    @withincode



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章