看到这篇博客的朋友,如果对于切面AOP这个方面没有概念或者很模糊的话,可以先去了解下基本概念或者理论方面,大概知道它是解决什么问题之后再看收获会更大.当然没有基础的话也可以往下看,因为我主要分享的是在工作中遇到了相关的问题,继而想到使用这种方式来解决问题的方案,代码的话我会使用一个小案例来举例。关于AOP的赘述我再这里不再啰嗦了。
最近的工作任务主要是关于指标报表统计的查询,然后实时更新最新的动态展示在页面上,以每小时更新一次的频率,使用的定时器,也就是一天执行24次的数据查询,每个整点统计汇总更新一次最新的数据。主要的模块大致就是各个指标(解决率,电话响应率,请求解决率,平均解决时长,不合格率),质量检测,作业产量,人力资源,投诉,培训和安全事件等几个模块的相关统计。每个模块的功能都相对较独立,表的关联也是同理。
当我们开发的差不多的时候,上面这时候要求每次查询的时间不是整点,而是改为了每个整点的5分钟来执行,例如8点05分执行的查询时0-8点之间的数据,由于之前时整点查询8点整的话那么8点之后的数据时不会查询出来的,我们使用的时间条件为当前的系统时间来做条件,现在改的话,就会导致每个整点的1-5分钟之间的数据也会查询出来。看到这里有的朋友可能会说 修改定时的表达式不就好了嘛,的确,但是当时的表达式也是按照整点的方式去做的,时间的条件主要是在数据库部分完成的。传入一个当前的时间作为条件。所以现在定时里面,每个模块的功能查询条件都得修改,但其实这根本不是业务上面的。而且每个模块得方法都得改,完全是不必要得工作量。我这个时候就想到了有没有什么办法能统一在我这些模块得所以查询方法调用的时候,把传入的当前时间重新设置为当前时间的整点,这样就会轻松很多。所以这时候我想到了使用AOP来做这件事儿,在我这些查询方法的调用之前,重新设置一下时间为需求需要的时间不久行了嘛 这样不管你后面是要每个整点的15分查询,还是半点查询,我都不需要再次修改代码了,而只用修改配置那个point切入点的方法就行了。下面就用案例代码来展示一下:
1.首先我们需要的肯定是一个专门用于处理切面这样的工具类:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* 切面工具类
*/
@Component
@Aspect
public class ApspectUtils {
@Pointcut("execution(权限类型 返回类型 包名.类名.方法名())")
public void pointCut(){}
@Before("pointCut()")
public void before(){
System.out.println("方法之前的执行方法");
}
}
2.查询方法调用之前需要时间被重置的类
import org.springframework.stereotype.Service;
@Service
public class QualityCheckService {
public void selectQualityCheckList(){
System.out.println("查询统计的业务代码");
}
}
3.最后来一个测试的类
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest
@RunWith(SpringRunner.class)
public class RunAspect {
@Autowired
QualityCheckService qualityCheckService;
@Test
public void test(){
qualityCheckService.selectQualityCheckList();
}
}
4.最后运行test方法的执行效果
最后在说一句,在@pointcut注解里面可以使用@execution,@annotation、@within、@target、@args,this、target、bean等众多的方式去匹配你所需要被执行的类或者方法,具体的可以参考其他文章。
PS:如果想要获取方法的参数 JoinPoint对象的getArgs()方法
@Before("pointCut()")
public void before(JoinPoint point){
Object[] args = joinPoint.getArgs();
System.out.println("方法之前的执行方法");
}