spring中AOP 注解开发示例详解

针对“spring中AOP 注解开发示例详解”的完整攻略,我将分为以下几个部分进行讲解:

1. AOP 概述

AOP,即 Aspect Oriented Programming,面向切面编程,是一种程序设计的思想,可以让程序逻辑分散到各个部分,从而增加代码的可维护性和辅助性。Spring框架提供了完善的AOP实现,可以通过纯Java编写切面代码,实现统一的业务逻辑。

2. AOP 注解详解

Spring框架的AOP机制有两种实现方式:一种是通过XML配置文件实现,另一种则是通过注解实现。其中,注解是更为常见的方式,比XML更加简洁明了,而且维护成本更低。下面是常用的AOP注解:

注解 描述
@Aspect 表明该类是一个切面,用于声明通知和切点
@Before 在切点之前执行通知
@After 在切点之后执行通知
@AfterReturning 在切点方法返回后执行通知
@AfterThrowing 在切点方法抛出异常后执行通知
@Around 在切点前后都会执行的通知

3. AOP 注解示例一

首先,我们创建一个Calculator接口,定义两个方法:加法和减法。

public interface Calculator {
    int add(int a, int b);
    int sub(int a, int b);
}

然后,创建一个实现类CalculatorImpl,实现Calculator接口。

public class CalculatorImpl implements Calculator {
    @Override
    public int add(int a, int b) {
        return a + b;
    }

    @Override
    public int sub(int a, int b) {
        return a - b;
    }
}

接下来,我们需要创建一个切面类LoggingAspect,并且在这个类中添加@Aspect注解。

@Aspect
@Component
public class LoggingAspect {

}

然后,我们需要在这个切面类中定义一个切点,通过@Pointcut注解来定义。

@Pointcut("execution(* com.example.demo.Calculator.*(..))")
public void pointcut() {}

上面这个切点表示匹配Calculator接口下的所有方法。

接着,我们需要定义通知,并且通过@Before注解实现前置通知。在LoggingAspect类中实现如下方法:

@Before("pointcut()")
public void before(JoinPoint joinPoint) {
    String methodName = joinPoint.getSignature().getName();
    Object[] args = joinPoint.getArgs();
    System.out.println("执行方法 " + methodName + " 前,参数为:" + Arrays.toString(args));
}

最后,我们就可以在DemoApplication中调用Calculator的方法,观察是否有输出日志。

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
        Calculator calculator = new CalculatorImpl();
        int result = calculator.add(1, 2);
        System.out.println("1+2=" + result);
        result = calculator.sub(3, 4);
        System.out.println("3-4=" + result);
    }

}

如果控制台输出如下内容,则说明实现成功。

执行方法 add 前,参数为:[1, 2]
1+2=3
执行方法 sub 前,参数为:[3, 4]
3-4=-1

4. AOP 注解示例二

现在,我们通过一个更加复杂的示例来观察AOP注解的用法。我们需要创建一个UserService接口,并且定义两个方法:通过用户名查找用户和保存用户。

public interface UserService {
    User getUser(String username);
    void saveUser(User user);
}

其中,User是一个模型类。

public class User {
    private String username;
    private String password;
    // getter 和 setter 略
}

接下来,创建一个实现类UserServiceImpl,实现UserService接口并且添加@Component注解。

@Service
public class UserServiceImpl implements UserService {
    private Map<String, User> users = new HashMap<>();

    @Override
    public User getUser(String username) {
        return users.get(username);
    }

    @Override
    public void saveUser(User user) {
        users.put(user.getUsername(), user);
    }
}

然后,我们需要创建一个切面类UserServiceAspect

@Aspect
@Component
public class UserServiceAspect {
    private final Logger logger = LoggerFactory.getLogger(UserServiceAspect.class);

    @Before("execution(* com.example.demo.UserService.*(..)) && args(username, ..)")
    public void before(String username) {
        logger.info("[before]开始查找用户:{}", username);
    }

    @AfterReturning(value = "execution(* com.example.demo.UserService.*(..))", returning = "result")
    public void after(User result) {
        logger.info("[after]用户信息:{}", result);
    }

    @Around("execution(* com.example.demo.UserService.*(..)) && args(user, ..)")
    public void around(ProceedingJoinPoint pjp, User user) throws Throwable {
        if (user.getPassword().length() < 6) {
            logger.error("[around]密码长度不能少于6个字符");
        } else {
            pjp.proceed();
        }
    }
}

我们来逐步分析这段代码。首先,在before方法中,我们定义了一个前置通知,这个通知用于输出日志信息。@Before注解中的execution()表示匹配UserService接口下所有方法,同时使用args()来匹配参数是String类型的方法,并且可以通过..来表示任意参数。

接着,在after方法中,我们定义了一个后置通知,这个通知用于输出用户信息。@AfterReturning注解中的execution()args()的含义与before方法中相同,同时使用returning属性来匹配返回值为User类型的方法。

