本文采用SpringBoot技术编写一个Spring AOP 示例。
一、引入依赖
<!--引入AOP依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
:::warning 注意:在完成了引入AOP依赖包后,不需要去做其他配置。AOP的默认配置属性中,spring.aop.auto属性默认是开启的,也就是说只要引入了AOP依赖后,默认已经增加了@EnableAspectJAutoProxy,不需要在程序主类中增加@EnableAspectJAutoProxy来启用。 :::
二、定义切面
定义切面类:在类上添加@Aspect 和@Component 注解即可将一个类定义为切面类。
@Aspect 注解 使之成为切面类
@Component 注解 把切面类加载到到IOC容器中,Bean交给Spring容器管理
package com.king.aop.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Objects;
/**
* 日志切面
* @PackageName com.king.aop.aspect
* @ClassName LogAspect
* @Auther jgg
* @Date 2021-7-5 10:16
*/
@Aspect
@Component
public class LogAspect {
private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Pointcut("execution(public * com.king.aop.controller.*.*(..))")
public void webLog(){}
/*前置通知*/
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable{
//接收到请求,记录请求信息
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request= attributes.getRequest();
//记录请求信息
System.out.println("URL" + request.getRequestURL().toString());
System.out.println("request.getMethod() = " + request.getMethod());
System.out.println("IP:" + request.getRemoteHost());
System.out.println("Class+Methord" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
System.out.println("params" + Arrays.toString(joinPoint.getArgs()));
logger.info("user ip: {}",request.getRemoteAddr());
}
//后置异常通知
@AfterThrowing("webLog()")
public void throwss(JoinPoint jp){
System.out.println("方法异常时执行...");
}
//后置最终通知,final增强,不管是抛出异常或者正常退出都会执行
@After("webLog()")
public void after(JoinPoint jp){
System.out.println("方法最后执行...");
}
@AfterReturning(returning = "obj",pointcut = "webLog()")
public void doAfterReturing(Objects obj) throws Throwable{
System.out.println("方法返回值为:"+obj);
logger.info("方法返回值为: {}",obj);
}
/**
* 环绕通知
* @param point
* @throws Throwable
*/
@Around("webLog()")
public void doAround(ProceedingJoinPoint point) throws Throwable{
System.out.println("方法环绕Running...");
try {
Object proceed = point.proceed();
System.out.println("方法环绕proceed,结果是 :" + proceed);
logger.info("方法返回值:{}",proceed);
} catch (Throwable throwable) {
throw throwable;
}
}
}
采用自定义注解的形式实现 Spring AOP
自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @PackageName com.king.aop.aspect
* @ClassName UserAspect
* @Auther jgg
* @Date 2021-7-6 9:31
*/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserAccess {
String desc() default "No Data!";
}
定义切面
package com.king.aop.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @PackageName com.king.aop.aspect
* @ClassName UserAccessAspect
* @Auther jgg
* @Date 2021-7-6 9:35
*/
@Component
@Aspect
public class UserAccessAspect {
@Pointcut(value ="@annotation(com.king.aop.aspect.UserAccess)")
public void access(){
}
@Before("access()")
public void doBefore(JoinPoint point){
System.out.println("-aop 日志记录启动-" + new Date());
}
/*环绕通知*/
@Around("@annotation(userAccess)")
public Object around(ProceedingJoinPoint pjp, UserAccess userAccess) {
//获取注解里的值
System.out.println("second around:" + userAccess.desc());
try {
return pjp.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
return null;
}
}
//进来切点这,最后经过的一个站,也是方法正常运行结束后
@After("access()")
public void after(JoinPoint joinPoint) {
System.out.println("-aop 日志记录结束-" + new Date());
}
}
三、知识补充
切点表达式
https://www.cnblogs.com/javazhiyin/p/9993299.html
原文链接:https://blog.csdn.net/qq_35387940/article/details/85261279
https://www.cnblogs.com/zhangxufeng/p/9160869.html