什么是面向切面编程(AOP)?怎么使用SpringBoot框架进行面向切面编程?

 

最开始知道面向切面编程(AOP)的时候,觉得这个中文名非常难以理解。

实际上,AOP是一种简单的思想,试图通过把业务代码与非业务代码分开,减少代码之间的耦合性,同时减少了代码的重复。

 

优点:1.减少业务代码与非业务代码之间的耦合性

           2.减少代码重复

 

一、没有使用AOP思想的代码

假设一个场景,现在有一个业务是计算数组中元素的最大值,代码如下

public void getMaxMethod(int a[]){
    int max = a[0];
    for(int i = 1; i < a.size(); i++){
        if(max < a[i]) max = a[i];
    }
}

后期由于数组元素很多,希望能够加上统计这个业务运行花费时间的功能(非业务代码)。

public void getMaxMethod(int a[]){
    //获取开始时间
    long startTime = System.currentTimeMillis();
    int max = a[0];
    for(int i = 1; i < a.size(); i++){
        if(max < a[i]) max = a[i];
    }
    //获取结束时间
    long endTime = System.currentTimeMillis();
    long costTime = endTime - startTime;
    log.info("cost time is " + costTime);
}

可以看到,加上非业务代码后,这个方法里既有了业务代码也有了非业务代码,随着后续需求继续增加,这个方法势必更加臃肿,包含很多功能,这增加了代码的耦合性。同时,若向多个不同业务功能(类似获取最大值这种)中增加统计时间的功能的话,统计时间的代码也需要写多份,很不方便。

二、增加AOP思想,使用Springboot对项目进行改造

下面提供两种方案使用AOP实现上述同样的功能,方案一使用execution表达式,方案二使用注解的方式。

package com.example.demo.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 切面类,统计方法执行时间
 * @Author cody
 * @Date
 */
@Aspect
@Component
public class Timing {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 方法一:使用execution表达式限定切面影响到的方法,该表达式表示com.example.demo.job.Math类下的所有方法都添加该切面
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("execution(* com.example.demo.job.Math.*(..))")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();
        logger.info("method is {}, time cost {} ms", joinPoint.getSignature().getName(), end-start);
        return result;
    }
    /**
     * 方法二:使用execution表达式限定切面影响到的方法,该表达式表示com.example.demo.job.Math类下的所有方法都添加该切面
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("@annotation(com.example.demo.annotation.TimeStat)")
    public Object doAround2(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();
        logger.info("method is {}, time cost {} ms", joinPoint.getSignature().getName(), end-start);
        return result;
    }

}
package com.example.demo.job;

import com.example.demo.annotation.TimeStat;
import org.springframework.stereotype.Component;

/**
 * 业务类
 * @Author cody
 * @Date 2020.11.20
 */

@Component
public class Math {
    //如果使用方案一,则不需要@TimeStat注解
    @TimeStat
    public int getMaxMethod(int[] a){
        int max = a[0];
        for(int i = 1; i < a.length; i++){
            if(max < a[i]) {
                max = a[i];
            }
        }
        return max;
    }

}
package com.example.demo;

import com.example.demo.job.Math;
import org.junit.jupiter.api.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;

/**
 * 测试AOP
 * @Author cody
 * @Date 2020.11.20
 */
@RunWith(SpringRunner.class)
@SpringBootTest
class DemoApplicationTests {
    @Autowired
    Math math;
    @Test
    void contextLoads() {
        int a[] = {1,2,45,3,2,65,3,6};
        System.out.println(math.getMaxMethod(a));
    }
}
2020-11-20 15:56:26.783  INFO 20620 --- [           main] com.example.demo.aspect.Timing           : method is getMaxMethod, time cost 17 ms
65

可以直接运行的项目代码链接我放到了github仓库。

同时这段代码只使用了环绕通知(Around Advice) 的方法。除此之外,springboot提供了更多注解,这些注解可以对切面处理时间前后进行更加精细的操作,我看到一篇文章写的非常好,所以这部内容不重复了。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的AOP面向切面编程的测试代码示例,使用Spring框架实现: 首先,创建一个切面类 `LoggingAspect`,用于定义切面逻辑: ```java import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") public void beforeAdvice(JoinPoint joinPoint) { System.out.println("Before method: " + joinPoint.getSignature().getName()); } @After("execution(* com.example.service.*.*(..))") public void afterAdvice(JoinPoint joinPoint) { System.out.println("After method: " + joinPoint.getSignature().getName()); } } ``` 然后,创建一个测试服务类 `UserService`,用于演示AOP的应用: ```java import org.springframework.stereotype.Service; @Service public class UserService { public void createUser(String username) { System.out.println("Creating user: " + username); } public void deleteUser(String username) { System.out.println("Deleting user: " + username); } } ``` 最后,创建一个Spring Boot应用程序,并在启动类中进行配置: ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.EnableAspectJAutoProxy; @SpringBootApplication @EnableAspectJAutoProxy public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); UserService userService = context.getBean(UserService.class); userService.createUser("John"); userService.deleteUser("John"); } } ``` 在上述示例中,`LoggingAspect` 切面类使用 `@Before` 和 `@After` 注解分别定义了在目标方法执行前和执行后的逻辑。切面逻辑会应用于 `UserService` 类中的所有方法。 当运行应用程序时,可以看到切面逻辑在方法执行前和执行后打印了相应的日志消息。 这是一个简单的AOP面向切面编程的示例,你可以根据实际需求进行更复杂的切面逻辑定义和应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值