Spring AOP面向切面编程实现日志功能
首先我们引入日志slf4j相关依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>
再引入spring-aop依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.23</version>
</dependency>
为了方便编码,lombok也是必不可少的
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<scope>provided</scope>
</dependency>
我们创建以下类,就能用切面对user相关的功能进行权限控制
@Aspect
@Component
public class UserAspect {
private static final Logger logger = LoggerFactory.getLogger(UserAspect.class);
private UserCache cache;
public UserAspect(UserCache cache) {
this.cache = cache;
}
@After("execution(* com.homework.UserServiceImpl.*(..))")
public void logMethodAccess(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
logger.debug("方法名: {}, 参数: {}", methodName, args);
}
@Around("execution(* com.homework.UserServiceImpl.addUser(..)) || " +
"execution(* com.homework.UserServiceImpl.deleteUser(..))")
public Object checkPermission(ProceedingJoinPoint joinPoint) throws Throwable {
if (!"admin".equals(cache.getUserName())) {
logger.warn("权限不足: 当前用户 {} 无法执行 {}", cache.getUserName(), joinPoint.getSignature().getName());
return false;
}
return joinPoint.proceed();
}
}
其中@After和@Before注释的方法可以看作是execution里的方法的前置操作以及后置操作,无论是否有异常都会进行,无法控制中间方法的进行与否。
三者的主要功能如下
@After可以进行资源释放、日志记录等功能
@Before可以进行参数校验、日志记录等功能
@Around方法会完全控制目标方法,可以进行权限检查、性能监控、事务管理等功能
如果需要完全控制目标方法的执行,使用 @Around
如果只需要在目标方法执行前或后做一些操作,使用 @Before或 @After
其中@Around方法的传入参数是ProceedingJoinPoint,这个方法和其它两种注解的传入参数的最大区别就是它会控制进程,只有返回 joinPoint.proceed() 了才会让这个方法继续进行,否则将会直接停止,而其它两种方法的返回值是 void 它们无法影响到方法的执行与停止。