首先我们引入日志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 它们无法影响到方法的执行与停止。