在实际应用中,一个方法通常会被多个切面拦截。例如,我们有一个方法,既需要记录其执行日志,又需要应用一些安全限制。这类职责通常由专门的切面来处理,因此在该场景下,会有两个切面作用于同一个方法的执行过程。同时使用多个切面没有任何问题,但有时切面的执行顺序非常重要,因为有些切面会控制切入点方法的执行,比如鉴权的切面在鉴权失败后便不会继续执行切入点方法。这种情况下其他切面可能就没有机会执行了。
// userservice.java
@service
public class userservice {
private final logger logger = logger.getlogger(userservice.class.getname());
@tolog
public string getuser(string username) throws exception {
logger.info("getuser method called with username: " + username);
return username;
}
}
// loggingaspect.java
// 定义日志切面
@aspect
public class loggingaspect {
// 定义日志记录器
private final logger logger = logger.getlogger(loggingaspect.class.getname());
// 定义日志环绕通知
@around("@annotation(dev.xyz.annotation.tolog)")
public object logaround(proceedingjoinpoint joinpoint) throws throwable {
// 切入点方法执行前执行
logger.info("logging before method: " + joinpoint.getsignature().getname());
// 执行切入点方法
object result = joinpoint.proceed();
// 切入点方法执行后执行
logger.info("logging after method: " + joinpoint.getsignature().getname());
// 修改切入点方法的返回值
return result;
}
}
// securityaspect.java
// 定义鉴权切面
@aspect
public class securityaspect {
private final logger logger = logger.getlogger(securityaspect.class.getname());
@around("@annotation(dev.xyz.annotation.tolog)")
public object checksecurity(proceedingjoinpoint joinpoint) throws throwable {
logger.info("security check performed.");
// 这里模拟鉴权失败
if (joinpoint.getargs()[0].equals("mark")) {
throw new exception("security check failed.");
}
object result = joinpoint.proceed();
logger.info("security check passed.");
return result;
}
}
// projectconfig.java
// spring 配置,创建两个切面 bean
@configuration
@componentscan(basepackages = "dev.xyz.service")
@enableaspectjautoproxy
public class projectconfig {
@bean
securityaspect securityaspect() {
return new securityaspect();
}
@bean
loggingaspect loggingaspect() {
return new loggingaspect();
}
}
// main.java
// 在 main 方法中进行测试
public class main {
public static void main(string[] args) throws exception {
annotationconfigapplicationcontext context = new annotationconfigapplicationcontext(projectconfig.class);
userservice userservice = context.getbean(userservice.class);
userservice.getuser("mark");
}
}这里先执行了 securityaspect 切面,因为鉴权失败,所以 loggingaspect 切面不会执行。

这种情况下,可以使用 @order 注解来控制切面执行的顺序,给注解传递一个数值作为参数,数值越小越先执行,现在给切面类添加上 @order 注解,让 loggingaspect 先于 securityaspect 执行:
// loggingaspect.java
// 定义日志切面
@aspect
@order(1)
public class loggingaspect {
// 这里的代码不变
// ...
}
// securityaspect.java
// 定义鉴权切面
@aspect
public class securityaspect {
// 这里的代码不变
// ...
}现在结果变的不一样了,先执行了 loggingaspect 切面:

如果存在多个 @order 数值一样的切面,这时的结果又和不使用 @order 一样了。不使用 @order 注解的切面永远晚于使用 @order 注解的切面执行。
到此这篇关于spring 切面执行链的实现示例的文章就介绍到这了,更多相关spring 切面执行链内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论