일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 백준
- UXUIPrimary
- 백엔드개발자
- 백엔드 부트캠프
- 부트캠프
- UXUI기초정복
- UXUI챌린지
- baekjoon
- Be
- 백엔드
- Java
- 환급챌린지
- 티스토리챌린지
- 오픈챌린지
- 디자인교육
- 디자인강의
- 내일배움카드
- Spring
- KDT
- 오픈패스
- 국비지원취업
- 객체지향
- 국비지원
- 내일배움캠프
- 패스트캠퍼스
- 국비지원교육
- mysql
- OPENPATH
- 오블완
- 디자인챌린지
- Today
- Total
군만두의 IT 공부 일지
[1주차] 내일배움캠프 Spring Java 심화 부트캠프 3기 - IoC와 DI 본문
오늘은 객체지향 책을 읽으면서 봤던 의존성 주입(DI: Dependency Injection), 제어의 역전(IoC)에 대해서 실제 코드로 학습을 진행했다. 먼저 주요 용어에 대해서 알아본다.
- 의존성: 객체 간의 관계에서 한 객체가 다른 객체를 사용하는 상황
- 주입: 코드에서 여러 방법을 통해 필요로 하는 객체를 해당 객체에 전달하는 것
- 제어의 역전: 객체의 생성, 생명주기, 의존성 관리를 개발자가 아닌 프레임워크나 컨테이너가 대신 하는 디자인 원칙
@RestController
@RequestMapping("/api")
public class MemoController {
private final MemoService memoService;
public MemoController(JdbcTemplate jdbcTemplate) {
this.memoService = new MemoService(jdbcTemplate);
}
@PostMapping("/memos")
public MemoResponseDto createMemo(@RequestBody MemoRequestDto requestDto) {
return memoService.createMemo(requestDto);
}
@GetMapping("/memos")
public List<MemoResponseDto> getMemos() {
return memoService.getMemos();
}
@PutMapping("/memos/{id}")
public Long updateMemo(@PathVariable Long id, @RequestBody MemoRequestDto requestDto) {
return memoService.updateMemo(id, requestDto);
}
@DeleteMapping("/memos/{id}")
public Long deleteMemo(@PathVariable Long id) {
return memoService.deleteMemo(id);
}
}
public class MemoService {
private final MemoRepository memoRepository;
public MemoService(JdbcTemplate jdbcTemplate) {
this.memoRepository = new MemoRepository(jdbcTemplate);
}
public MemoResponseDto createMemo(MemoRequestDto requestDto) {
Memo memo = new Memo(requestDto);
Memo saveMemo = memoRepository.save(memo);
MemoResponseDto memoResponseDto = new MemoResponseDto(saveMemo);
return memoResponseDto;
}
public List<MemoResponseDto> getMemos() {
return memoRepository.findAll();
}
public Long updateMemo(Long id, MemoRequestDto requestDto) {
Memo memo = memoRepository.findById(id);
if (memo != null) {
memoRepository.update(id, requestDto);
return id;
} else {
throw new IllegalArgumentException("선택한 메모는 존재하지 않습니다.");
}
}
public Long deleteMemo(Long id) {
Memo memo = memoRepository.findById(id);
if (memo != null) {
memoRepository.delete(id);
return id;
} else {
throw new IllegalArgumentException("선택한 메모는 존재하지 않습니다.");
}
}
}
위 코드에서 MemoService와 MemoRepository 사이의 강한 결합(strong coupling)을 확인할 수 있다.
public MemoController(JdbcTemplate jdbcTemplate) {
this.memoService = new MemoService(jdbcTemplate);
}
...
public MemoService(JdbcTemplate jdbcTemplate) {
this.memoRepository = new MemoRepository(jdbcTemplate);
}
MemoService 클래스의 생성자에서 MemoRepository 인스턴스를 직접 생성하고 있다. 또한, MemoController 클래스에서도 생성자에 MemoService를 직접 생성하고 있다.
제어의 흐름이 MemoController → MemoService → MemoRepository로 흐르고 있다. 강한 결합은 유연성이 떨어지고, 유지보수성 및 테스트를 어렵게 만든다.
"강한 결합" 해결할 방법
1. 각 객체에 대한 객체 생성은 딱 1번만!
2. 생성된 객체를 모든 곳에서 재사용!
3. 생성자 주입을 사용하여 필요로하는 객체에 해당 객체 주입!
위 내용을 바탕으로 코드를 아래와 같이 수정할 수 있다. MemoController와 MemoService에서 JdbcTemplate을 MemoRepository에 주입할 필요가 없어졌다. DI를 사용하면 MemoRepository → MemoService → MemoController로 제어의 흐름이 역전된 것을 확인할 수 있다.
public MemoController(MemoService memoService) {
this.memoService = memoService;
}
...
public MemoService(MemoRepository memoRepository) {
this.memoRepository = memoRepository;
}
DI에서는 객체 생성이 우선된다. 이때 객체를 생성하고 관리하는 역할은 Spring 프레임워크가 대신해준다.
- 빈 (Bean): Spring이 관리하는 객체
- Spring IoC 컨테이너: Bean을 모아둔 컨테이너
Spring Bean을 등록하려면 @Component 애너테이션을 사용한다.
@Component
public class MemoService {
@Autowired
private MemoRepository memoRepository;
// ...
}
MemoSercive 객체를 생성할 때는 카멜 케이스(첫 문자는 소문자, 다음 단어의 첫 문자는 대문자)로 이름을 짓는다.
MemoService memoService = new MemoService();
Spring Bean을 사용할 때는 @Autowired 애너테이션을 사용한다. @Autowired 애너테이션을 적용하는 것은 Spring IoC 컨테이너에 의해 관리되는 클래스에서만 가능하다. 객체의 불변성 때문에 일반적으로는 생성자를 사용하여 DI한다.
- 필드 위에 @Autowired
- Bean을 주입할 때 사용할 메서드 위에 @Autowired
@Component
@RequiredArgsConstructor // final로 선언된 멤버 변수를 파라미터로 사용하여 생성자를 자동으로 생성합니다.
public class MemoService {
private final MemoRepository memoRepository;
// public MemoService(MemoRepository memoRepository) {
// this.memoRepository = memoRepository;
// }
...
}
Lombok의 @RequiredArgsConstructor를 사용하면, 생성자가 자동으로 주입되므로 생성자 생성 코드를 생략할 수 있다.
'개발일지 > 스파르타코딩클럽' 카테고리의 다른 글
[2주차] 내일배움캠프 Spring Java 심화 부트캠프 3기 - JPA 심화 (1) | 2025.02.10 |
---|---|
[1주차] 내일배움캠프 Spring Java 심화 부트캠프 3기 - JWT (1) | 2025.02.07 |
[1주차] 내일배움캠프 Spring 프로젝트 AWS - EC2, H2를 활용하여 배포하기 (1) | 2025.02.05 |
[1주차] 내일배움캠프 Spring Java 심화 부트캠프 3기 - JDBC와 JPA (0) | 2025.02.03 |
[1주차] 빗물 받는 르탄이 (0) | 2022.09.11 |