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.
