본문 바로가기

SPRING/Spring

[스프링| 스프링 핵심 원리 | 기본편 | 의존관계 자동 주입] 롬복과 최신 트랜드

@Getter

@Getter 애노테이션은 클래스의 필드에 대한 getter 메소드를 자동으로 생성해줍니다. 클래스 레벨이나 필드 레벨에 적용할 수 있으며, 특정 필드에만 적용하고 싶다면 해당 필드에만 애노테이션을 붙일 수 있습니다.

import lombok.Getter;

@Getter
public class UserData {
    private String name;
    private int age;
}

public String getName() {
    return this.name;
}

public int getAge() {
    return this.age;
}

@Setter

@Setter 애노테이션은 클래스의 필드에 대한 setter 메소드를 자동으로 생성해줍니다. 이 애노테이션 역시 클래스 전체 또는 특정 필드에 적용할 수 있습니다. 필드가 final로 선언되지 않은 경우에만 setter 메소드가 생성됩니다.

import lombok.Setter;

@Setter
public class UserData {
    private String name;
    private int age;
}

public void setName(String name) {
    this.name = name;
}

public void setAge(int age) {
    this.age = age;
}

@ToString

@ToString 애노테이션은 클래스의 toString() 메소드를 자동으로 생성해줍니다. 이 메소드는 클래스의 모든 필드를 문자열 형태로 반환하며, 필요에 따라 특정 필드를 제외하거나 포함하는 형태로 커스터마이즈할 수 있습니다.

 

import lombok.ToString;

@ToString
public class UserData {
    private String name;
    private int age;
}

@Override
public String toString() {
    return "UserData(name=" + name + ", age=" + age + ")";
}

사용상의 유의점

  • @Getter와 @Setter를 사용할 때는 클래스의 캡슐화 원칙을 유지하는 것이 중요합니다. 모든 필드에 대해 무분별하게 접근자와 설정자를 제공하는 것은 캡슐화를 약화시킬 수 있습니다.
  • @ToString 사용 시 순환 참조 문제가 발생할 수 있으므로, @ToString.Exclude 애노테이션을 사용하여 순환 참조가 발생하는 필드를 출력에서 제외해야 할 수 있습니다.

@NoArgsConstructor

Lombok 라이브러리의 @NoArgsConstructor 애노테이션은 Java 클래스에 파라미터가 없는 기본 생성자를 자동으로 생성하는 기능을 제공합니다. 이 애노테이션이 매우 유용한 경우는 주로 객체를 직렬화하거나, 프레임워크 및 라이브러리가 클래스의 인스턴스를 자동으로 생성할 때 필요합니다.

@NoArgsConstructor의 기능과 특징

  • 기본 생성자 생성: @NoArgsConstructor 애노테이션을 클래스에 적용하면, Lombok은 해당 클래스에 파라미터가 없는 기본 생성자를 자동으로 추가합니다. 이 생성자는 public 접근 제어자를 가지며, 클래스 내에 다른 생성자가 명시적으로 정의되어 있지 않다면 필요한 경우에 매우 유용합니다.
  • 접근 제어자 설정: @NoArgsConstructor 애노테이션은 접근 제어자를 설정하는 속성(access)을 제공합니다. 이를 통해 생성자의 접근 수준을 public, protected, package-private, 또는 private으로 지정할 수 있습니다.
  • 예외 처리: 생성자에서 특정 예외를 던질 수 있도록 @NoArgsConstructor는 force 속성을 사용하여 필드를 강제로 초기화할 수 있습니다. 이는 주로 final 필드가 있을 때 사용됩니다.

@AllArgsConstructor

Lombok 라이브러리의 @AllArgsConstructor 애노테이션은 클래스의 모든 필드를 인자로 받는 전체 생성자(all-args constructor)를 자동으로 생성해줍니다. 이 애노테이션은 클래스의 모든 필드를 초기화할 수 있는 생성자를 간편하게 만들고 싶을 때 유용하게 사용됩니다.

@AllArgsConstructor의 기능과 특징

  • 전체 생성자 생성: @AllArgsConstructor 애노테이션을 클래스에 적용하면, 클래스의 모든 필드를 매개변수로 갖는 생성자를 자동으로 생성합니다. 이를 통해 객체를 생성할 때 모든 필드를 한 번에 초기화할 수 있습니다.
  • 접근 제어자 설정: @AllArgsConstructor 애노테이션은 생성자의 접근 수준을 설정할 수 있는 access 속성을 제공합니다. 생성자의 접근 수준을 public, protected, package-private, 또는 private로 지정할 수 있습니다.
  • 필수 필드에 대한 초기화 보장: 생성자를 통해 클래스의 필수 필드가 반드시 초기화되어야 하는 경우, @AllArgsConstructor를 사용하면 필드가 누락되지 않도록 보장할 수 있습니다. 이는 클래스의 무결성을 유지하는 데 도움이 됩니다.