最后,在around方法中,我们定义了一个环绕通知,这个通知用于校验密码长度。@Around注解中的execution()args()的含义与before方法中相同,同时在方法体中,我们可以通过ProceedingJoinPoint类和proceed()方法来实现对方法的执行。如果密码长度小于6个字符,我们将输出错误日志,否则将继续执行方法。

最后,我们在DemoApplication中调用UserService中的方法,观察是否有输出日志。

@Service
public class DemoApplication implements CommandLineRunner {
    @Autowired
    private UserService userService;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        User user1 = new User();
        user1.setUsername("xiaoming");
        user1.setPassword("123");
        userService.saveUser(user1);

        User user2 = new User();
        user2.setUsername("xiaowang");
        user2.setPassword("123456");
        userService.saveUser(user2);

        User user3 = userService.getUser("xiaoming");
        User user4 = userService.getUser("xiaowang");
    }
}

控制台输出如下内容,则说明实现成功。

[around]密码长度不能少于6个字符
[before]开始查找用户:xiaoming
[before]开始查找用户:xiaowang
[after]用户信息:User{username='xiaowang', password='123456'}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:spring中AOP 注解开发示例详解 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • 深入理解React虚拟DOM

    深入理解React虚拟DOM React是一个非常流行的JavaScript库,用于构建用户界面。React的核心思想是通过组件化的方式来构建应用程序,其中虚拟DOM是React的核心机制之一。了解虚拟DOM对于理解React的工作方式非常重要。 什么是虚拟DOM 虚拟DOM是一个JavaScript对象,描述了实际DOM的结构和信息。它是React用来描述…

    其他 2023年3月28日
    00
  • 一起动手编写Android图片加载框架

    以下是“一起动手编写Android图片加载框架”的完整攻略: 1. 概述 在 Android 应用中,图片是经常使用的资源,但是加载图片可能会对 APP 的性能产生影响。为了实现更快的图片加载效果,我们可以通过开发一个图片加载框架来提高 APP 的性能。 2. 需求分析 在开发图片加载框架之前,我们需要先分析加载图片的一些需求,包括: 异步加载:不阻塞主线程…

    other 2023年6月25日
    00
  • html5之日历控件

    以下是“HTML5之日历控件”的完整攻略: HTML5之日历控件 在HTML5中,我们可以使用<input type=”date”>标签来创建日历控件。以下是创建日历控件的步骤: 1. 创建日历控件 我们可以使用以下代码来创建日历控件: <label for="">选择日期:</label> <i…

    other 2023年5月7日
    00
  • win10开发者套件Visual Studio 2016预览版2发布下载

    Win10开发者套件Visual Studio 2016预览版2发布下载攻略 前言 本文将介绍Win10开发者套件Visual Studio 2016预览版2的下载、安装和使用方法,并提供两条示例说明,供开发者参考。 步骤一:下载Visual Studio 2016预览版2 首先,你需要前往Microsoft官方网站下载Visual Studio 2016预…

    other 2023年6月26日
    00
  • python-将cv2.mean()的输出转换为其他颜色模型(lab)

    以下是关于“python-将cv2.mean()的输出转换为其他颜色模型(lab)”的完整攻略,包括定义、转换步骤、示例说明和注意项。 定义 在OpenCV中,cv2.mean()函数可以计算图像的平均值。默认情况下,该函数返回BGR色空间中的均值。本攻略将介绍如何将cv2.mean()函数的输出转换为其他颜色模型,例如LAB色空间。 转换步骤 将cv2.m…

    other 2023年5月8日
    00
  • Win11提示找不到文件请确定文件名是否正确怎么解决?

    Win11提示找不到文件的错误提示可能会出现在系统的各个部分,例如在桌面或文件资源管理器中打开文件夹,打开程序等操作时都有可能出现此类提示。此错误提示通常有以下几个原因: 文件被删除或移动,导致路径不正确,系统无法找到。 文件名中将中文空格、标点符号作为文件名,导致系统无法解析文件名。 文件被病毒或恶意软件感染,导致无法使用。 针对以上错误,我们可以尝试一下…

    other 2023年6月26日
    00
  • c#遍历文件夹下全部文件

    当然,我很乐意为您提供有关“C#遍历文件夹下全部文件”的完整攻略。以下是详细的步骤和两个示例: 1 C#遍历文件夹下全部文件 在C#中,可以使用Directory类和FileInfo类来遍历文件夹下的全部文件。这在需要对文件夹中的所有文件进行操作时非常有用。 2 使用Directory类遍历文件夹下全部文件 以下是使用Directory类遍历文件夹下全部文件…

    other 2023年5月6日
    00
  • rabbitmq彻底卸载

    RabbitMQ彻底卸载 RabbitMQ是一个开源的消息队列系统,可以用来实现分布式应用程序之间的消息传递。虽然RabbitMQ使用简单且可靠,但在某些情况下,你可能需要彻底卸载它。本文将介绍如何在Windows和Linux操作系统上彻底卸载RabbitMQ。 Windows下卸载RabbitMQ 停止RabbitMQ服务 在开始卸载RabbitMQ之前,…

    其他 2023年3月28日
    00
合作推广
合作推广
分享本页
返回顶部