@AllArgsConstructor 및 @NoArgsConstructor의 접근 제한 설정 방법
MSA(Microservices Architecture) 환경에서는 각 서비스가 독립적으로 동작하며, 데이터 및 객체의 무분별한 생성 및 변경을 방지하는 것이 중요하다. 따라서 @AllArgsConstructor 및 @NoArgsConstructor의 접근 제한자를 적절히 설정하여 객체의 생성 및 변경을 제어해야 한다.
1. @AllArgsConstructor (모든 필드를 포함하는 생성자)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
설정 이유
1. 엔티티 객체의 직접적인 변경 방지
• 엔티티는 무분별하게 생성되거나 수정되어서는 안 되므로 **protected**로 설정하여 내부에서만 사용할 수 있도록 제한.
2. Spring Data JPA 및 ORM 사용을 고려
• JPA에서는 엔티티를 조회할 때 프록시 객체를 생성하는데, public 생성자가 없으면 객체를 생성할 수 없다.
• 하지만 외부에서 직접 엔티티를 생성하는 것은 지양해야 하므로 protected 수준으로 접근을 제한.
📌 적용 예시
@Getter
@Entity
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int price;
}
🛠 사용 예
// 잘못된 사용 (제한된 생성자 호출 불가)
// Product product = new Product(1L, "스마트폰", 1000); ❌
// 올바른 사용 (팩토리 메서드 또는 빌더 사용)
Product product = Product.createProduct("스마트폰", 1000);
2. @NoArgsConstructor (기본 생성자)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
설정 이유
1. JPA의 프록시 객체 생성을 허용해야 함
• JPA에서는 기본 생성자가 필요하므로 반드시 제공해야 하지만, 외부에서 직접 호출되는 것은 막아야 함.
• 따라서 @NoArgsConstructor(access = AccessLevel.PROTECTED)를 설정하여 엔티티 외부에서는 기본 생성자를 호출할 수 없도록 제한.
2. DTO 변환 및 직렬화(Serialization) 고려
• Jackson(JSON 변환 라이브러리)이나 Kafka 메시지 처리 시 기본 생성자가 필요할 수 있음.
• 하지만 엔티티의 경우, JSON 직렬화를 위한 DTO를 따로 만들어 사용하는 것이 일반적이므로 엔티티에 public 기본 생성자를 두지 않는 것이 좋음.
적용 예시
@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int price;
}
🛠 사용 예
// JPA가 기본 생성자를 사용하여 객체를 생성할 수 있음 (사용자 호출은 불가능)
Product product = new Product(); // ❌ (protected라서 외부에서 직접 호출 불가)
// JPA 내부에서는 사용 가능 (Spring이 프록시 객체를 만들 때 필요)
3. DTO 및 Service에서의 객체 생성 제한
DTO의 경우 public 생성자 허용
• DTO는 데이터를 담는 용도이므로 제한 없이 public 생성자를 허용하는 것이 일반적이다.
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class ProductDto {
private Long id;
private String name;
private int price;
}
엔티티 객체의 직접 생성 방지
• 엔티티는 @AllArgsConstructor 및 @NoArgsConstructor를 protected로 제한하고,
팩토리 메서드 또는 @Builder를 이용하여 생성하는 방식이 바람직함.
@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int price;
// 객체 생성을 위한 팩토리 메서드
public static Product createProduct(String name, int price) {
return new Product(null, name, price);
}
}
🛠 사용 예
Product product = Product.createProduct("스마트폰", 1000); // ✅ 올바른 사용 방식
4. @Builder와 함께 사용할 경우
빌더 사용 시 생성자 접근 제한 설정
• @Builder는 @AllArgsConstructor를 필요로 하지만, 엔티티가 직접 생성되는 것을 막아야 하므로 protected로 제한해야 한다.
@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@Builder
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int price;
}
🛠 사용 예
Product product = Product.builder()
.name("스마트폰")
.price(1000)
.build(); // ✅ 빌더를 통해서만 객체 생성 가능
5. 정리: MSA 환경에서 생성자 접근 제한 기준
적용 대상생성자 접근 제한 방식설정 이유
엔티티 클래스 (@Entity) | @NoArgsConstructor(access = AccessLevel.PROTECTED) | JPA 프록시 객체 생성을 허용하면서 외부 사용을 제한 |
@AllArgsConstructor(access = AccessLevel.PROTECTED) | 직접 객체 생성을 방지하고, 빌더 또는 팩토리 메서드 사용 유도 | |
DTO 클래스 | @NoArgsConstructor(access = AccessLevel.PUBLIC) | JSON 변환 및 직렬화 지원 |
@AllArgsConstructor(access = AccessLevel.PUBLIC) | DTO의 직렬화 및 데이터 전달 용도로 사용 | |
빌더 패턴 사용 (@Builder) | @AllArgsConstructor(access = AccessLevel.PROTECTED) | 직접 객체 생성을 방지하고 빌더 패턴 사용 강제 |
팩토리 메서드 제공 | public static 메서드로 생성 | 객체 생성 로직을 캡슐화 |
결론
MSA 환경에서는 무분별한 객체 생성을 방지하고, 올바른 방식으로 객체를 초기화할 수 있도록 접근 제한을 설정하는 것이 중요하다.
• 엔티티 클래스(@Entity)
• @NoArgsConstructor(access = AccessLevel.PROTECTED) → JPA를 위한 기본 생성자는 허용하지만, 외부 사용은 제한.
• @AllArgsConstructor(access = AccessLevel.PROTECTED) → 직접 객체 생성을 방지.
• @Builder 활용 시 생성자 호출을 막고 빌더만 사용 가능하도록 설정.
• DTO 클래스
• public 생성자 허용 (@NoArgsConstructor, @AllArgsConstructor) → JSON 변환 및 직렬화를 위해 필요.
• 팩토리 메서드 또는 @Builder 사용 권장
• 직접 객체 생성이 필요할 경우 public static 팩토리 메서드 제공.
이를 통해 MSA 환경에서 객체의 일관성을 유지하고, 올바른 방식으로 객체를 관리할 수 있도록 설계하는 것이 바람직하다. 🚀
'Spring' 카테고리의 다른 글
[Spring AOP] JDK Dynaic Proxy에서 내부호출이 안되는 이유 (0) | 2025.03.11 |
---|---|
[Spring AOP] @Transactional의 Proxy 작동 방식 (0) | 2025.03.11 |
[Lombok] @Builder를 클래스가 아닌 메서드에 적용하는 이유 (0) | 2025.03.11 |
[Spring/Serialization-Deserialization] Date, LocalDate, LocalDateTime 형변환 방법, 직렬화/역직렬화 문제 해결하기 (0) | 2025.03.07 |
[Github] Yml파일 서브모듈에서 불러와서 안전하게 사용하기 (0) | 2025.02.17 |