@RequiredArgsConstructor

Lombok 라이브러리의 @RequiredArgsConstructor 애노테이션은 "필수 생성자"(required constructor)를 자동으로 생성하는 기능을 제공합니다. 이 생성자는 모든 필수 필드, 즉 final 필드와 @NonNull 어노테이션이 붙은 필드를 매개변수로 받습니다. 이 애노테이션은 클래스에서 반드시 초기화가 필요한 필드만을 대상으로 생성자를 생성하여, 필수적인 값들이 초기화되지 않는 것을 방지합니다.

@RequiredArgsConstructor의 기능과 특징

  • 필수 필드에 대한 생성자 생성: @RequiredArgsConstructor는 final 필드 또는 @NonNull 어노테이션이 붙은 필드에 대한 생성자를 자동으로 생성합니다. 이 필드들은 생성자를 통해 반드시 초기화되어야 하므로, 생성자에 포함됩니다.
  • 접근 제어자 설정: 생성자의 접근 수준을 설정할 수 있는 access 속성을 제공합니다. 이를 통해 생성자의 접근 수준을 public, protected, package-private, 또는 private으로 지정할 수 있습니다.
  • 초기화 보장: 필수 필드가 적절히 초기화되지 않은 경우, 객체의 인스턴스화 과정에서 컴파일 타임 에러를 방지하고, 런타임에 예상치 못한 동작을 예방할 수 있습니다.
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class User {
    private final String name; // final 필드, 생성자에 포함됨
    private final int age;     // final 필드, 생성자에 포함됨
    @NonNull
    private String email;      // @NonNull 어노테이션 적용, 생성자에 포함됨
}

public User(String name, int age, String email) {
    if (email == null) {
        throw new NullPointerException("email is marked non-null but is null");
    }
    this.name = name;
    this.age = age;
    this.email = email;
}

사용 시 유의점:

  1. @NonNull과 예외 처리: @NonNull 어노테이션이 적용된 필드는 생성자에서 null 체크를 자동으로 추가합니다. 이는 null 값을 전달했을 때 NullPointerException을 발생시키므로, 사용자는 이를 명확히 인지하고 적절한 예외 처리를 고려해야 합니다.
  2. 코드의 명확성: @RequiredArgsConstructor를 사용하면 생성자에 자동으로 포함될 필드가 명시적으로 표시되지 않습니다. 이로 인해 코드를 처음 접하는 다른 개발자가 클래스의 생성자를 이해하기 어려울 수 있습니다.
  3. 클래스 설계: final 필드와 @NonNull 필드만 생성자에 포함되므로, 클래스 설계 시 이를 고려하여 필드를 선언해야 합니다. 클래스의 불변성이 중요하거나 필수적인 필드가 명확한 경우에 특히 유용합니다.

@Data

Lombok 라이브러리의 @Data 애노테이션은 자바 클래스에 대해 흔히 필요한 여러 가지 기능을 한 번에 제공하는 종합 애노테이션입니다. 이 애노테이션은 클래스에 대한 getter, setter, toString, equals, hashCode 메소드와 함께 필요한 생성자까지 자동으로 생성합니다. @Data는 주로 데이터를 저장하는 객체, 즉 데이터 모델이나 DTO(Data Transfer Object)에서 사용되며, 많은 반복적인 코드를 간소화하여 개발자의 편의성을 크게 향상시킵니다.

@Data 애노테이션의 주요 기능

자동 생성되는 메소드들

  • Getter와 Setter: 클래스의 모든 필드에 대해 getter 메소드와 setter 메소드를 생성합니다. 필드가 final인 경우에는 setter가 생성되지 않습니다.
  • @ToString: 객체의 문자열 표현을 제공하는 toString() 메소드를 생성합니다. 기본적으로 클래스 이름과 함께 모든 필드의 이름과 값을 포함합니다.
  • @EqualsAndHashCode: 두 객체가 같은지 비교하는 equals() 메소드와 객체의 해시 코드를 반환하는 hashCode() 메소드를 생성합니다. 이 메소드들은 객체의 모든 필드를 기반으로 계산됩니다.
  • @RequiredArgsConstructor: final 필드 또는 @NonNull 어노테이션이 붙은 필드를 매개변수로 받는 생성자를 생성합니다. 이는 객체의 필수 필드가 생성 시점에 초기화될 수 있도록 보장합니다.

