Spring

🧠 Java Config 기반 AOP 예외처리 웹 애플리케이션 만들기 (2025.04.07)

upwardtrend 2025. 4. 7. 00:46

 

오늘은 Java Config 방식으로 AOP(Aspect-Oriented Programming)를 활용해 예외 처리를 구현하는 웹 애플리케이션을 직접 만들어보았습니다. 기존의 XML 설정 방식과 Annotation 기반 방식과 비교하며, Java 코드만으로 설정을 처리할 수 있는 장점도 함께 느껴볼 수 있었어요.


1️⃣ 프로젝트 구조

java-config-version/
├── src/
│   └── main/
│       ├── java/
│       │   └── com/example/javaconfig/
│       │       ├── App.java
│       │       ├── AppConfig.java
│       │       ├── Calculator.java
│       │       ├── LoggingAspect.java
│       │       └── WebAppInitializer.java
└── pom.xml

2️⃣ pom.xml (필수 의존성)

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.30</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.3.30</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.20.1</version>
    </dependency>
</dependencies>

3️⃣ AppConfig.java (설정 클래스)

package com.example.javaconfig;

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

@Configuration // 설정 클래스임을 명시
@ComponentScan("com.example.javaconfig") // 해당 패키지 하위 컴포넌트 자동 탐색
@EnableAspectJAutoProxy // AOP 기능을 활성화
public class AppConfig {
}

✅ XML 설정 없이 자바 코드로 모든 설정을 해결합니다.


4️⃣ Calculator.java (비즈니스 로직 클래스)

package com.example.javaconfig;

import org.springframework.stereotype.Component;

@Component // 스프링이 관리할 수 있도록 등록
public class Calculator {
    public int divide(int a, int b) {
        return a / b; // 0으로 나누면 예외 발생
    }
}

5️⃣ LoggingAspect.java (AOP 예외 로깅)

package com.example.javaconfig;

import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.io.FileWriter;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Aspect // 이 클래스가 AOP 역할을 한다는 표시
@Component // Bean으로 등록
public class LoggingAspect {

    // 예외 발생 후 실행되는 어드바이스
    @AfterThrowing(pointcut = "execution(* com.example.javaconfig.Calculator.*(..))", throwing = "ex")
    public void logException(Exception ex) {
        try {
            // 현재 시간을 포맷팅
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
            FileWriter writer = new FileWriter("log_" + timestamp + ".txt");
            writer.write("에러 발생: " + ex.getMessage());
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

✅ @AfterThrowing은 예외가 발생했을 때 특정 메서드(logException)가 실행되게 합니다.


6️⃣ WebAppInitializer.java (웹 어플리케이션 초기화 설정)

package com.example.javaconfig;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;

public class WebAppInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext container) {
        // 자바 설정 기반 컨텍스트 생성
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(AppConfig.class); // 설정 클래스 등록

        // DispatcherServlet 생성 및 설정
        DispatcherServlet servlet = new DispatcherServlet(context);
        ServletRegistration.Dynamic registration = container.addServlet("dispatcher", servlet);
        registration.setLoadOnStartup(1); // 서버 시작 시 서블릿 로딩
        registration.addMapping("/"); // 루트 경로에 매핑
    }
}

✅ 웹.xml 없이 웹 애플리케이션 초기화 가능하게 해줍니다.


7️⃣ App.java (테스트용 실행 클래스)

package com.example.javaconfig;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {
    public static void main(String[] args) {
        // 자바 설정 기반의 컨텍스트 생성
        var context = new AnnotationConfigApplicationContext(AppConfig.class);

        // Calculator 빈 가져오기
        Calculator calculator = context.getBean(Calculator.class);

        try {
            // 예외 유발 (0으로 나누기)
            calculator.divide(10, 0);
        } catch (Exception e) {
            System.out.println("예외 발생 (메인): " + e.getMessage());
        }
    }
}

✨ 요약

항목 내용

학습 주제 Java Config 방식 AOP 예외처리
주요 기능 @Aspect, @AfterThrowing, Java Config 기반 설정
사용 기술 Spring Context, Spring AOP, AspectJ
설정 방식 XML 없이 전부 Java로 설정
테스트 방식 divide(10, 0) 실행 시 로그파일 생성됨

💭 부족했던 점

  • 처음에는 WebAppInitializer가 꼭 필요한지 헷갈렸고, DispatcherServlet 설정도 익숙하지 않았습니다.
  • AOP의 pointcut 표현식이 익숙하지 않아 자꾸 오타가 났습니다.

🔧 개선할 점

  • AOP 표현식을 더 다양한 예제로 연습해보아야겠습니다.
  • 예외 로그 파일을 한 개만 사용하고 로그 누적 방식으로도 개선할 수 있을 것 같습니다.

📍 마무리

XML 없이 Java로만 설정하는 방식은 코드 관리가 쉬워지고 IDE의 도움을 받을 수 있어 좋았습니다.
AOP를 이용해 예외 처리 흐름을 분리하는 것도 실무에서 유용할 것 같아요.