Spring AOP注解执行两次,方法体执行一次的问题及原因分析 -- 知识铺
代码如下:
public class UserRealm extends Pac4jRealm(){
@Override
public AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
System.out.println("Onece");
Set<String> roles=new HashSet()<>;
roles.add("admin");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setRoles(roles);
return authorizationInfo ;
}
在controller层有一个方法
@RequestMapping("/hello2")
@ResponseBody
public String hello2() {
SecurityUtils.getSubject().checkRoles("user");
return "success";
}
当执行chekRoles 执行了doGetAuthorizationInfo() 方法 但是要打印两个"Onece" 请问这是什么原因呢?
原因如下:
这个问题其实换一个标题问题更清晰:即是 Spring Aop注解执行两次 方法体执行一次!!!
在我的业务场景中 使用CGLIB动态代理 通过DynamicAdvisedInterceptor来处理 intercept是aop处理入口:
包含四个参数 第一个是代理方法 第二个是目标方法 第三个是方法参数 第四个是方法代理信息
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
通过打断点发现了bug出现的原因:
第一次执行时 代理方法和目标方法 是同一个!!!
第二次执行时 目标方法才是真正的方法体!!!
解决方法就是去除掉
当前我的pub-shiro项目依赖了 pub-datasource模块 pub-datasource模块里面使用了
@Aspect
@EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true)
@Component
使用了cglib代理 而后在shiroConfig中 注入了DefaultAdvisorAutoProxyCreator代理器 存在了两个代理器 这两个代理器的区别和为什么出现该问题的原因 我还在研究中 得出答案会来更新
本问题即是Spring Aop注解执行两次 方法体执行一次!!! 代理1 代理 代理2 而 代理2 代理 真正的方法体!!! 这也就是为什么shiro中 权限校验方法执行两次 而真正的方法体执行一次的原因。
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/geek001/post/20240428/Spring-AOP%E6%B3%A8%E8%A7%A3%E6%89%A7%E8%A1%8C%E4%B8%A4%E6%AC%A1%E6%96%B9%E6%B3%95%E4%BD%93%E6%89%A7%E8%A1%8C%E4%B8%80%E6%AC%A1%E7%9A%84%E9%97%AE%E9%A2%98%E5%8F%8A%E5%8E%9F%E5%9B%A0%E5%88%86%E6%9E%90--%E7%9F%A5%E8%AF%86%E9%93%BA/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com