spring aop获取目标对象的方法对象及方法上的注解

article/2025/10/18 18:51:53

spring aop获取目标对象的方法对象(包括方法上的注解)

这两天在学习权限控制模块。以前看过传智播客黎活明老师的巴巴运动网视频教程,里面就讲到权限控制的解决方案,当时也只是看看视频,没有动手实践,虽说看过几遍,可是对于系统中的权限控制还是很迷茫,所以借着这次机会动手实践一下。

    黎活明老师的巴巴运动网使用的框架是struts + spring + jpa,大致思路是使用自定义注解,在需要权限控制的方法前使用注解定义方法所需的权限,然后使用AOP拦截访问的方法,在执行目标对象前通过反射取得目标对象所需的权限,然后从当前session中取得登陆用户,遍历用户所拥有的权限,如果有权限则继续执行目标对象,如果没有权限则跳转到错误提示页面。巴巴运动网使用的struts + spring + jpa应用这种方案是有问题的,大致是spring aop无法拦截通过反射调用的方法,然后黎活明老师通过定制RequestProcessor 解决了这个问题。具体权限实现方案及对这种方案应用到巴巴运动网的缺陷的分析可以参看黎活明老师的巴巴运动网视频教程。

    我在实践的过程中采用的是spring mvc + spring + hibernate 的框架,因此使用spring aop拦截是完全可以实现这种权限方案的。因此我在系统中定义了一个切面,申明了切入点及一个环绕通知。

以下是被拦截的方法申明,方法上有做权限控制的注解Permission

 

  1. @Permission(module="user",operation="select")    
  2. @RequestMapping(value="/detail/{uid}",method=RequestMethod.GET)    
  3.     public String detail(@PathVariable int uid,Model model){    
  4.     ....    
  5. }    

以下是AOP定义

  1. @Pointcut("execution(java.lang.String com.jiangnan.cms.controller..*.*(..))")    
  2. public void controller(){}    
  3. @Around("controller()")    
  4. public Object introcepter(ProceedingJoinPoint pjp) throws Throwable{    
  5.     System.out.println("拦截到了" + pjp.getSignature().getName() +"方法...");    
  6. }    

测试的时候日志中的确输出了被拦截的方法。可是pjp.getSignature().getName()只是方法的名称,做权限控制需要得到方法上的注解Permission,那么就需要获取目标对象上的Method对象,通过Method对象的getAnnotation(Permission.class)方法获取注解。可是怎么怎么直接获取Method对象而不是方法名称呢?通过pjp.getSignature()方法获取的Signature方法上好像没有直接getMethod()方法,于是去问度娘,得出如下的转换:

  1. Signature signature = pjp.getSignature();    
  2. MethodSignature methodSignature = (MethodSignature)signature;    
  3. Method targetMethod = methodSignature.getMethod();    

这下终于满足需求了,于是迅速的写出了权限控制的代码:

 

 

  1. public Object introcepter(ProceedingJoinPoint pjp) throws Throwable{    
  2.     System.out.println("拦截到了" + pjp.getSignature().getName() +"方法...");    
  3.     Signature signature = pjp.getSignature();    
  4.     MethodSignature methodSignature = (MethodSignature)signature;    
  5.     Method targetMethod = methodSignature.getMethod();    
  6.         
  7.     Class clazz = targetMethod.getClass();    
  8.     if(clazz.isAnnotationPresent(Permission.class)){    
  9.         //获取方法上注解中表明的权限    
  10.         Permission permission = (Permission)clazz.getAnnotation(Permission.class);    
  11.         String module = permission.module();    
  12.         String operation = permission.operation();    
  13.         Privilege privilege = new Privilege(new PrivilegePK(module, operation));    
  14.         //获取当前用户拥有的权限    
  15.         User user = (User)ContextUtils.getHttpSession().getAttribute("employer");    
  16.         if(null != user){    
  17.             System.out.println(user.getUsername());    
  18.         }    
  19.         Set<Role> roles = user.getRoles();    
  20.         for(Role role : roles){    
  21.             if(role.getPrivileges().contains(privilege)){    
  22.                 //如果当前用户拥有的权限包含方法注解上的权限,则执行被拦截到的方法    
  23.                 return pjp.proceed();    
  24.             }    
  25.         }    
  26.         //如果没有权限,抛出异常,由Spring框架捕获,跳转到错误页面    
  27.             throw new PermissionException();    
  28.         }    
  29.         return pjp.proceed();    
  30.     }    

