[Spring Boot] log4j 라이브러리 사용 : 의존성 주입

수빈·2024년 11월 28일

SpringBoot

목록 보기
3/4

의존성 주입 (Dependency Injection, DI)은 Spring Frameword의 핵심 개념 중 하나로, 객체 간의 의존성을 설정 파일이나 코드 외부에서 관리하는 방식이다. 이번애는 Spring Boot 프로젝트에 log4j 라이브러리를 사용하여 의존성을 주입하는 작업과, 의존성이 프로젝트에 미치는 영향에 대해서 알아보도록 하겠다.




1. 의존성 주입이란?

의존성 주입(DI)은 객체가 필요한 의존성을 스스로 생성하지 않고 외부에서 제공받는 디자인 패턴이다. Spring에서는 IoC(Inversion of Control) 컨테이너가 의존성을 관리하며, 이를 통해 코드의 결합도를 낮추고 확장성을 높인다.

의존성 주입의 장점
1. 결합도 감소 : 객체 간의 직접적인 의존성을 제거하여 코드 변경의 영향을 줄인다.
2. 유연성 증가 : 다양한 구현체를 쉽게 교체할 수 있다.
3. 테스트 용이성 : 의존성을 Mocking 하여 단위 테스트가 쉬워진다.




2.log4j 라이브러리 설정

2-1. log4j 란?

log4j는 java 기반 애플리케이션에서 로깅을 관리하는 라이브러리이다. Spring Boot에서는 기본적으로 logback이 사용되지만, log4j로 대체하여 의존성을 주입하는 방법을 살펴보도록 하겠다.


2-2. Maven 의존성 추가

1. pon.xml 파일 수정
프로젝트의 pom.xmllog4j 관련 의존성을 추가해준다.

<dependencies>
    <!-- log4j Core -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.20.0</version>
    </dependency>
    <!-- log4j API -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.20.0</version>
    </dependency>
</dependencies>

2. Spring Boot 기본 로깅 라이브러리 제외
Spring Boot는 기본적으로 logback을 사용하므로 이를 제외해야 충돌을 방지할 수 있다.
프로젝트를 생성하면 생성되는 pom.xml에서 spring-boot-starter-web, spring-boot-starter-test 에서 내부적으로 로깅 시스템을 포함하기 때문에 이부분에 로깅 기능을을 제외해주었다.

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>


2-3. log4j2.xml 설정 파일 생성

Spring Boot는 기본적으로 src/main/resources 디렉터리에서 설정 파일을 찾는다. src/main/resources/log4j2.xml 파일을 생성하고 아래와 같이 작성해준다.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <!-- 콘솔 로깅 -->
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <!-- 기본 로그 설정 -->
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

log4j2.xml 코드 분석




3. 의존성 주입을 통한 log4j 사용

3-1. 로깅 기능 추가

1. Service 클래스에 의존성 주입
src/main/java/com/example/board/service/MyService.java 파일을 생성하고 아래와 같이 작성해준다.

package com.example.demo.service;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Service;

@Service
public class MyService {

    private static final Logger logger = LogManager.getLogger(MyService.class);

    public void performAction() {
        logger.info("Performing some action...");
        logger.debug("Debugging information here.");
        logger.error("An error occurred!");
    }
}
  • LogManager.getLogger(Class<?>): 현재 클래스에 대한 로거 인스턴스를 생성한다.
  • 다양한 로그 수준(info, debug, error)을 활용하여 메시지를 출력한다.

3-2. Controller 에서 Service 호출

src/main/java/com/example/board/controller/MyController.java 파일을 생성하고 아래와 같이 작성해준다.

package com.example.demo.controller;

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

@RestController
public class MyController {

    private final MyService myService;

    public MyController(MyService myService) {
        this.myService = myService;
    }

    @GetMapping("/action")
    public String triggerAction() {
        myService.performAction();
        return "Action performed, check logs!";
    }
}


4. 의존성 테스트

4-1. 테스트

  • 애플리케이션 실행 후 /action URL에 GET 요청을 보낸다
  • log4j2.xml에 정의된 패턴에 따라 로그 메세지가 출력된다.

4-2. 로깅 변경 테스트

Spring Boot의 log4j에서 다른 라이브러리로 교체를 하려고 할 때. 예를 들어, logback으로 전환하기 위해 pom.xml에서 log4j를 제외하고 logback 의존성을 추가하였다.

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.4.6</version>
</dependency>

그러면 아래와 같이 MyService 부분에서 에러가 발생한다.

MyService에서 발생한 에러는 log4j 관련 클래스 (LogManager, Logger)를 사용하고 있기 때문이다. 즉, MyServicelog4j 라이브러리에 의존적인 관계라고 볼 수 있다.

1. 직접적인 의존성
MyService클래스는 log4j 의 API인 LogManagerLogger를 사용하고 있다. 따라서, log4j가 프로젝트에서 제거되면 해당 클래스는 컴파일 오류를 발생시긴다.

2. 결합도 문제
MyService는 현재 특정 로깅 구현체인 log4j에 강하게 결합되어 있다. 다른 로깅 라이브러리(예: logback이나 java.util.logging)로 교체하려면 MyService코드를 직접 수정해야한다. 이는 유지보수와 확장성을 저해한다.

의존성 주입의 관점에서보면 MyService는 로깅 기능을 직접 생성하거나 관리하지 않더라도 특정 구현체(log4j)에 강하게 의존하는 상태이다. 이로인해 다음과 같은 문제가 발생하게 된다.

  • 테스트 어려움 : log4j가 없으면 MyService를 테스트 할 수 없다.
  • 유연성 부족 : 로깅 라이브러리를 교체할 때 MyService의 코드를 수정해야한다.



log4j 라이브러리를 사용하여 의존성을 주입하는 테스트(?)를 해보았는데 의존성 관리 문제는 프로젝트의 유지보수와 확장성에 중요한 영향을 미치는 것 같다. 라이브러리의 업데이트나 교체 등의 상황이 발생했을 때를 대비하여 의존성 관리 전략을 잘 세워두어 이러한 문제를 미리 예방 할 수 있으면 좋을 것 같다는 생각을 했다..!

profile
Development History

0개의 댓글