3Layer Architecture
- Presentation Tier (Controller) - client
일반 사용자가 직접 액세스 할 수 있는 계층- Logic Tier (Service) - application
비즈니스 로직이 실행되는 계층- Data Tier (Repository) - database
데이터 스토리지 계층
IoC, DI
DI 패턴을 사용하여 IoC 설계 원칙을 구현 함
DI (의존성 주입)
- 약한 결합도, 약한 의존성을 가지게 하는 것
- 필드,메서드,생성자를 통해 주입이 가능하지만 생성자를 통해 주입하는 것이 일반적
IoC (제어의 역전)
- DI를 통해 프로그램의 제어 흐름이 뒤바뀌는 것
Bean
- 스프링 프레임워크가 관리하고 있는 객체
- 외부에서 들어오는 객체를 사용 가능
- Bean으로 등록하고자 하는 클래스에 @Component를 붙이면 Bean으로 등록 됨
- Component가 등록되는 이유
- @SpringBootApplication 안에는 @ComponentScan이 들어있어 해당 패키지와 하위 패키지 내에 있는 @Component들을 찾아 Bean에 객체를 올리게 됨
- 원래 주입하는 필드,메서드,생성자에 @Autowired를 달아야함 (스프링 4.3버젼 이후로 생략이 가능, 생성자는 하나일 때만 가능)
- Bean으로 관리되고 있는 클래스만 @Autowired로 주입 가능
IoC Container
Bean들을 모아둔 공간
수동 주입도 가능
public MemoService(ApplicationContext context){
// 1. 'Bean' 이름으로 가져오기
MemoRepository memoRepository = (MemoRepository) context.getBean("memoRepository");
// 2. 'Bean' 클래스 형식으로 가져오기
MemoRepository memoRepository = context.getBean(MemoRepository.class);
this.memoRepository = memoRepository;
}
@Controller, @Service, @Repository
- 이 어노테이션들 안에는 @Component가 들어 있음
- 따라서 자동으로 Bean으로 관리 됨
- 해당 계층 역할을 하는 Bean 클래스라는 의미
MemoService.java
public MemoResponseDto createMemo(MemoRequestDto requestDto) {
// RequestDto -> Entity
Memo memo = new Memo(requestDto);
// DB 저장
Memo saveMemo = memoRepository.save(memo);
// Entity -> ResponseDto
MemoResponseDto memoResponseDto = new MemoResponseDto(saveMemo);
return memoResponseDto;
}
MemoRepository.java
public Memo save(Memo memo) {
// DB 저장
KeyHolder keyHolder = new GeneratedKeyHolder(); // 기본 키를 반환받기 위한 객체
String sql = "INSERT INTO memo (username, contents) VALUES (?, ?)";
jdbcTemplate.update(con -> {
PreparedStatement preparedStatement = con.prepareStatement(sql,
Statement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1, memo.getUsername());
preparedStatement.setString(2, memo.getContents());
return preparedStatement;
},
keyHolder);
// DB Insert 후 받아온 기본키 확인
Long id = keyHolder.getKey().longValue();
memo.setId(id);
return memo;
}
MemoService.java의 아래 코드가 오타가 나서 1번이 아니라 2번으로 실행되는 강의가 있었다.
// Entity -> ResponseDto
1. MemoResponseDto memoResponseDto = new MemoResponseDto(saveMemo);
// Entity -> ResponseDto
2. MemoResponseDto memoResponseDto = new MemoResponseDto(memo);
강의를 보면서 저거 오류가 나겠다 싶었는데 제대로 작동되는것을 보고 왜 저럴까 하다가 강의를 멈추고 하나하나 생각해보았다.
MemoRepository.java를 천천히 보니 requestDto의 값은 DB에 저장된다는 것은 알게되었다. 하지만 MemoRepository.java에서 memo.setId(id)로 설정한 id값이 MemoService.java에 어떻게 넘어가는지가 이해가 안되다가 며칠 전에 배운 JVM 구조를 떠올리게 되었다.

위 그림처럼 자바의 객체는 Heap 영역에 저장되므로 주소 값에 있는 값 자체가 memo.setId(id)를 통해 변경이 되었다는 것을 알았다. (얕은 복사)
// DB 저장
Memo saveMemo = memoRepository.save(memo);하지만 대충 프린트로 두 곳의 주소 값을 찍어보니 같은 곳을 가르키고 있었다. saveMemo는 따로 객체가 생성된게 아니라 memo의 주소값을 저장한 것이므로 성능에 문제가 없겠다는 생각을 했다. savaMemo는 개발 편의상 따로 만든 것 같다.System.out.println(saveMemo.toString()+"\n"+memo.toString());
- 스프링을 기초부터 차근차근 배우는데 한번은 배웠던 내용이라 익숙하기도 하고 아직은 어렵기도 하다