[Spring] Lombok 올바른 사용법

enjoy89·2023년 11월 30일
1
post-thumbnail
post-custom-banner

Lombok이란

Lombok은 자바 컴파일 시점에서 반복적인 코드를 줄이기 위해 사용되는 라이브러리 중 하나이다. 특정 어노테이션을 사용하여 코드를 간소화하고 가독성을 높이는데 많은 도움이 된다.

우리는 Spring에서 Lombok을 사용하여 매우 편하고 빠르게 개발을 할 수 있다. 하지만 잘못 사용하면 위험성이 매우 높은 것이 바로 Lombok이다.
여러 강의 내용에서 @Data 어노테이션은 흔히 사용을 지양해야 하고, @Setter 어노테이션은 가급적 열어두지 말라는 말을 많이 들었다. 별 생각 없이 하지말라는건 하지 않았지만, 왜 사용하면 안 되는지 그 이유가 궁금했다.

지금부터 자주 사용되는 Lombok 어노테이션 종류와, 올바른 사용방법을 하나씩 알아보도록 하자.



1. @Getter / @Setter

  • 가장 먼저 살펴볼 어노테이션은 @Getter@Setter이다. 이는 가장 많이 쓰이는 어노테이션으로 필드에 대한 getter 및 setter 메서드를 자동으로 생성해준다.
  • 사용방법은 아래와 같이 그냥 필드를 가지는 클래스 위에 선언해주면 된다.
    @Getter
    @Setter
    public class Member {
    
    	private Long id;
    	private String name;
    }
  • 이와 같이 @Getter 어노테이션을 사용함으로써 필드 id, name의 getId(), getName()메서드를 자동으로 생성해주고, @Setter 어노테이션을 사용함으로써 setId(), setName() 메서드가 자동으로 생성된다.

❗️ 주의할 점

  • 여기서 주의할 점이 하나 있다. @Getter 어노테이션의 경우 객체 필드를 읽는 동작이기 때문에 그다지 위험성이 있지는 않지만, @Setter 어노테이션의 경우 객체의 상태를 변경할 수 있는 동작이므로 객체의 안정성이 보장 받기는 힘들어진다.
  • Setter는 그 의도가 분명하지 않고, 무분별하게 사용할 경우 언제 어디서 객체의 상태가 변경되었는지 추적하기 힘든 상황이 벌어질 수 있다. 그러므로 필드값의 변경이 필요한 경우 Setter 보다는 더욱 의미 있는 메서드를 생성하여 사용하는 것이 좋다.
  • 아래는 객체의 상태를 업데이트 하는 동작을 @Setter 어노테이션을 사용하지 않고, 따로 update 라는 의름의 메서드를 생성하여 구현한 방식이다.
  • Setter와 동작은 같지만, 어노테이션을 사용하는 것 보다 값의 변경이 필요한 경우에만 update 메서드를 호출하여 사용한다면 객체의 안전성을 취할 수 있을 것이다.
        public void update(String name) {
        	this.name = name;
        }

2. @NoArgsConstructor / @AllArgsConstructor

  • @NoArgsConstructor 어노테이션은 아무런 파라미터가 없는 생성자를 자동으로 생성해주고, @AllArgsConstructor 어노테이션은 모든 필드를 파라미터로 받는 생성자를 자동으로 생성해준다.
@NoArgsConstructor
@AllArgsConstructor
public class Member {

	private Long id;
	private String name;

	// @NoArgsConstructor 동작 생략
	public Member() {
	}

	// @AllArgsConstructor 동작 생략
	public Member(Long id, String name {
		this.id = id;
		this.name = name;
	}
 }

❗️ 주의할 점

  • 보통 @NoArgsConstructor 어노테이션은 단독 사용하기 보다는 접근 권한을 protected 두고 외부에서 무분별한 객체 생성을 막는 방법으로 사용하는 것이 좋다.
  • JPA에서는 프록시를 생성하기 위해서 기본 생성자를 반드시 하나 가져야 하므로 생성자 접근 권한을 private 말고 protected으로 열어두길 권장하고 있다.
  • 아래와 같이 사용하면 된다.
    @NoArgsConstructor (access = AccessLevel.PROTECTED)
    @AllArgsConstructor
    public class Member {
    
    	private Long id;
    	private String name;
    }
    
