AOP:面向切面编程,是对面向对象的补充
一般处理非业务性代码,是非业务性代码的相同性比较高,才可以提出出来(eg:打印日志)
开始使用:
目标:控制器业务代码,统一进行日志输出
1.引入依赖包:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
2.创建entity 包,创建一个User类
@Data
全参构造器
@AllArgsConstructor
public class User {
private Integer id;
private String name;
3.创建Controller包,创建一个UserController
package org.example.Conertroller;
import org.example.annotaion.LogAnnotaion;
import org.example.entity.User;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserCon {
@GetMapping("/list")
public List<User> list() {
return Arrays.asList(
new User(1, "张三"),
new User(2, "李四"),
new User(3, "王五")
);
}
@GetMapping("/getById/{id}")
public User getUserId(@PathVariable("id") Integer id){
return new User(1,"张三");
}
@LogAnnotaion("插入操作")
@GetMapping("/save")
public Boolean save(){
return true;
}
@LogAnnotaion("删除操作")
@GetMapping("/del/{id}")
public Boolean del(@PathVariable("id") Integer id){
return true;
}
@LogAnnotaion("编辑操作")
@GetMapping("/edit")
public Boolean edit(){
return true;
}
}
4.这里开始进行AOP操作:自定义注解,标记目标方法
创建一个annotaion的包,创建一个LogAnnotaion注解,
【那些是要进行操作的,那些就添加标注】。
eg:
package org.example.annotaion;
import org.aspectj.lang.annotation.Aspect;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface LogAnnotaion {
String value() default "";
}
5.实现切面的操作
5.1通过表达式 ,找到那些符合的切点:@Pointcut("@annotation(org.example.annotaion.LogAnnotaion)")
5.2 通知方法(切点) 这里进行业务的处理
@Around("logPointCut()") 执行的周围
around(ProceedingJoinPoint point),这里是根据连接点的不同,来区分的是要执行那个业务
package org.example.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.assertj.core.internal.bytebuddy.matcher.MethodSortMatcher;
import org.example.annotaion.LogAnnotaion;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import java.lang.reflect.Method;
//注入到ioc,创建这个对象出来
@Component
//切面注解
//通过注解找到目标方法
//找到切点
//通过切点执行我们要定义的方法
@Aspect
public class LogAspect {
//表达式 找到符合的
@Pointcut("@annotation(org.example.annotaion.LogAnnotaion)")
public void logPointCut(){
}
//日志的输出
@Around("logPointCut()")
//判断不同的业务方法(通过连接点对象ProceedingJoinPoint point)
public Object around(ProceedingJoinPoint point) throws Throwable {
//得到方法名
String name=point.getSignature().getName();
//获取注解,先获取目标方法,通过目标方法获取注解
//获取签名信息
MethodSignature s= (MethodSignature)point.getSignature();
// getSignature():这是JoinPoint接口(point对象实现该接口)中的一个方法,用于获取当前连接点的签名信息。
// 、签名信息包括了方法的名字、返回类型以及参数类型等描述方法特征的数据。
//获取目标方法
Method method = s.getMethod();
//通过目标获取注解
LogAnnotaion logAnnotaion= method.getAnnotation(LogAnnotaion.class);
if(logAnnotaion!=null){
String value=logAnnotaion.value();
System.out.println("【系统输出】"+"操作是:"+ value+"调用了"+name+"方法"+"返回值是:"+point.proceed());
}
System.out.println(method);
//获取目标方法返回值
return point.proceed();
}
}