Spring AOP你会用吗?一看就明白

2020-05-26  本文已影响0人  爱做梦的锤子

SpringBoot 2.1.5.RELEASE
java version 1.8.0_231

一、什么是Spring AOP?

对这个名词的概念解释相信大家都不陌生,Spring AOP即是Spring的核心特性之一,AOP 全拼 Aspect Oriented Program,面向切面编程。
从字面意思理解切面编程的意思就好像是我们用“刀子”把一个顺序执行的代码从某一部位切开,然后我们在这个切面上写上我们的代码。AOP技术的目的是为了方便开发者,在切面编程的思想中,开发人员需要将核心业务和周边业务区分开。
核心业务就是涉及系统中核心部分的业务逻辑,比如操作数据库,修改重要用户数据等,这些业务不具有普适性,每个业务方法都有各自不同的处理逻辑;
周边业务就是一些共性逻辑操作,比如一些通用日志打印,方法耗时统计等等

几个名词概念

什么时间:方法执行前

具体什么事情:打印日志

哪些类的哪些方法:* site.teamo.mall.service.impl...(..))
理解为:在site.teamo.mall.service.impl包下的所有类的所有方法

将通知和切入点结合:在site.teamo.mall.service.impl包下的所有类的所有方法在方法执行前打印日志

整体流程理解

在Spring AOP核心的四点是:通知、切入点、切面、织入。一个完整的流程可以描述为:编写你的增强功能(通知),确定这个功能的执行时间(连接点),确定这个功能在什么地方生效(切入点),经过以上三步就形成了一个切面,使用Spring的动态代理机制对目标对象进行代理,将切面引入目标对象的执行逻辑,这样切面就被织入了目标对象

Spring AOP中五种通知类型

二、一个场景

找出慢方法:现有系统A,系统A中的代码中存在调用外部服务接口的逻辑,对此需要统计系统A服务层中各个方法的执行时长,找出执行慢的方法对其统计,以便后续优化。

一般逻辑

methodA(){
    long start = currentTime();
    doSomething;//方法A核心业务逻辑
    ...
    if(currentTime-start>500){
        LoG.info(方法执行时长过长,记为慢方法);
    }
}

methodB(){
    long start = currentTime();
    doSomething;//方法B的核心业务逻辑
    ...
    if(currentTime-start>500){
        LoG.info(方法执行时长过长,记为慢方法);
    }
}
...
...

这样的一个逻辑中就是将核心业务和周边业务没有进行区分,在这样的一个场景中核心业务就是各自方法自己具体的业务逻辑(methodA和methodB自己的功能逻辑),而周边业务就是计算一个各自核心业务的执行时间执行较慢时则打印日志。在这种实现方式中,虽然满足了当前需求即找出慢方法,可以当周边业务需求发生变更时(比如要将慢方法的执行时间记录进数据库),会带来较多的代码改动,存在风险。

切面编程逻辑

avatar

记录开始时间和计算耗时是周边业务,methodA的功能逻辑是核心业务,将周边业务写在切面中,就将核心业务和周边业务分开来编程了,耦合性也就降低

三、具体实现


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

切面表达式eg:execution(* site.teamo.mall.service.impl...(..))

avatar
  • 1——execution 所要执行的表达式主体
  • 2——代表方法返回值类型, *代表匹配所有类型
  • 3——切入点的类在site.teamo.mall.service.impl包及其子包
  • 4——代表匹配切入点包下的类,*代表匹配所有类
  • 5——切入点类的方法,*代表所有方法,(..)代表方法入参,结合起来即所有入参的所有方法

@Aspect
@Component
public class SlowMethodStatistics {

    private static final Logger LOGGER = LoggerFactory.getLogger(SlowMethodStatistics.class);

    @Around("execution(* site.teamo.mall.service.impl..*.*(..))")
    public Object slowMethodLog(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        // 执行目标 service
        Object result = joinPoint.proceed();
        // 记录结束时间
        long cost = System.currentTimeMillis() - start;
        if (cost > 1) {
            LOGGER.info("======{}.{} 执行耗时:{}======",
                    joinPoint.getTarget().getClass(),
                    joinPoint.getSignature().getName(),
                    cost);
        }
        return result;
    }
}


@SpringBootTest
@RunWith(SpringRunner.class)
@EnableAutoConfiguration
@MapperScan(basePackages = {"site.teamo.mall.dao"})
public class AopTest {

    @Autowired
    private UserService userService;

    @Test
    public void aopTest() throws Exception {
        userService.queryUsernameIsExist("mall");
        userService.queryUserForLogin("test","12345");
    }

}

执行效果

avatar

文章欢迎转载,转载请注明出处,个人公众号【爱做梦的锤子】,全网同id,个站 http://te-amo.site,欢迎关注,里面会分享更多有用知识,还有我的私密照片

上一篇下一篇

猜你喜欢

热点阅读