컨트롤러 어노테이션 @Controller를 붙이면 클래스가 스프링 빈에 등록되고 관리된다.
이를 컴포넌트 스캔이라고 하고, @Component 애노테이션이 있으면 스프링 빈에 자동으로 등록되는데,
@Controller, @Service, @Repository 등도 @Component를 포함하고 있기 때문에 스프링 빈에 등록되는 것이다.
MemberService를 컨트롤러마다 새로운 객체를 만들어서 사용하지 않고 (new MemberService())
스프링 컨테이너에 등록하여 사용할 수 있음
MemberController에서 MemberService의 생성자를 만들 때 @Autowired 어노테이션을 붙이면
스프링 컨테이너에서 미리 정의된 MemberService를 가져와 할당해준다.
이것을 의존성 주입이라고 하고, 좀 더 공부해봐야 더 알 것 같다. *
그런데 MemberController에 @Autowired를 붙이는 것 만으로는 의존성 주입도 안될 뿐더러 스프링 빌드조차 되지 않는다.
스프링 컨테이너에서 MemberService를 알 수 없기 때문이다.
그래서 MemberService 클래스에 @Service를 붙여야만 @Autowired를 쓸 수 있다.
MemberService 클래스 내에 있는 MemberRepository도 같은 방식으로 @Autowired를 쓰고,
이를 위해 @Repository 어노테이션을 MemberRepository에 붙여주어야 한다.
물론 @Service, @Repository 어노테이션을 붙이면 @Controller를 붙여서 @GetMapping을 사용하는 것처럼
스프링의 기능을 사용할 수 있겠지만 @Autowired는 왜 굳이 @Controller - @Service, @Service - @Repository를
명시하기를 원하는 걸까
강의를 끝까지 듣고보니까 관계를 명시하기를 바라는 것이 아니고, MemberService가 스프링 빈으로 등록되어있지
않았기 때문에 @Autowired했는데 해당 컴포넌트를 찾을 수 없어 오류가 났던 것이다.
실제로 MemberService에 @Service가 아닌 @Component를 붙여주어도 오류없이 잘 실행된다.
의존성 주입에는 이번에 사용한 생성자 주입 외에도 필드 주입, setter 주입등이 있으나 의존 관계가 실행 중에
변하는 경우가 거의 없으므로 사용하지 않는다.
@Service, @Repository, @Autowired를 지우고 진행한다.
SpringConfig.java
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService(){
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository(){
return new MemoryMemberRepository();
}
}
초반에 배운
Controller - Service - Repository
로 연결되는 구조가 실제 annotation으로 명시를 해줘야 하는거였다니 신기하다.
그림 - 참조 스프링 입문 pdf
스프링 빈
+import를 보니 스프링 빈에서 빈은 bin이 아니고 콩을 의미하는 bean이다.
+스프링 핵심 원리 강의에서 DI, 컨테이너에 대한 자세한 내용을 설명해주신다한다.
HTML에서 Form으로 members/new에 submit했을 때, input 값 들을 받기 위해서 Controller에서
다음과 같이 작성해준다.
@PostMapping("members/new")
public String create(MemberForm memberForm){
Member member = new Member();
member.setName(memberForm.getName());
memberService.join(member);
return "redirect:/";
}
여기서 MemberForm은 name과 그 getter, setter가 포함된 별도의 클래스이다.
인터페이스의 다형성과 의존성 주입을 이용해 기존 코드를 전혀 손대지않고 설정만으로 구현 클래스를 변경
할 수 있다.
MemoryMemberRepository => JdbcMemberRepository.
이런게 객체지향의 매력이다.
@SpringBootTest: 스프링 컨테이너와 테스트를 함께 실행한다.
@Transactional: 테스트 케이스에 이 애노테이션이 있으면, 테스트 시작 전에 트랜잭션을 시작하고,
테스트 완료 후에 항상 롤백한다. DB에 데이터가 남지 않으므로 다음 테스트에 영향을 주지 않는다.
아니 이거때문에 30분가량 왜 저장안되는지 로그 찾아보고 구글링하고 있었다. 하필 비슷한 오류도 있었다.
통합 테스트를 이용하는 것보다 단위 테스트를 잘 만드는 것이 좋다고 말씀하셨다.
근데 이런 조그만 테스트를 만드는 데도 통합 테스트가 필요했는데 스프링에서 단위테스트가 얼마나 쓰일지
아직 잘 모르겠다.
JPA는 기존 반복 코드는 물론이고, 기본적인 SQL도 JAP가 직접 만들어 실행해준다.
단지 SQL 생산 뿐아니라 JPA를 사용함으로써 SQL과 데이터 중심 설계에서 객체 중심 설계로 패러다임을 전환할 수 있다.
리포지토리에 구현 클래스 없이 인터페이스 만으로 개발을 완료할 수 있다. CRUD기능도 제공한다.
스프링 데이터 JPA는 JPA를 편리하게 사용하도록 도와주는 기술이므로 JPA를 먼저 학습한 후에 스프링 JPA를 학습해야 한다.
실무에서는 JPA와 스프링 데이터 JPA를 기본으로 사용하고 복잡한 쿼리는 Querydsl이라는 라이브러리를 사용한다.
AOP가 필요한 상황
문제
=> Aspect Oriented Programming
실제 클래스의 복제본으로 프록시를 생성하여 실제 클래스를 조작한다.
jointPoint.proceed()를 통해 실제 클래스를 실행한다.