然后接着测试,可是在测试的过程中发现对于需要权限验证的detail方法,居然直接执行了,权限控制并没有起作用,于是debug调试,发现

 

 

  1. clazz.isAnnotationPresent(Permission.class)   

返回的是false,检查下,被拦截的方法上有Permission注解啊,而且注解的定义是方法级别的,作用范围是运行期啊,这个没错啊,重启了Eclipse,重新发布了,结果还是这样,郁闷啊。。。接着把生成的.class文件反编译,看到类上有Permission注解的呀,真是百思不得其解啊。。。实在想不明白,关灯睡觉了。

 

    第二天,心里老是想着这个问题,牵挂着他,很难受啊!大笑突然灵光一闪,会不会这个获取到得Method对象不是目标对象上的Method对象,因为通过检查,目标类上的Method上是的确有那个注解的,除非拦截到的Method对象不是目标对象上的,是代理对象上的,而这个代理对象上的这个方法上没有Permission注解。然后去网上搜了下这方面的资料,原来spring aop使用cglib生成的代理是不会加上父类的方法上的注解的,也就是这边生成的代理类上的方法上没有Permission注解,然后也看到了一篇老外的文章,上面有所提到,但那时针对接口实现的代理,大意是通过接口生成的代理,通过

 

  1. Signature signature = pjp.getSignature();    
  2. MethodSignature methodSignature = (MethodSignature)signature;    
  3. Method targetMethod = methodSignature.getMethod();    

