2일 차 TIL
오늘은 스프링 입문 강의 메모장 프로젝트 CRUD 파트인 1-17부터
IoC와 Bean 파트인 2-5까지 수강했다.
데이터를 저장하는 방법들이 어떤 흐름으로 발전해 왔는지에 대해서 순서대로 설명해 준다고 느꼈다.
스프링 입문 1강
DB사용 전)
데이터를 세션단위로 저장할 수 있었다. 서버를 재시작하면 데이터가 소멸한다.
- Map<Long,Memo> 사용해서 HashMap 구현체에 저장
DB 사용 후)
Mysql을 사용해서 DB를 영구적으로 관리한다.
1. JdbcTemplate 으로 데이터 저장하기
쿼리문을 작성해서 JdbcTemplate에 넘겨줘서 실행할 수 있다.
이때 Jdbc는 데이터베이스에는 여러 종류가 있는데
백엔드 서버(Spring boot)에서 각 DB별로 작성해야 하는 코드형식이 다르다.
커넥션을 연결하는 방법
SQL을 전달하는 방법
결과를 응답하는 방법 등
그래서 사용하는 DB를 바구면 작성했던 코드들을 전부 수정해야 한다.
하지만 Jdbc 를 통해 각 DB를 기준으로 코드를 작성하는 것이 아닌
개발자는 표준화된 JDBC에 맞춰서 코드를 작성하면 돼서
DB의 종류에 구애받지 않을 수 있다.
ex) JDBC 도입으로 Mysql -> PostgreSQL 유연한 DB 변경 가능
2. JPA로 데이터 저장하기
-> ORM을 통해 쿼리문을 직접 작성하지 않고 데이터를 생성/관리할 수 있다.
Map객체에 데이터를 저장하면?
- 서버를 껏다 켜면 없어진다.
하지만 DB에 저장하면?
- 데이터를 영구적으로 보관할 수 있다.
JPA는 ORM의 표준 명세로써 애플리케이션 서버와 JDBC 사이에서 동작된다.

JPA를 구현한 것중 사실상 표준으로 사용되는 것이 바로 Hibernate이다.
사실상 표준이라는 말은 기업간 경쟁으로 시장에서 결정되는 비 공식적 표준을 뜻한다.
스프링 입문 2강
이전에는 직접 JdbcTemplate를 생성하고 리포지토리와 서비스 클래스에 주입하는 방식이었다면
3 Layer Architecture를 도입해서
컨트롤러의 요청 수신/응답, 비즈니스 로직(사용자의 요구사항을 처리), DB CRUD 작업을 분리할 수 있었다.