  • 또한, @AllArgsConstructor 어노테이션 사용은 지양해야 한다. 이는 매우 편리하게 생성자를 만들어주지만, 별 생각없이 사용할 경우 치명적인 오류를 발생시킬 수 있다.
  • 왜냐하면 이 어노테이션은 클래스에 존재하는 모든 필드에 대한 생성자를 자동으로 생성하는데, 인스턴스 멤버의 선언 순서에 영향을 받기 때문에 두 변수의 순서를 바꾸면 생성자의 입력 값 또한 바뀌게 되어 이상한 값이 생성되기 때문이다.
  • 위의 Member 클래스의 id와 name의 변수의 순서를 바꾸어 생성자를 사용할 경우에는 자료형 오류가 발생하겠지만, 예를 들어 아래와 같이 필드가 하나 추가 된다면, name과 location의 값의 순서가 바뀌게 되어 엉뚱한 값이 생성될 것이다.
    private Long id;
    private String name;
    private String location;   // 추가된 필드
    
    Member member = new Member(1, "jeondui", "Chuncheon");  // 올바른 순서
    Member member = new Member(1, "Chuncheon", "jeondui");  // 잘못된 순서
    

3. @Data

  • 이는 @ToString, @EqualsAndHashCode, @Getter, @Setter, @RequiredArgsConstructor 를 모두 포함하는 어노테이션이다. 한 마디로 올인원이다. 강력한 어노테이션인 만큼 그에 따른 부작용도 많다.
  • 위에서 말한 어노테이션이 가지고 있는 문제점을 모두 가지고 있다. 그 중 @ToString 어노테이션에 대해 추가로 말해 보겠다.
  • @ToString 어노테이션은 필드 값들에 대한 ToString 메서드를 자동 생성해주는 기능인데, 만약 두 객체가 다대일 양방향 연관관계라고 가정한다면, 이때 ToString을 호출할시 서로 무한 순환 참조가 되어 stackoverflow가 발생한다.
  • 이러한 문제를 해결하기 위해서는 @ToString(exclude = "member") 처럼 옵션을 사용해서 특정 항목을 제외시키는 방법을 사용할 수 있다.
  • 이 외에도 @Data 어노테이션은 여러 위험성이 존재하므로 사용을 지양하는 것이 좋다.



4. @Builder

  • 빌더 패턴을 자동으로 생성해주며 객체를 생성할 때 가독성과 유연성을 높여주는 어노테이션이다. 빌더 패턴은 객체의 생성 과정을 단순화하며, 특히 많은 수의 선택적인 매개변수를 가진 객체를 생성할 때 효과적이다.
  • 그러므로 아래와 같이 생성자에 @Builder 어노테이션을 사용하여 의미 있는 객체를 생성할 수 있다.

public class Member {

	private Long id;
	private String name;

	@Builder
	public Member(Long id, String name {
		this.id = id;
		this.name = name;
	}
}

// builder를 이용하여 객체 생성
Member member = Member.builder()
                .id(1)
                .name("jeondui")
                .build();
  • 객체를 생성할 때 필요한 필드만 선택적으로 설정하며 훨씬 가독성이 높아진 것을 확인할 수 있다.



실제로 적용해보기

지금까지 Lombok의 자주 사용되는 어노테이션 종류와 올바른 사용방법에 대해 알아보았다. 이제 실제로 엔티티 클래스를 Lombok 어노테이션을 사용하여 만들어보자.

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "member")
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "member_id", nullable = false)
    private Long id;

    @Column(name = "member_name")
    private String name;

    @Builder
    public Member(Long id, String name) {
        this.id = id;
				this.name = name;
    }

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

@Data, @Setter, @AllArgsConstructor 어노테이션을 사용하지 않고, 빌더를 이용하여 의미 있고 안전한 객체 생성을 할 수 있게 되었다.

정리

지금까지 Lombok에서 제공하는 유용한 어노테이션에 대해 알아보았다.
아무 생각 없이 편리하다고 무작정 사용하는 것 보다는, 올바른 사용 방법과 위험성을 인지하고 나의 상황에 알맞게 활용하는 것이 중요한 것 같다.




Reference

https://www.nowwatersblog.com/springboot/springstudy/lombok

https://dev-jhl.tistory.com/entry/Lombok-올바른-Lombok-사용법-Builder

profile
Backend Developer 💻 😺
post-custom-banner

0개의 댓글