【aop】10分钟利用aop写注解权限认证
2021/6/21 6:28:59
本文主要是介绍【aop】10分钟利用aop写注解权限认证,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前言
之前学过很多遍AOP切面,但印象中自己只会在切点前后打印写日志,没有实战能力,为此,本篇笔记就点除了“打印日志”之外的AOP常用功能
AOP基础
这这篇笔记的同学应该大都了解过AOP,这里不详述了,只带着大家回忆一下核心知识点。
AOP用途
用途:如前面所言,你可以简单理解为你想在spring容器中某一个方法每次调用前后打印一些日志。(设为计算器的方法cal.add(a,b)
)
静态代理与动态代理:
- 静态代理:你自己在那个方法体力自己写日志打印逻辑,
add(a,b){打印日志;正常业务;打印日志}
- 动态代理:不在add()方法体里写,而是在别的java文件里写,这样就达到了解耦或者不侵入代码等目的。其实最终的效果是一样的,spring会帮你在target目录下(或者你看不到的内存中)生成新的class文件,这个class里文件就像你自己写的静态代理一样,写到了方法体了。
核心概念
之前你可能学过几遍了,还是记不住,那这里还是简单说下吧。
面>点,所以切面是一个类,而切点是一个正则表达式,他说明要匹配的方法(这个方法叫目标)。
- 切面:Aspect
- 切点:PointCut
那么日志怎么表示呢?就是使用@Before、@After或者@Around等注解,它代表要在前面正则表达式匹配的方法前后执行一些日志
更多:还有其他的方法以及他们的匹配顺序自己查吧。
前面提及了一个正则表达式的东西,他说明了日志要在哪个方法前后打印。既然是正常表达式了,那么它就可以匹配多个方法打印同样的日志。这个正则表达式的格式为:
返回类型 包名.方法(参数)
这样就能表示任意一个方法了。有几个小点记一下
*
和正则表达式一样,代表任意..*
打包多级*
,比如a.b.c.d(),可以写为a..d()
(..)
表示方法参数任意
hello-world
前面说的日志术语叫做:通知。通知一般都写到单独的一个java类中,并且在对应通知方法上指定了是哪个目标方法 的通知(如计算器的add()方法)
下面的方法是我从其他笔记摘过来的,简单看下即可,他是说:log()方法打印日志,而@AfterReturning是说他在目标方法正常返回后被调用(就是说add方法没有报错执行完了)。
@Aspect public class LogAspect{ // 匹配org.a.service.impl包下所有类的、 // 所有方法的执行作为切入点 @AfterReturning(returning="rvt", pointcut="execution(*org.a.service.impl.*.*(..))") // 声明rvt时指定的类型会限制目标方法必须返回指定类型的值或没有返回值 // 此处将rvt的类型声明为Object,意味着对目标方法的返回值不加限制 public void log(Object rvt){ System.out.println("获取目标方法返回值:" + rvt); System.out.println("模拟记录日志功能..."); } }
这里还得提下细节:@AfterReturning注解里指定了2个属性,
- returning是说计算器的add方法返回了一个参数rvt,然后把这个参数传入log(rvt)方法里执行日志通知。
- pointcut是说该日志通知匹配的目标方法(你理解为正则表达式就可以了)
execution(*org.a.service.impl.*.*(..))")
里面写的就是正则表达式- 但其他通常还有另外一种用法,如
@AfterReturning(pointcut="controller()")
,是说正则表达式不在这里写,而是在切面类另外一个方法controller()上用@PointCut
标注的(至此,我们了解了切点) - pointcut和value属性是不同名属性(就是说他俩用哪个都行)
AOP用于权限控制
比如现在有个需求:自己写完权限了,如何让他控制某个方法不被任意调用呢?用切面可以轻易解决
先定义你的一个注解,注解的写法不详述了,都是套路
@Target(ElementType.TYPE) // 限定注解只能标注到类上 @Retention(RetentionPolicy.RUNTIME) // 注解什么时候存在 // RUNTIME就是编译、class、运行class时都存在 @interface MyAnnotation{ //注解的参数:参数类型+参数名(); String value() default "";//如果不写默认值,注解上就必须给定参数值 }
@Aspect // 切面 @Component public class AuthAspect { // 自动注入你自己写的权限认证service @Autowired 权限认证Service authService; // 定义一个切点,用于写正则表达式 @Pointcut("* com.a.ctrl.*(..))")// ctrl包下的任意方法,任意参数,任意返回值,满足则匹配到 public void myPointCut1() {} // 并且在controller方法上加了你自己写的注解@MyAnnotation的 @Pointcut("@annotation(MyAnnotation)") public void authMethod(String value){ // 自动转入你注解带来的value信息 } // 验证 public void log(ProceedingJoinPoint joinPoint){ // 获取注解 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); MyAnnotation myAnno = method.getAnnotation(MyAnnotation.class); // 比如注解里带来了要验证的内容,是角色还是权限等 String val = myAnno.value; // 获取当前用户 用户没有必要作为参数传过来,可以使用threadlocal等方式放到threadloca中; 得到的User user; // 也可以使用spring的方法进行获取请求信息,然后获取请求里代理的cookie和用户等信息 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); String info = request.getParameter("name"); // 进行验证myAnno authService.验证(user.userId,myAnno.value); // 如果验证不通过可以直接抛异常让mvc进行异常捕获或者其他处理方式 // 业务方法 returnVal = joinPoint.proceed(); }
优化:上面获取注解信息的逻辑应该可以优化,在kotlin里看过相关的逻辑,但是java里不知道有没有类似的,doc里查查应该能查到
就这样,虽然有点虎头蛇尾,但想说的都说完了。
随意再谈点aop其他内容吧
aop进行定义切点时,还有几个其他的属性
@Around("@annotation(Transactional)")
:标注了@Transactional注解拦截的@Around("within(com.test..*)")
包下所有的方法。该类的所有方法都执行aop方法。即要把注解加在类上. 在接口上声明不起作用 。 子孙类经测试匹配不到@Around("this(com.TestService)")
实现了该接口的类、继承该类、该类本身的类—的所有方法(包括不是接口定义的方法,但不包含父类的方法)@Around("target(java类或接口)")
//实现了该接口的类、继承该类、该类本身的类—的所有方法(包括不是接口定义的方法,包含父类的方法)。必须是在目标对象上声明注解,在接口上声明不起作用
该睡觉了。。。
这篇关于【aop】10分钟利用aop写注解权限认证的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-06-19《2023版Java工程师》课程升级公告
- 2024-06-15matplotlib作图不显示3D图,怎么办?
- 2024-06-1503-Loki 日志监控
- 2024-06-1504-让LLM理解知识 -Prompt
- 2024-06-05做软件测试需要懂代码吗?
- 2024-06-0514-ShardingSphere的分布式主键实现
- 2024-06-03为什么以及如何要进行架构设计权衡?
- 2024-05-31全网首发第二弹!软考2024年5月《软件设计师》真题+解析+答案!(11-20题)
- 2024-05-31全网首发!软考2024年5月《软件设计师》真题+解析+答案!(21-30题)
- 2024-05-30【Java】百万数据excel导出功能如何实现