切面应用场景:日志记录,加密解密,token令牌验证等等
我在这里应用到的是 token令牌验证 ,来验证当前我这个app端用户在调用后台接口的时候是否是已登录状态,没有登陆(没有token或者token失效)的用户是不允许访问对应接口的
上述场景是需要切面来验证的,否则的话每一个需要验证的接口都需要调这个公共方法时会产生代码混乱以及代码分散的情况,同时基于AOP不会破坏原来程序逻辑,因此它可以很好的对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
一、spring boot中应用 切面
- pom.xml 引入对应的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 具体应用
- 首先我需要定义一个切面类(具体讲解写在了代码注释里面),其中有一个细节是我自己定义了一个NoLoginToken注解,用来指定那些方法不需要走切面验证,因为像 登录、注册以及手机号发验证码等等在这类的接口是不需要验证token的,所以我自定义了一个这个注解,当在接口里面引入这个注解的时候就告诉我这个程序,这个接口不需要验证token,在下面我会给出这个注解的具体内容。
- 项目结构
-
切面类 LoginTokenAspect.java
@Component @Aspect // 必须要的 @Slf4j public class LoginTokenAspect { // 下面是我自定义的一个类 ,里卖我引入了 Redis 模板 // 因为用户的token 我是存在了redis里面,这个根据自己需要引入 @Autowired private LoginTokenHelper loginTokenHelper; /** * 扫描rest包及子包下所有方法,这些方法再调用的时候是需要验证用户token的 */ @Pointcut("execution(public * com.mbyte.easy.rest..*.*(..))") // 切入点表达式,有两种方式,这是其中一种,还有一种就是 切入注解 public void loginToken(){ } //@Around注解可以用来在调用一个具体方法前和调用后来完成一些具体的任务。 @Around("loginToken()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { log.info("开始验证token令牌"); RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest(); //获取请求头里面的 token值 String token = request.getHeader(DysConstant.LOGIN_TOKEN); // 获取注解 ,引入这个不用验证token的注解 NoLoginToken noLoginToken = AnnotationUtil.INSTANCE.getAnnotation(joinPoint, NoLoginToken.class); // 需要验证令牌的情况 if(noLoginToken == null || !noLoginToken.value()) { log.info("需要验证token令牌:{}",token); Long userId = loginTokenHelper.getToken(token); log.info("验证用户ID为:{}",userId); if(userId == null){ throw new BusinessException(DysConstant.LOGIN_TOKEN_ERROR); }else{ // 刷新token loginTokenHelper.refreshToken(token,userId); } }else{ log.info("不需要验证token令牌"); } log.info("结束验证token令牌"); return joinPoint.proceed(); } }
-
NoLoginToken注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface NoLoginToken {
/**
* 添加该注解的rest接口 默认无需token验证
* @return
*/
boolean value() default true;
}
在不需要验证token的接口上加上这个注解,他就会走 else 里面具体的代码,也就是说不需要再验证了token了
二、spring aop原理的简单讲解
- spring有两大核心 : ioc 、aop
- 我在前面讲解springmvc 的原理的时候其实已经用到这些 东西了:spring MVC工作原理解析
- ioc:通过反射生成的实例放入Hashmap里面,当发生请求调用的时候,去Hashmap里面挑选相应的实例,然后通过代理去执行实例的方法。
- AOP: Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理(通过反射获取类的信息,然后根据类的信息,通过cglib字节码注入技术对类进行增强(包含对类进行补充或生成新的类),然后通过反射生成它的实例,再用代理去执行生成实例的方法)。