示例1 - 基础用法
项目结构
demo01 项目结构:
demo01
└── src
├── main
│ ├── java
│ │ └── demo
│ │ ├── AspectConfig.java
│ │ ├── Demo01Application.java
│ │ └── SayHello.java
│ └── resources
└── test
├── java
└── resources
build.gradle
中的依赖:
compile('org.springframework.boot:spring-boot-starter')
compile('org.springframework.boot:spring-boot-starter-aop')
compile group: 'org.projectlombok', name: 'lombok', version: '1.18.0'
各个类的代码:
package demo;
import org.springframework.stereotype.Component;
@Component
public class SayHello {
public String hi(String msg) {
return "Hi " + msg;
}
}
package demo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class AspectConfig {
// 定义切点(切入位置)
@Pointcut("execution(* demo.SayHello.*(..))")
private void pointcut(){}
@Before("pointcut()")
public void before(JoinPoint joinPoint){
System.out.println("我是前置通知");
}
@AfterReturning(value="pointcut()", returning = "returnVal") // 别忘了returning参数
public void afterReturning(JoinPoint joinPoint, Object returnVal){
System.out.println("我是后置通知...,收到的returnVal: " + returnVal);
}
@After("pointcut()")
public void after(JoinPoint joinPoint) {
System.out.println("最终通知....");
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("我是环绕通知前....");
//执行目标函数
Object obj= (Object) joinPoint.proceed();
System.out.println("我是环绕通知后....");
if (obj instanceof String) {
return "我被切面修改了";
}
return obj;
}
@AfterThrowing(value="pointcut()", throwing="throwable") // 别忘了throwing参数
public void afterThrowing(JoinPoint joinPoint, Throwable throwable){
System.out.println("异常通知:"+ throwable.getMessage());
}
}
package demo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@Slf4j
public class Demo01Application implements CommandLineRunner {
@Autowired
private SayHello sayHello;
@Override
public void run(String... args) throws Exception {
System.out.println("result: " + sayHello.hi("World"));
}
public static void main(String[] args) {
SpringApplication.run(Demo01Application.class, args);
}
}
运行主类 Demo01Application ,输出:
我是环绕通知前....
我是前置通知
我是环绕通知后....
最终通知....
我是后置通知...,收到的returnVal: 我被切面修改了
result: 我被切面修改了
示例2:多个 @Aspect 和 @Order 配合使用
demo02 项目结构:
demo02
└── src
├── main
│ ├── java
│ │ └── demo
│ │ ├── AspectConfig01.java
│ │ ├── AspectConfig02.java
│ │ ├── Demo02Application.java
│ │ └── SayHello.java
│ └── resources
└── test
├── java
└── resources
package demo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Aspect
@Order(1)
@Component
public class AspectConfig01 {
// 定义切点(切入位置)
@Pointcut("execution(* demo.SayHello.*(..))")
private void pointcut(){}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("AspectConfig01: 我是环绕通知前....");
//执行目标函数
Object obj= (Object) joinPoint.proceed();
System.out.println("AspectConfig01: 我是环绕通知后....");
if (obj instanceof String) {
return "AspectConfig01: 我被切面修改了";
}
return obj;
}
}
package demo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Aspect
@Order(2)
@Component
public class AspectConfig02 {
// 定义切点(切入位置)
@Pointcut("execution(* demo.SayHello.*(..))")
private void pointcut(){}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("AspectConfig02: 我是环绕通知前....");
//执行目标函数
Object obj= (Object) joinPoint.proceed();
System.out.println("AspectConfig02: 我是环绕通知后....");
if (obj instanceof String) {
return "AspectConfig02: 我被切面修改了";
}
return obj;
}
}
执行主类 Demo02Application ,输出:
AspectConfig01: 我是环绕通知前....
AspectConfig02: 我是环绕通知前....
AspectConfig02: 我是环绕通知后....
AspectConfig01: 我是环绕通知后....
result: AspectConfig01: 我被切面修改了
示例3 - 对使用特定注解的方法使用切面
可以对某些注解「装饰」的类或者方法,织入切面。这个示例展示对注解「装饰」的方法织入切面。
demo03 项目结构:
demo03
├── build.gradle
└── src
├── main
│ ├── java
│ │ └── demo
│ │ ├── AspectConfig.java
│ │ ├── Demo03Application.java
│ │ ├── MyAnnotation.java
│ │ └── SayHello.java
│ └── resources
└── test
├── java
└── resources
注解 MyAnnotation :
package demo;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface MyAnnotation {
boolean value() default false;
}
类 SayHello :
package demo;
import org.springframework.stereotype.Component;
@Component
public class SayHello {
@MyAnnotation // 用自定义的注解修饰hi方法
public String hi(String msg) {
return "Hi , this is SayHello. " + msg;
}
}
类 AspectConfig:
package demo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Order(1)
@Component
public class AspectConfig {
// 定义切点(切入位置)
@Pointcut("@annotation(demo.MyAnnotation)")
private void pointcut(){}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
System.out.println("AspectConfig: 注解中的value值:" + myAnnotation.value());
System.out.println("AspectConfig: 我是环绕通知前....");
//执行目标函数
Object obj= (Object) joinPoint.proceed();
System.out.println("AspectConfig: 我是环绕通知后....");
if (obj instanceof String) {
return "AspectConfig: 我被切面修改了";
}
return obj;
}
}
主类:
package demo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@Slf4j
public class Demo03Application implements CommandLineRunner {
@Autowired
private SayHello sayHello;
@Override
public void run(String... args) throws Exception {
System.out.println("result: " + sayHello.hi("World"));
}
public static void main(String[] args) {
SpringApplication.run(Demo03Application.class, args);
}
}
执行主类,输出:
AspectConfig: 注解中的value值:false
AspectConfig: 我是环绕通知前....
AspectConfig: 我是环绕通知后....
result: AspectConfig: 我被切面修改了
示例4 - 对使用特定注解的类的所有方法使用切面
这个示例展示对注解「装饰」的类中的所有方法织入切面。
项目结构:
demo04
├── build.gradle
└── src
├── main
│ ├── java
│ │ └── demo
│ │ ├── AspectConfig02.java
│ │ ├── Demo04Application.java
│ │ ├── MyAnnotation02.java
│ │ └── SayHello.java
│ └── resources
└── test
├── java
└── resources
注解 MyAnnotation02 :
package demo;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface MyAnnotation02 {
boolean value() default false;
}
注意,注解的@Target是ElementType.TYPE,只能用来修饰class。
用注解 MyAnnotation02 修饰 SayHello 类:
package demo;
import org.springframework.stereotype.Component;
@Component
@MyAnnotation02(value = true)
public class SayHello {
public String hi(String msg) {
return "Hi , this is SayHello. " + msg;
}
}
类 AspectConfig02:
package demo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
@Aspect
@Order(2)
@Component
public class AspectConfig02 {
// 定义切点(切入位置)
@Pointcut("within(@demo.MyAnnotation02 *)")
private void pointcut(){}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 获取类的所有注解
Annotation[] annotations = signature.getDeclaringType().getAnnotations();
for (Annotation annotation : annotations) {
if (annotation.annotationType() == MyAnnotation02.class) {
System.out.println("AspectConfig02: 注解value:" + ((MyAnnotation02) annotation).value());
}
}
System.out.println("AspectConfig02: 我是环绕通知前....");
//执行目标函数
Object obj= (Object) joinPoint.proceed();
System.out.println("AspectConfig02: 我是环绕通知后....");
if (obj instanceof String) {
return "AspectConfig02: 我被切面修改了";
}
return obj;
}
}
主类 Demo04Application:
package demo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@Slf4j
public class Demo04Application implements CommandLineRunner {
@Autowired
private SayHello sayHello;
@Override
public void run(String... args) throws Exception {
System.out.println("result: " + sayHello.hi("World"));
}
public static void main(String[] args) {
SpringApplication.run(Demo04Application.class, args);
}
}
运行主类,输出:
AspectConfig02: 注解value:true
AspectConfig02: 我是环绕通知前....
AspectConfig02: 我是环绕通知后....
result: AspectConfig02: 我被切面修改了