这段代码获取的targetMethod对象是接口上的方法,他上面也是没有注解的(原文地址http://stackoverflow.com/questions/5714411/getting-the-java-lang-reflect-method-from-a-proceedingjoinpoint)。但是我这边不是通过接口生成代理的啊,是使用cglib通过继承目标对象生成代理的啊,难道这边获取的targetMethod对象是代理对象上的?于是就想证明。于是在代码中输出以下信息:

 

 

  1. Signature signature = pjp.getSignature();    
  2. MethodSignature methodSignature = (MethodSignature)signature;    
  3. Method targetMethod = methodSignature.getMethod();    
  4. System.out.println("classname:" + targetMethod.getDeclaringClass().getName());    
  5. System.out.println("superclass:" + targetMethod.getDeclaringClass().getSuperclass().getName());    
  6. System.out.println("isinterface:" + targetMethod.getDeclaringClass().isInterface());    
  7. System.out.println("target:" + pjp.getTarget().getClass().getName());    
  8. System.out.println("proxy:" + pjp.getThis().getClass().getName());    
  9. System.out.println("method:" + targetMethod.getName());    

结果如下:

 

 

  1. classname:com.jiangnan.cms.controller.LogonController    
  2. superclass:java.lang.Object    
  3. isinterface:false    
  4. target:com.jiangnan.cms.controller.LogonController    
  5. proxy:com.jiangnan.cms.controller.LogonController
    EnhancerByCGLIB
    f6998fd8    
  6. method:logon    

其他的都可以理解,按理3来说classname输出的应该是代理对象,应该是com.jiangnan.cms.controller.LogonController

EnhancerByCGLIB

f6998fd8,而不是com.jiangnan.cms.controller.LogonController,因为通过methodSignature对象获取的Method上没有Permission注解,所以通过getDeclaringClass获取定义该method的对象应该是代理对象而不是目标对象啊,这个没法解释啊抓狂,实验结果不能令人满意啊,不知道如何进行,希望有大神知道,或者以后想明白了再来完善。。。

 

    至此,通过MethodSignature也无法直接获取目标对象的被拦截Method对象,那就只能用最笨的办法了,通过反射获取,刚才提到的一篇文章(http://stackoverflow.com/questions/5714411/getting-the-java-lang-reflect-method-from-a-proceedingjoinpoint)有说明,代码如下:

  1. Class[] parameterTypes = new Class[pjp.getArgs().length];    
  2. Object[] args = pjp.getArgs();    
  3. for(int i=0; i<args.length; i++) {    
  4.     if(args[i] != null) {    
  5.         parameterTypes[i] = args[i].getClass();    
  6.     }else {    
  7.         parameterTypes[i] = null;    
  8.     }    
  9. }    
  10. String methodName = pjp.getSignature().getName();    
  11. Method method = pjp.getSignature().getDeclaringType().getMethod(methodName, parameterTypes);    

这种方式能实现,但是麻烦了点,简化了下,最终代码如下:

 

  1. Method realMethod = pjp.getTarget().getClass().getDeclaredMethod(signature.getName(), targetMethod.getParameterTypes());    

此处获取到的realMethod就是目标对象上的,realMethod.isAnnotationPresent(Permission.class)返回的是true。    对于这些东西还是要亲身实践的,视频要看,尤其是好的视频,要看不止一遍,但是看过了一定要动手实践,看看视频是简单的,完全不知道自己动手会遇到这些问题,不过遇到问题是好事,解决这些问题自己才能成长!大笑


http://chatgpt.dhexx.cn/article/YnjW3G9F.shtml

相关文章

spring aop获取目标对象的方法对象

这两天在学习权限控制模块。以前看过传智播客黎活明老师的巴巴运动网视频教程&#xff0c;里面就讲到权限控制的解决方案&#xff0c;当时也只是看看视频&#xff0c;没有动手实践&#xff0c;虽说看过几遍&#xff0c;可是对于系统中的权限控制还是很迷茫&#xff0c;所以借着…

赢在下班后,告别一无所有

工作几年后&#xff0c;为什么有些人财务自由&#xff0c;而有些人&#xff0c;仍一无所有&#xff1f; 其间差别&#xff0c;就在于&#xff1a;八小时之外的思维模式不同。 大部分的人&#xff0c;觉得八小时之内是工作&#xff0c;八小时之外是生活&#xff0c;工作和生活之…

关于海明码,我悟了

目录&#xff1a; 话在前面差错控制编码差错控制编码的分类 检错码纠错码 奇偶校验码海明码 校验位的位置码字格式校验位的确定校验位的校验规则(重点)海明编码示例 检错和纠错 什么是码距海明码的码距海明码的检错与纠错能力海明码的检错与纠错能力理解 总结考题最后参考链接…

SVPWM原理

SVPWM原理 空间矢量的定义PWM逆变器基本输出电压矢量SVPWM的实现 SVPWM已经是非常成熟且应用范围最为广泛的PWM调制方式之一了&#xff0c;所以本文也只是常规的原理介绍。 空间矢量的定义 交流电动机绕组的电压、电流、磁链等物理量都是随时间变化的&#xff0c;如果考虑到它…

foc学习笔记2——svpwm

foc学习笔记2——svpwm 写在前面&#xff1a;如今网上关于foc的文章和教程很多&#xff0c;但初学者往往会被那些专业且复杂的公式搞晕&#xff0c;不知道自己到底在学什么。本文尽量少列公式&#xff0c;多解释用途&#xff0c;所以不会有公式的推导过程&#xff0c;会更加注重…

二、SVPWM

二、SVPWM 1. 介绍 SVPMW是将逆变器和电机看作一个整体&#xff0c;用八个基本的电压矢量合成期望的电压矢量&#xff0c;建立逆变器功率器件的开关状态&#xff0c;并依据电机磁链和电压关系&#xff0c;实现对电机恒磁通变压变频调速。 三相无刷电机的三项排除三项全部为1和…

SVPWM调制中非零基础矢量的幅值是2/3Udc还是Udc?

1:、三相电压空间矢量的合成 设直流母线侧电压为Udc&#xff0c;逆变器输出的三相相电压为UA、UB、UC、其分别加在空间上互差120的三相静止平面坐标系上&#xff0c;可以定义三个相电压UA(t)、UB(t)、UC(t)、他们的方向始终在各自的轴线上&#xff0c;而大小随着时间按正弦规律…

Matlab SVPWM仿真模型

文中涉及的仿真模型可在公众号 iFTrue未来已来 中获取&#xff1a; 请扫描下方二维码关注微信公众号&#xff1a;iFTrue 未来已来 在公众号后台回复以下关键字获取SVPWM仿真模型&#xff1a;SVPWM模型 「 iFTrue 未来已来 」 目录&#xff1a; 1.1 基于C语言的SIMULINK仿真模…

SVPWM调制的simulink仿真

1、SVPWM的生成 在FOC矢量控制中&#xff0c;Id、Iq 经过PID输出Vd、Vq。Vd、Vq经过反park变换成Vα、Vβ。再Vα、Vβ合成空间参考矢量Uref。那么怎么根据Vα、Vβ确定Uref所在扇区&#xff0c;然后确定所在扇区两个非零基础矢量的作用时间呢。 1.1、传统的计算方法 1.1.1、…

电机专用SVPWM算法实现

SH33F2811包含三相电机的空间矢量脉宽调制&#xff08;Space Vector Pulse Width Modulation&#xff0c;SVPWM&#xff09;算法&#xff0c;对应于交流感应电机或永磁同步电机中的三相电压源逆变器的功率器件的一种特殊的开关触发顺序和脉宽大小的组合。这种开关触发顺序和组合…

小猫爪:PMSM之FOC控制04-SVPWM

小猫爪&#xff1a;PMSM之FOC控制04-SVPWM 1 SVPWM的引出2 SVPWM的原理3 SVPWM的推导4 仿真END 1 SVPWM的引出 在Park变换那一节&#xff0c;说到了可以通过控制Eq(Iq)和Ed(Id)来控制电机。而电流我们并不能直接控制&#xff0c;只能简介通过控制输出电压来控制电流&#xff0c…

SVPWM matlab建模

此为SVPWM算法的SIMULINK建模过程&#xff0c;没有具体的公式推导&#xff08;太多了&#xff0c;难打字&#xff09; abc为matlab自带的三相正弦波发生器&#xff0c;需要调整参数。 首先进行坐标变换 第一个fcn里的代码 function y fcn(a,b,c) y (2/3)*( a-0.5*b-0.5*c);%…

SVPWM算法的推导

博文默认采用恒幅值变换&#xff0c;若是用到恒功率变换的时候&#xff0c;会特别说明。推导过程其实有很多种&#xff0c;云龙混杂&#xff0c;看着看着自己就晕了&#xff0c;所以最好找一种自己好理解的。有关坐标变换的理论&#xff0c;参考坐标变化这篇博客 1.三相空间电…

svpwm理解

svpwm主要用于逆变器件的开关与导通&#xff0c;使得在电机内部形成圆形磁场。与spwm相比有诸多优点&#xff0c;中小功率的逆变器基本都采用svpwm进行逆变控制。 svpwm目的是在电机内部形成圆形磁场&#xff0c;磁场与电机内部合成电压的关系为正交&#xff0c;即合成电压为磁…

SimpleFOC(八)—— 理论+实践 深度分析SVPWM

目录 说明一、有感FOC控制原理二、SVPWM原理三、SimpleFOC&#xff08;不带电流采样&#xff09;的控制原理&#xff1a;四、SimpleFOC核心代码五、代码实验5.1、实验目的5.2、硬件准备5.3、修改代码 第一阶段5.3.1 打开例程5.3.2 修改代码5.3.3 验证上传5.3.4 电机观测5.3.5 修…

matlab查表svpwm,SVPWM的查表生成方式代码

昨天研究了传统的SVPWM生成方法之后 偶然看到了这个东西: 也就是说 SVPWM的占空比-角度的关系可以用分段函数进行表示 这样就简单多了 基本上通过查cos表+判断能避免浮点数运算 下面素程序www 结果输出到3个txt文件中,修改p的值可以算占空比(相电压)或者线电压... /* * SVPW…

svpwm的matlab模型,SVPWM的matlab仿真实现

在仿真之前您必须安装MATLAB7.0或以上版本&#xff0c;必须确保simpowersysm工具箱已被安装&#xff0c;如果以上要求已经达到&#xff0c;那么就可以执行以下步骤了&#xff1a; 步骤1&#xff1a;打开matlab主界面&#xff0c;然后在command window界面中的“>>”旁边输…

SVPWM细节

SVPWM细节 # 原理 通过六个扇区的六个非零矢量进行矢量合成所需电压&#xff0c;但在合成过程中不可避免地会经过零矢量来合成&#xff0c;从而降低开关频率动作次数。 一般过调制的情况下非零矢量作用时间大于载波周期&#xff0c;所以在此过程中只取有效矢量的作用时间之和。…

SVPWM学习

作者寄语&#xff1a;在公众号&#xff08;浅谈电机控制&#xff09;中以小文章的形式记录自己学习SVPWM的过程。有时候自学未免出现理解错误的地方&#xff0c;所以烦请学友们批评指正。 如果需要SVPWM模型&#xff0c;关注微信公众号&#xff1a;浅谈电机控制。留下邮箱获取…

单相SVPWM

单相SVPWM逆变技术起源于三相电机调速系统中的三相SVPWM技术&#xff0c;在三相SVPWM调制中由旋转的电压矢量得到旋转的磁场&#xff0c;对电压矢量进行控制从而实现电机调速&#xff0c;其实电压矢量控制的实质是一种逆变过程&#xff0c;故单相SVPWM逐渐被研究并应用于逆变电…