사용상의 유의점

  • 성능 문제: equals()와 hashCode() 메소드가 객체의 모든 필드를 사용하여 계산됨으로써, 필드가 많거나 복잡한 객체에서 성능 저하가 발생할 수 있습니다.
  • 순환 참조 문제: @ToString에서 순환 참조가 발생할 경우, 스택 오버플로 에러가 발생할 수 있습니다. 예를 들어, 서로 다른 객체가 상호 참조하는 경우에 toString() 호출이 무한 루프에 빠질 수 있습니다.
  • 보안 문제: toString() 메소드가 민감한 정보를 포함한 모든 필드를 출력하기 때문에 로깅 등에서 보안상의 문제가 발생할 수 있습니다. 예민한 데이터는 @ToString.Exclude를 사용하여 제외해야 합니다

@Data 애노테이션은 데이터를 다루는 객체에 대한 코드를 매우 간결하게 만들어 주지만, 사용할 때는 성능, 보안, 그리고 적절한 경우에만 사용하는 것이 중요합니다. 데이터 모델이나 DTO에서 자주 사용되며, 반복적인 코드를 줄이고자 할 때 매우 유용합니다.

@Value

Lombok 라이브러리의 @Value 애노테이션은 클래스를 불변(immutable) 객체로 만들기 위해 사용됩니다. @Value는 클래스의 모든 필드를 final로 설정하고, 기본적으로 private과 final로 선언된 클래스로 만들어 객체의 불변성을 보장합니다. 이 애노테이션은 @Data 애노테이션과 유사한 기능을 제공하지만, 불변 객체 생성에 특화된 기능을 제공하는 차이가 있습니다.

@Value 애노테이션의 주요 기능

  • 모든 필드를 final로 선언: 객체 생성 후 필드의 상태가 변경될 수 없도록 모든 필드를 final로 선언합니다.
  • 기본 생성자를 private으로 생성: 외부에서 객체를 무분별하게 생성할 수 없도록 기본 생성자를 private으로 만듭니다. 객체의 인스턴스는 오직 정의된 방법(보통 정적 팩토리 메소드)을 통해서만 생성할 수 있습니다.
  • Getter 메소드 제공: 불변 필드의 값을 외부에서 접근할 수 있도록 Getter 메소드를 자동으로 생성합니다. Setter 메소드는 생성되지 않습니다.
  • @ToString, @EqualsAndHashCode 포함: @ToString과 @EqualsAndHashCode 애노테이션 기능이 내장되어 있어 객체의 문자열 표현과 동등성 검사를 쉽게 할 수 있습니다.
  • 모든 필드를 생성자 인자로 받는 생성자 생성: 클래스의 모든 필드를 인자로 받는 생성자를 자동으로 생성합니다. 이 생성자는 필드의 불변성을 유지하는 데 필요합니다.

@Builder

Lombok 라이브러리의 @Builder 애노테이션은 빌더 패턴(Builder Pattern)을 쉽게 구현할 수 있도록 해주는 기능을 제공합니다. 빌더 패턴은 객체 생성 과정을 단계별로 분리하여 최종적으로 복잡한 객체를 조립할 수 있게 해주는 디자인 패턴입니다. 이 패턴은 특히 많은 수의 매개변수를 갖는 객체를 생성할 때, 매개변수의 순서를 신경 쓰지 않고 명확하게 객체를 생성할 수 있도록 도와줍니다.

@Builder의 주요 기능

  • 체이닝 방식의 API 제공: @Builder를 사용하면 메소드 체이닝을 통해 객체의 필드 값을 설정할 수 있는 API가 자동으로 생성됩니다. 각 필드 값 설정 메소드는 객체의 해당 필드 값을 설정한 뒤, 객체 자신을 반환합니다.
  • 객체의 일관성 유지: 빌더 패턴을 사용하면 객체의 필드를 초기화하는 과정에서 일관성을 유지할 수 있습니다. 객체가 완전히 생성된 후에 사용할 수 있도록 하여, 일부 초기화되지 않은 객체가 사용되는 것을 방지합니다.
  • 필드별 선택적 할당: 객체 생성 시 필요한 필드만 설정할 수 있으며, 각 필드는 선택적으로 값을 할당받을 수 있습니다. 이는 선택적 매개변수가 많은 경우 특히 유용합니다.
