Spring AOP
Spring AOP 即面向切面,是对OOP
面向对象的一种延伸。AOP
机制可以让开发者把业务流程中的通用功能抽取出来,单独编写功能代码。在业务流程执行过程中,Spring
框架会根据业务流程要求,自动把独立编写的功能代码切入到流程的合适位置。
我们通过AOP
机制可以实现:Authentication
权限检查、Caching
缓存、Context passing
内容传递、Error handling
错误处理、日志打印等功能,这里我们讲一下怎么用Spring AOP
来实现权限检查。
SpringBoot 通过自定义注解实现权限检查
Maven依赖
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
MyPermissionTag.class自定义注解
@Retention
: 用来修饰注解,是注解的注解,称为元注解。@Target
:用来说明对象的作用范围
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
这里特别讲一下@Retention
,按生命周期来划分可分为3类:
RetentionPolicy.SOURCE
:注解只保留在源文件,当Java
文件编译成class
文件的时候,注解被遗弃(运行时去动态获取注解信息);RetentionPolicy.CLASS
:注解被保留到class
文件,但jvm
加载class
文件时候被遗弃,这是默认的生命周期(在编译时进行一些预处理操作);RetentionPolicy.RUNTIME
:注解不仅被保存到class
文件中,jvm
加载class
文件之后,仍然存在(做一些检查性的操作);
这3个生命周期分别对应于:Java
源文件(.java
文件) —> .class
文件 —> 内存中的字节码。
AuthInterceptor 权限检查的切面
这里简单介绍一下,切面的执行方法和其执行顺序:
@Around
通知方法将目标方法封装起来@Before
通知方法会在目标方法调用之前执行@After
通知方法会在目标方法返回或者异常后执行@AfterReturning
通知方法会在目标方法返回时执行@Afterthrowing
通知方法会在目标方法抛出异常时执行
这里以一个返回正常的情况为例:(异常替换最后一步即可)
HasLoginAspect.class
- 注意要在启动类扫描这个
class
,并且添加@EnableAspectJAutoProxy(proxyTargetClass = true)
package com.sharehoo.config.aspect;
import com.alibaba.fastjson.JSONObject;
import com.sharehoo.config.lang.Consts;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* @Author miki
* @Description 用户是否登录的鉴权注解 *
* @Date 14:48 2020/11/30
* @Param
* @return
**/
@Component
@Aspect
@SuppressWarnings({"unused"})
public class HasLoginAspect {
public static final Logger logger = LoggerFactory.getLogger(HasLoginAspect.class);
public HasLoginAspect(){
logger.info("创建aop切面拦截...");
}
/**
* 参数处理
*
* @param point
*/
@Before("@annotation(com.sharehoo.config.annotation.HasLogin)")
public void beforeProReq(JoinPoint point) {
logger.info("前置拦截-开始");
logger.info("前置拦截-结束");
}
@Around("@annotation(com.sharehoo.config.annotation.HasLogin)")
public Object checkRequestHead(ProceedingJoinPoint joinPoint) throws Throwable {
logger.debug("===>check access token start:{}", joinPoint.getArgs());
long begin = System.nanoTime();
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
request.setCharacterEncoding("UTF-8");
HttpServletResponse response =
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
HttpSession session = request.getSession();
Object user= session.getAttribute(Consts.CURRENTUSER);
String requestUri = request.getRequestURI();
String requestMethod = request.getMethod();
logger.info(
"===>get the equest url:{}; and request method:{}; ",
requestUri, requestMethod);
long end = System.nanoTime();
logger.info("API deal time log {}:{}",
joinPoint.getTarget().getClass() + "." + joinPoint.getSignature().getName(),
(end - begin) / 1000000);
if(ObjectUtils.isEmpty(user)){
response.sendRedirect("http://sharehoo.cn/login?prePage=http://sharehoo.cn" + requestUri);
return null;
}
return joinPoint.proceed();
}
/**
* 参数处理
*
* @param point
*/
@After("@annotation(com.sharehoo.config.annotation.HasLogin)")
public void afterProReq(JoinPoint point) {
logger.info("登录校验拦截-结束");
}
}
给大家安利一款免费的在线流程图设计软件:贼好用 ProcessFlow — 免费在线作图、实时协作 ProcessFlow是一个在线作图工具的聚合平台, 它可以在线画流程图、思维导图、UI原型图、UML、网络拓扑图、组织结构图等等, 您无需担心下载和更新的问题, 不管Mac还是Windows,一个浏览器就可以随时随地的发挥创意,规划工作,解放您的双手,让您腾出双手去成就别人的梦想。