또한 각 클래스를 Bean으로 등록해 관리하여
이미 있는 객체(Bean)를 파라미터로 넘겨받아 사용함으로써
객체의 중복 생성을 막을 수 있었다.
다시말해 의존성 주입(DI)을 통한 제어의 역전(IoC)으로
객체의 중복 생성을 해결한 것이다.
DI는 Gof의 디자인 패턴
IoC는 객체지향의 SOLID 원칙에서 나왔다.
즉 DI패턴을 사용하여 IoC 설계 원칙을 구현할 수 있다.
강하게 결홥된 클래스는 interface 없이 필요한 것을 직접 만들어서 사용한다.
public class Consumer {
void eat() {
Chicken chicken = new Chicken();
chicken.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.eat();
}
}
class Chicken {
public void eat() {
System.out.println("치킨을 먹는다.");
}
}
- "치킨"외에 다른 음식을 먹으려면 eat() 메서드 자체를 수정해야 함.
하지만 inteface 다형성의 원리를 사용하여 구현한다면?
public class Consumer {
void eat(Food food) {
food.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.eat(new Chicken());
consumer.eat(new Pizza());
}
}
interface Food {
void eat();
}
class Chicken implements Food{
@Override
public void eat() {
System.out.println("치킨을 먹는다.");
}
}
class Pizza implements Food{
@Override
public void eat() {
System.out.println("피자를 먹는다.");
}
}
- eat 메서드는 그대로 두고 구현체를 생성하거나 수정하면 된다.
제어의 역전(IoC)는 Consumer가 직접 Food를 만들어서 먹는 것과 달리
Food를 Consumer에게 전달해 주는 것을 말한다.
Consumer -> Food
Food -> Consumer
기존의 메모장 프로젝트 서비스 코드
public class MemoService {
private final JdbcTemplate jdbcTemplate;
public MemoService(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public MemoResponseDto createMemo(MemoRequestDto requestDto) {
// DB 저장
MemoRepository memoRepository = new MemoRepository(jdbcTemplate); // 객체 생성
...
}
public List<MemoResponseDto> getMemos() {
// DB 조회
MemoRepository memoRepository = new MemoRepository(jdbcTemplate); // 객체 생성
...
}
public Long updateMemo(Long id, MemoRequestDto requestDto) {
MemoRepository memoRepository = new MemoRepository(jdbcTemplate); // 객체 생성
...
}
public Long deleteMemo(Long id) {
MemoRepository memoRepository = new MemoRepository(jdbcTemplate); // 객체 생성
...
}
}
- 서비스(Consumer)가 리포지토리(Food)를 직접 만들어서 사용함 -> 객체 중복 생성 문제 발생
왜냐하면 리포지토리에게 파라미터로 JdbcTemplate로 넘겨줘야 하기 때문
IoC를 적용한 서비스 코드
public class MemoService {
// 멤버 변수 선언
private final MemoRepository memoRepository;
// 생성자: MemoService(JdbcTemplate jdbcTemplate)가 생성될 때 호출됨
public MemoService(JdbcTemplate jdbcTemplate) {
this.memoRepository = new MemoRepository(jdbcTemplate); // 멤버 변수 생성
}
public MemoResponseDto createMemo(MemoRequestDto requestDto) {
// RequestDto -> Entity
Memo memo = new Memo(requestDto);
// DB 저장
Memo saveMemo = memoRepository.save(requestDto);
// Entity -> ResponseDto
MemoResponseDto memoResponseDto = new MemoResponseDto(saveMemo);
return memoResponseDto;
}
...
}
- 리포지토리(Food)를 서비스(Consumer)에게 전달함 -> 객체 중복 생성 해결
강한 결합 상태의 메모장 프로젝트에서 제어의 흐름은 Controller ⇒ Service ⇒ Repository
하지만 DI 즉, 의존성 주입을 통해 제어의 흐름을 Repository ⇒ Service ⇒ Controller로 역전함으로써
효율적인 코드로 바뀌었습니다.
JdbcTemplate를 각 레이어에서 생성자로 한 번만 주입받기에
객체 중복 생성을 해결할 수 있다.
@Bean
근데 이 의존성을 주입받으려면 일단 해당 객체가 생성되어야 한다.
이를 Bean으로 객체를 등록하고, 스프링이 관리해줌으로써
개발자가 따로 new 키워드를 통해 생성하지 않아도 주입할 수 있다.
컨트롤러 - 서비스 - 리포지토리는 각각
@Controller - @Service - @Repository 어노테이션을 붙여서 Bean으로 등록할 수 있다.

Bean은 @ComponentScan으로 스프링이 등록해 준다.
의존성은 @Autowired를 통해 주입할 수 있지만
생성자가 1개인 경우 Spring 4.3 버전부터 생략가능하다.
아니면 @RequiredArgsConstruct를 사용해서 자동생성할 수도 있다.
수동으로 스프링에 등록된 Bean을 가져와서 의존성을 주입할 수도 있다.
ApplicationContext 객체를 사용하는 방법이다.
@Component
public class MemoService {
private final MemoRepository memoRepository;
public MemoService(ApplicationContext context) {
// 1.'Bean' 이름으로 가져오기
MemoRepository memoRepository = (MemoRepository) context.getBean("memoRepository");
// 2.'Bean' 클래스 형식으로 가져오기
// MemoRepository memoRepository = context.getBean(MemoRepository.class);
this.memoRepository = memoRepository;
}
...
}

Bean의 작명은 객체의 첫 글자만 소문자로 바꿔서 등록된다.
ex) MemoRepository -> memoRepository
'내배캠' 카테고리의 다른 글
| [내일배움캠프 본캠프] 4일 차 TIL Bean 수동 등록, 쿠키/세션 (0) | 2026.02.14 |
|---|---|
| [내일배움캠프 본캠프] 3일 차 TIL 영속성 컨텍스트 (0) | 2026.02.12 |
| [내일배움캠프 본캠프] 1일 차 TIL 상품-주문 미니프로젝트 피드백 (0) | 2026.02.10 |
| [내일배움캠프 사전캠프] 3일 차 TIL Jackson (0) | 2026.02.06 |
| [내일배움캠프 사전캠프] 2일 차 TIL 상품-주문 미니프로젝트 (0) | 2026.02.05 |
