김영한 스프링 입문 공부 (완)

기석·2022년 4월 27일
1
post-thumbnail

컴포넌트 스캔


컨트롤러 어노테이션 @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, 컨테이너에 대한 자세한 내용을 설명해주신다한다.

Spring MVC


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가 포함된 별도의 클래스이다.

개방 폐쇄 원칙 (OOP, Open-Closed Principle)


인터페이스의 다형성과 의존성 주입을 이용해 기존 코드를 전혀 손대지않고 설정만으로 구현 클래스를 변경
할 수 있다.
MemoryMemberRepository => JdbcMemberRepository.
이런게 객체지향의 매력이다.

Spring 통합 테스트


@SpringBootTest: 스프링 컨테이너와 테스트를 함께 실행한다.
@Transactional: 테스트 케이스에 이 애노테이션이 있으면, 테스트 시작 전에 트랜잭션을 시작하고,
테스트 완료 후에 항상 롤백한다. DB에 데이터가 남지 않으므로 다음 테스트에 영향을 주지 않는다.
아니 이거때문에 30분가량 왜 저장안되는지 로그 찾아보고 구글링하고 있었다. 하필 비슷한 오류도 있었다.

통합 테스트를 이용하는 것보다 단위 테스트를 잘 만드는 것이 좋다고 말씀하셨다.
근데 이런 조그만 테스트를 만드는 데도 통합 테스트가 필요했는데 스프링에서 단위테스트가 얼마나 쓰일지
아직 잘 모르겠다.

스프링 DB 접근 기술


  • 순수 Jdbc: 직접 관래해야하는 connection, close, sql, 방대한 예외처리
  • 스프링 JdbcTemplate: sql query와 처리 함수정도만 작성하면 됨
  • JPA: JPA를 이용해 객체 중심으로 데이터를 다룰 수 있는 JPQL을 사용
  • 스프링 데이터 JPA: JPA를 더 쉽게 사용하려고 묶은 프레임워큰데 인터페이스만 있어도 동작이 된다.

JPA


JPA는 기존 반복 코드는 물론이고, 기본적인 SQL도 JAP가 직접 만들어 실행해준다.
단지 SQL 생산 뿐아니라 JPA를 사용함으로써 SQL과 데이터 중심 설계에서 객체 중심 설계로 패러다임을 전환할 수 있다.

스프링 데이터 JPA


리포지토리에 구현 클래스 없이 인터페이스 만으로 개발을 완료할 수 있다. CRUD기능도 제공한다.

스프링 데이터 JPA는 JPA를 편리하게 사용하도록 도와주는 기술이므로 JPA를 먼저 학습한 후에 스프링 JPA를 학습해야 한다.
실무에서는 JPA와 스프링 데이터 JPA를 기본으로 사용하고 복잡한 쿼리는 Querydsl이라는 라이브러리를 사용한다.

AOP


AOP가 필요한 상황

  • 모든 메소드의 호출 시간을 측정하고 싶다면
  • 공통 관심 사항 vs 핵심 관심 사항
  • 회원 가입 시간, 회원 조회 시간을 측정하고 싶다면?

문제

  • 회원가입, 회원 조회에 시간을 측정하는 기능은 핵심 관심 사항이 아니다.
  • 시간을 측정하는 로직과 핵심 비즈니스의 로직이 섞여서 유지보수가 어렵다.
  • 시간을 측정하는 로직을 별도의 공통 로직으로 만들기 굉장히 어렵다.
  • 시간을 측정하는 로직을 변경할 때 모든 로직을 찾아가면서 변경해야 한다.

=> Aspect Oriented Programming

  • 회원가입, 회원 조회 등 핵심 관심사항과 시간을 측정하는 공통 관심 사항을 분리한다.
  • 시간을 측정하는 로직을 별도의 공통 로직으로 만들었다.
  • 핵심 관심 사항을 깔끔하게 유지할 수 있다.
  • 변경이 필요하다면 이 로직만 변경하면 된다.
  • 원하는 적용 대상을 선택할 수 있다.

스프링 AOP 동작 방식


실제 클래스의 복제본으로 프록시를 생성하여 실제 클래스를 조작한다.
jointPoint.proceed()를 통해 실제 클래스를 실행한다.

profile
블로그 이사갔어요 https://kiseoky.tistory.com

0개의 댓글