JavaRush /Курси /Модуль 5. Spring /Практика: налаштування простого аспекту для логування

Практика: налаштування простого аспекту для логування

Модуль 5. Spring
Рівень 3 , Лекція 4
Відкрита

Давай створимо практичний приклад, в якому налаштуємо аспект для логування.

1. Логування: що і навіщо?

Логування — це процес запису даних про виконання додатка. Воно допомагає відстежити, що відбувається "під капотом", і стає головним артефактом для відладки і аналізу в продакшн-середовищах.

Наприклад, якщо в тебе є метод, який обробляє замовлення в інтернет-магазині, корисно знати:

  • Коли цей метод був викликаний.
  • Які дані передані як параметри.
  • Що відбулося всередині методу: успіх чи помилка.

За допомогою AOP ми можемо впровадити логування без зміни бізнес-логіки методів. Тобто твій код лишається чистим, а функціональність додається на рівні аспекту.


2. Налаштування проєкту

Крок 1: Підключи залежності

Створи Spring Boot проєкт (якщо ще не зробив) і переконайся, що spring-boot-starter-aop є в твоєму pom.xml (або build.gradle):


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

Крок 2: Увімкни підтримку AOP

Spring Boot автоматично активує AOP, якщо ти додав залежність. Жодних додаткових налаштувань не знадобиться. Однак якщо ти використовуєш Spring Framework без Boot, переконайся, що в конфігурації увімкнено компонент @EnableAspectJAutoProxy.


3. Створення аспекту для логування

Почнемо з простого аспекту для логування методів.

Крок 1: Створи клас аспекту

Створи новий клас LoggingAspect у проєкті:


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.demo.service.*.*(..))") // Вкажи, де застосовувати аспект
    public void logBeforeMethodExecution() {
        System.out.println("A method in the service layer is about to be called.");
    }
}

Розбір коду:

  • @Aspect — вказує, що цей клас є аспектом.
  • @Component — реєструє аспект як Spring Bean.
  • @Before — визначає, що вказана дія (logBeforeMethodExecution) має виконатися перед викликом методу.
  • "execution(* com.example.demo.service.*.*(..))" — це вираз Pointcut. Він обирає всі методи з пакету com.example.demo.service.

Крок 2: Розроби сервіс для тесту

Додамо простий сервіс, щоб перевірити наше логування. Для цього в пакеті service створюємо клас OrderService:


package com.example.demo.service;

import org.springframework.stereotype.Service;

@Service
public class OrderService {

    public void processOrder(String orderId) {
        System.out.println("Processing order with ID: " + orderId);
    }
}

Крок 3: Створи контролер

Щоб перевірити роботу аспекту, створимо контролер. Додаємо новий клас OrderController:


package com.example.demo.controller;

import com.example.demo.service.OrderService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {

    private final OrderService orderService;

    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }

    @GetMapping("/process-order")
    public String processOrder(@RequestParam String orderId) {
        orderService.processOrder(orderId);
        return "Order processed!";
    }
}

4. Тестуємо!

Запусти застосунок і відкрий браузер. Введи URL, наприклад:


http://localhost:8080/process-order?orderId=123

Ти маєш побачити результат у консолі:


A method in the service layer is about to be called.
Processing order with ID: 123

Перемога! Ти успішно додав логування в метод сервісу без зміни його коду.


5. Покращуємо наш аспект: логування аргументів

Давай додамо можливість логувати параметри виклику методу. Для цього використовуй API JoinPoint. Онови свій аспект так:


import org.aspectj.lang.JoinPoint;
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.demo.service.*.*(..))")
    public void logBeforeMethodExecution(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object[] methodArguments = joinPoint.getArgs();

        System.out.println("Method " + methodName + " is called with arguments: ");

        for (Object arg : methodArguments) {
            System.out.println("    " + arg);
        }
    }
}

Тепер при виклику методу в консолі ти побачиш:


Method processOrder is called with arguments:
    123
Processing order with ID: 123

Це робить логування набагато інформативнішим.


6. Додаємо @Around для вимірювання часу виконання

Наступний крок: вимірювання часу роботи методів. Оновимо аспект з використанням @Around:


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

@Aspect
@Component
public class PerformanceLoggingAspect {

    @Around("execution(* com.example.demo.service.*.*(..))")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();

        Object result = joinPoint.proceed(); // Виконуємо метод

        long endTime = System.currentTimeMillis();
        System.out.println("Execution time of " + joinPoint.getSignature().getName() +
                ": " + (endTime - startTime) + "ms");

        return result;
    }
}

Тепер, коли ти викличеш метод, отримаєш ще й інформацію про його час виконання:


Processing order with ID: 123
Execution time of processOrder: 5ms

7. Зворотний зв'язок: типові помилки

Одна з найпоширеніших помилок при використанні AOP — неправильне визначення Pointcut. Наприклад, якщо вкажеш занадто «широкий» Pointcut, твій аспект може почати спрацьовувати на несподіваних методах, наприклад, toString(). Щоб уникнути цього, намагайся чітко вказувати пакети й класи.


8. І що далі?

Додавання рівнів логування, динамічне керування аспектами через конфігураційні файли, створення аспектів для обробки виключень... Ласкаво просимо в світ безмежних можливостей Spring AOP!

Тепер у тебе є інструмент, який спрощує життя. Використовуй його мудро й обережно, як чарівну паличку. 😉

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