import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Product {
    private final String name;
    private final int price;
    private final String description;
}

public class BuilderExample {
    public static void main(String[] args) {
        Product product = Product.builder()
                                 .name("Coffee")
                                 .price(15)
                                 .description("Freshly brewed coffee")
                                 .build();

        System.out.println(product);
    }
}

위의 코드에서 Product 클래스에 @Builder를 적용하면, Lombok은 자동으로 빌더 클래스를 생성합니다. 이 빌더 클래스를 통해 Product 객체를 생성할 때, 필드의 이름을 명시적으로 지정하며 값을 할당할 수 있습니다. build() 메소드는 최종적으로 설정된 값들을 가지고 Product 객체를 생성합니다.

사용상의 유의점

  • 불변성: 생성된 객체의 불변성을 보장하려면, 객체의 필드를 final로 선언하고, setter를 제공하지 않아야 합니다. @Builder는 이런 패턴에 적합하며, 객체가 한 번 생성된 후에는 변경되지 않도록 할 수 있습니다.
  • 기본값 설정: 빌더를 사용할 때 필드에 기본값을 설정하고 싶다면, 빌더의 필드 선언 시 초기값을 할당할 수 있습니다.
  • 필수 값 검증: 생성자나 설정 메소드에서 일반적으로 수행하는 필수 값 검증을 빌더에서 수행하려면, build() 메소드에서 이러한 검증 로직을 추가해야 할 수도 있습니다.

@Slf4j

Lombok 라이브러리의 @Slf4j 애노테이션은 클래스에 로깅 기능을 손쉽게 추가할 수 있도록 해주는 기능입니다. 이 애노테이션을 사용하면 Simple Logging Facade for Java (SLF4J)에 대한 로거 인스턴스를 자동으로 생성해줍니다. SLF4J는 Java에서 널리 사용되는 로깅 추상 계층이며, 다양한 로깅 구현체(Logback, log4j)를 통일된 방식으로 사용할 수 있게 도와줍니다.

@Slf4j의 주요 기능

  • 자동 로거 인스턴스 생성: @Slf4j 애노테이션을 사용하면 클래스 내부에 private static final 로거 인스턴스가 자동으로 생성됩니다. 이 로거를 통해 로그 메시지를 기록할 수 있습니다.
  • 간편한 로깅 설정: 로깅을 위해 별도의 로거 객체를 수동으로 생성하고 구성할 필요 없이, 애노테이션 한 줄로 로깅 준비가 완료됩니다.
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class LogExample {
    public void performSomeTask() {
        log.debug("Starting some task");
        // task implementation
        log.info("Task completed successfully");
        try {
            // some code that might throw an exception
        } catch (Exception e) {
            log.error("Error occurred while performing task", e);
        }
    }
}

위 예제에서 @Slf4j를 클래스 LogExample에 적용하였습니다. 이 클래스 내의 메소드에서는 log 객체를 통해 로그를 기록할 수 있습니다. 여기서 debug, info, error 메소드들은 각각 디버그, 정보, 오류 로그를 기록합니다.

로깅 레벨

  • TRACE: 가장 상세한 로그를 기록합니다.
  • DEBUG: 개발 과정에서 유용한 디버깅 정보를 제공합니다.
  • INFO: 일반적인 정보를 기록하는 데 사용합니다.
  • WARN: 잠재적인 문제를 예고하는 로그를 기록합니다.
  • ERROR: 실제 오류를 기록할 때 사용합니다.

사용상의 유의점

  1. 성능 고려: 로깅은 시스템의 성능에 영향을 줄 수 있습니다. 따라서 로깅 레벨을 적절히 설정하여 불필요한 로그가 너무 많이 기록되지 않도록 조절하는 것이 중요합니다.
  2. 보안 문제: 로그에 민감한 정보가 포함되지 않도록 주의해야 합니다. 로그를 통해 비밀번호나 개인정보가 노출되는 것을 방지해야 합니다.
  3. 로깅 구성: @Slf4j는 로거를 제공하지만, 로깅 구현체와 로그 포맷, 로그 레벨 등은 별도로 설정 파일을 통해 관리해야 합니다. 예를 들어, Logback이나 log4j의 설정 파일에서 이를 구성할 수 있습니다.