一、什么是AOP?
AOP全称Aspect-Oriented Programming,意为面向方面的编程,也叫切面编程。在java中是面向对象OOP的编程模式,每个业务逻辑都进行了封装隔离开来,此时如果有多个业务模块需要引入公共行为,例如日志功能、安全性检测、异常处理方法等,若是对所有封装模块进行修改显然是不合理的。而AOP则解决了这个问题,可以横向切入各个封装模块的方法中,而不需要改动任何封装代码。
二、业务场景描述
后端使用jdk1.8 springboot2 + IDEA + Mybatis + Mysql
两个月前自己用业务时间做了个小程序,在后端程序中需要将用户登录态放初始化到spring容器中,并且在用户登录的时候更新容器中的登录态数据。
两个更新时机,spring容器初始化及用户调用小程序登录接口(这个我用AOP进行数据更新)。
三、AOP业务代码用法
1.引入POM
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.添加@Aspect注解
package com.demo1.demo1.config;
import com.demo1.demo1.pojo.LoginStatus;
import com.demo1.demo1.service.LoginStatusService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Aspect
@Component
public class InitializationCache {
// (使用aop切点来执行更新登录态信息)
//初始化登录态表数据到内存中
public static Map<String, String> loginStatusMap = new HashMap<String, String>();
@Autowired
LoginStatusService loginStatusService;
//配置AOP切点
@Pointcut("execution(public * com.demo1.demo1.service.impl.LoginStatusImpl.updateStatus(String,String))")
public void executePoint(){}
/**
* 两个执行时机
* 1.spring容器启动时加载登录态信息到内存;
* 2.用户登录态信息更新时使用AOP执行方法更新内存数据
*/
@PostConstruct
@After("executePoint()") //在切点方法后执行
public void init() {
List<LoginStatus> list = loginStatusService.findAll();
for(LoginStatus status : list){
loginStatusMap.put(status.getOpenid(),status.getSkey());
}
System.out.println("初始化登录态完成!总数量:"+list.size());
for(String key : loginStatusMap.keySet()) {
System.out.println("key:"+key);
System.out.println("val:"+loginStatusMap.get(key));
}
}
//在切点方法前执行
@Before("executePoint()")
public void doBefore(JoinPoint joinPoint){
}
//当方法进行返回的时候,returning属性是指定方法参数中的result来接收返回参数,这样就可以修改返回参数
@AfterReturning(value = "executePoint()", returning = "result")
public void doAfterReturning(JoinPoint joinPoint, Object result){
// System.out.println("切点方法执行后.. 返回结果:{"+result+"}");
}
//切点方法异常时执行
@AfterThrowing(value = "executePoint()", throwing = "e")
public void deAfterThrowing(JoinPoint joinPoint, Exception e){
// System.out.println("打印异常信息:" + e);
}
//环绕方法,切点方法执行前后都会触发
@Around("executePoint()")
public void deAround(ProceedingJoinPoint joinPoint) throws Throwable{
// System.out.println("方法执行前打印");
// joinPoint.proceed();//方法执行
// System.out.println("方法执行后打印");
}
}
@Aspect:声明是一个切面类
@Component: 将该类注入到spring中管理
@PointCut:配置一个切点
@PostConstruct:服务器加载servlet的时候执行一次,可以简单理解为spring容器加载时执行(被注解方法必须是void方法、非、static、不能抛出异常等)
切点对应业务方法

3.切点的写法注意
上面代码中
public * com.demo1.demo1.service.impl.LoginStatusImpl.updateStatus(String,String)
updateStatus方法必须指定参数类型,如果忽略方法参数则写:updateStatus(..) 所有该方法名都视为切点。
写法1:public * com.demo1.demo1.service.impl.LoginStatusImpl.*(..)
表示该实现类下的所有方法
写法2:public * com.demo1.demo1.service.impl.*.*(..)
表示该impl包下的所有类
等等.........
四、优化
上面已经实现了AOP在合适的时机更新数据,并且用通配符可以适配多个方法。但是每个增加一个需要更新登录态数据的业务时机我都要遵循或修改这里的通配符规则,这时候可以利用注解来使用AOP的功能。基本逻辑就是切面类中的切点指定你的自定义注解类,然后在需要做更新的时机方法上增加该注解【一对一对多】
|