생략된 annotation
@RestController
@RequestMapping("/api/v1")
public class EssentialController {
private final EssentialService essentialService;
// 여기에 생략된 것이 있음
public EssentialController(EssentialService essentialService) {
this.essentialService = essentialService;
}
@GetMapping("/date")
...
Core님 왈, "new 키워드가 없는데 왜 작동할까요?"라는 의문점을 남겨주셨다. 생각을 해보면 이상하긴 하다.
일반적인 java 코드에서 constructor에 EssentialService를 사용할 수 있게끔 설정을 하려면, 이렇게 dependency를 설정했었다:
private final EssentialService essentialService;
public EssentialController() {
essentialService = new EssentialService();
}
하지만 처음 올린 코드에선 이런 방식이 아닌, Dependency Injection(의존성 주입) 중 Constructor Injection을 사용해 객체의 dependency를 설정한다:
@Autowired
public EssentialController(EssentialService essentialService) {
this.essentialService = essentialService;
}
그리고 이 때 @Autowired annotation을 사용한다. 즉, 생략된 annotation은 @Autowired이다.
Dependency Injection을 사용할 경우, runtime에 결합을 결정지어 클래스 간 결합도가 낮아지게 된다.
(이 부분을 Spring에 대해 예시를 든 레퍼런스를 찾고 싶었으나, 제가 못 찾은건지 다들 간단하게 interface 상속에서 polymorphism으로 구현할 때의 문제만을 예시로 들더라고요... )
이는 곧 SOLID 원칙 중 Open Closed Principle를 지키는 데에 도움을 준다.
Constructor Injection을 사용하는 이유:
필수적으로 사용해야 하는 dependency가 없을 경우, Instance를 만들지 못하도록 강제할 수 있다.
따라서, NullPointerException을 방지할 수 있다.
그리고, 이때 Constructor가 하나일 경우 @Autowired를 생략해도 작동한다. (Spring 4.3 이후)
결론: SOLID 원칙과 dependency 관련 오류를 방지하기 위해 @Autowired annotation이 사용되며, 이는 생략이 가능하다.
Integer vs int 비교
public record ApiResponse(Integer id, String date, String subject, String content) {}
여기서 id가 왜 Integer인지에 대해 지적해주셨다.
세미나에선 'Integer 클래스의 사용하지 않는 method까지 함께 가져와질 수 있다'라고 하시며 굳이 이유가 없다면 int로 해도 상관 없을 거 같다 하셨다. 이외에도 Integer의 사용 여부를 결정할 수 있는 게 뭐가 있을까 생각해봤다.
우선 primitive data type, wrapper class 간 차이를 먼저 살펴보자.
primitive data type (int):
기본 초기화 0
null 불가, 따라서 NullPointerException 불가.
처리 과정 최적화됨
wrapper class (Integer):
null 가능
오토 박싱/언박싱을 거치면 성능에 약간의 영향 가능
여러 편의 method 제공
여기서 ID 값은 null이 될 이유가 없고, 단순 index의 역할만 수행하므로 int가 적합하다고 생각한다.
결론: 꼭 Integer가 필요한 상황이 아니면 int를 쓰는 게 좋고, 더 안전하다.
생략된 annotation @RestController @RequestMapping("/api/v1") public class EssentialController { private final EssentialService essentialService;
// 여기에 생략된 것이 있음 public EssentialController(EssentialService essentialService) { this.essentialService = essentialService; } @GetMapping("/date") ...
Core님 왈, "new 키워드가 없는데 왜 작동할까요?"라는 의문점을 남겨주셨다. 생각을 해보면 이상하긴 하다. 일반적인 java 코드에서 constructor에 EssentialService를 사용할 수 있게끔 설정을 하려면, 이렇게 dependency를 설정했었다: private final EssentialService essentialService;
public EssentialController() { essentialService = new EssentialService(); }
하지만 처음 올린 코드에선 이런 방식이 아닌, Dependency Injection(의존성 주입) 중 Constructor Injection을 사용해 객체의 dependency를 설정한다:
@Autowired public EssentialController(EssentialService essentialService) { this.essentialService = essentialService; }
그리고 이 때 @Autowired annotation을 사용한다. 즉, 생략된 annotation은 @Autowired이다. Dependency Injection을 사용할 경우, runtime에 결합을 결정지어 클래스 간 결합도가 낮아지게 된다. (이 부분을 Spring에 대해 예시를 든 레퍼런스를 찾고 싶었으나, 제가 못 찾은건지 다들 간단하게 interface 상속에서 polymorphism으로 구현할 때의 문제만을 예시로 들더라고요... ) 이는 곧 SOLID 원칙 중 Open Closed Principle를 지키는 데에 도움을 준다.
Constructor Injection을 사용하는 이유:
결론: SOLID 원칙과 dependency 관련 오류를 방지하기 위해 @Autowired annotation이 사용되며, 이는 생략이 가능하다.
우선 primitive data type, wrapper class 간 차이를 먼저 살펴보자. primitive data type (int):
wrapper class (Integer):
여기서 ID 값은 null이 될 이유가 없고, 단순 index의 역할만 수행하므로 int가 적합하다고 생각한다. 결론: 꼭 Integer가 필요한 상황이 아니면 int를 쓰는 게 좋고, 더 안전하다.