利用Spring AOP和自定義注解實現日志功能


Spring AOP的主要功能相信大家都知道,日志記錄、權限校驗等等。

用法就是定義一個切入點(Pointcut),定義一個通知(Advice),然后設置通知在該切入點上執行的方式(前置、后置、環繞等)。

只不過一直沒想過切入點還可以是注解

 

下面直接進入節奏

1、打開STS,新建一個Spring Starter Project。如果不清楚STS是什么,可以參考我的 Spring Tools Suite (STS) 簡介,幾分鍾的事。

Starter模塊選擇web、aop,其實我還選了一個Devtools模塊,不過對這個示例來說沒有區別。

新建完成后,外觀是這樣的:

 

2、新建一個注解 cn.larry.spring.annotation.Log

注意:STS有新建注解的選項(沒注意過Eclipse有沒有~~),可以直接選擇保留策略和目標。當然也可以新建好空白注解之后添加。

新建的注解內容如下:

package cn.larry.spring.annotation;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Documented
@Retention(RUNTIME)
@Target(METHOD)
public @interface Log {

}

由於只是案例示范,這里只添加一個注解參數 value 即可。如下:

package cn.larry.spring.annotation;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Documented
@Retention(RUNTIME)
@Target(METHOD)
public @interface Log {
    String value() default "我是日志注解";
}

3、接下來就該AOP登場啦,新建一個類 cn.larry.spring.aspect.LogAspect。並添加@Component和@Aspect注解 -- 這是因為@Aspect只能作用在bean上。如下:

package cn.larry.spring.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class LogAspect {

}

然后定義一個Pointcut,如下:

@Pointcut("@annotation(cn.larry.spring.annotation.Log)")
private void cut() { }    

再定義一個Advice,如下:

@Around("cut()")
public void advice(ProceedingJoinPoint joinPoint){
    System.out.println("環繞通知之開始");
    try {
        joinPoint.proceed();
    } catch (Throwable e) {
        e.printStackTrace();
    }
    System.out.println("環繞通知之結束");
}

至此,一個簡單的Aspect就創建完畢。

注:本來我想直接使用 新建Aspect,不過提示本項目不是一個Aspect項目,遂放棄。想了一下,大概是因為Spring僅借用了注解的緣故。

下面就是該Aspect的使用了。

4、新建一個Service,並添加一個run方法(方法名隨意),然后在該方法上使用注解@Log:

package cn.larry.spring.service;

import org.springframework.stereotype.Service;

import cn.larry.spring.annotation.Log;

@Service
public class DemoService {
    @Log
    public void run(){
        System.out.println("----我是cn.larry.spring.service.DemoService.run()----");
    }
}

5、有了方法,還需要調用,所以新建一個Controller,注入Service,並調用其方法:

package cn.larry.spring.web.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.larry.spring.service.DemoService;

@RestController
@RequestMapping("/aop")
public class AopController {
    @Autowired
    private DemoService demoService;
    @RequestMapping
    
    public String run(){
        demoService.run();
        return "Controller completed!";
    }
}

 

至此,一個簡單的示例就完成了,以Spring Boot App啟動,然后訪問  http://localhost:8080/aop 即可。控制台內容如下:

 

當然,這是最簡單的示例,實際需求通常比這個復雜,不過不外乎獲取注解的參數,然后根據參數內容進行操作。甚至可以獲取被注解的方法,再獲取該方法的參數,然后根據參數再進行不同的操作。

如有意,歡迎探討。

 

補充:

@AspectJ 是用被注解的Java類來聲明切面的一種方式(另一種方式就是xml設置),但是Spring只是借用它的注解,本質還是Spring的東西。原文如下:

@AspectJ refers to a style of declaring aspects as regular Java classes annotated with annotations. 
The @AspectJ style was introduced by the AspectJ project as part of the AspectJ 5 release. 
Spring interprets the same annotations as AspectJ 5, using a library supplied by AspectJ for pointcut parsing and matching. 
The AOP runtime is still pure Spring AOP though, and there is no dependency on the AspectJ compiler or weaver.

 


免責聲明!

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



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