Skip to content

AOP for logging

Introduction, the problem of using logs

Example of using AOP to log method calls.

public void processOrder(Order order) {
    Logger logger = LoggerFactory.getLogger(OrderService.class);
    logger.info("Processing order: " + order.getId());

    try {
        // Business logic for processing the order
        orderRepository.save(order);
        logger.info("Order processed successfully: " + order.getId());
    } catch (Exception e) {
        logger.error("Error processing order: " + order.getId(), e);
        throw new OrderProcessingException("Failed to process order", e);
    }
}

Old Usage with Spring Boot

example of using a Java Proxy to add logging:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class LoggingProxy implements InvocationHandler {

    private final Object target;

    public LoggingProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("After method: " + method.getName());
        return result;
    }

    public static <T> T createProxy(T target, Class<T> interfaceType) {
        return (T) Proxy.newProxyInstance(
            interfaceType.getClassLoader(),
            new Class<?>[]{interfaceType},
            new LoggingProxy(target)
        );
    }
}

Modern Usage with Spring Boot

First, define the class:

import org.springframework.stereotype.Service;

@Service
public class OrderService {
    public void processOrder(Order order) {
        // Business logic for processing the order
        orderRepository.save(order);
    }
}

Then, define the aspect:

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.OrderService.processOrder(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Before method: " + joinPoint.getSignature().getName());
    }

    @After("execution(* com.example.service.OrderService.processOrder(..))")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("After method: " + joinPoint.getSignature().getName());
    }
}

Finally, enable AOP in your Spring Boot application:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan(basePackages = "com.example")
@EnableAspectJAutoProxy
public class AppConfig {
}

Enable it all on the main Application Class:

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.example.service.OrderService;

public class Application {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        OrderService orderService = context.getBean(OrderService.class);
        orderService.processOrder(new Order(1));
        context.close();
    }
}