백기선님의 스프링프레임워크 입문을 수강한 후 하는 기록입니다.
무료강의이며 1시간 30분정도 되기 때문에 금방 들을 수 있습니다. Spring petClinic 이라는 샘플 프로젝트를 기반으로 강의를 진행하지만, 굳이 따라하지 않고 봐도 좋을 것 같습니다.
제 생각에는 스프링을 자주 써보긴 했지만 왠지 알고 쓰는 것 같진 않을때? 한번 훑으면 좋을 것 같습니다 .
아래는 강의 목차입니다.
섹션 1. Inversion of Control
IoC 는 DI, AOP 와 더불어 스프링 프레임워크의 핵심 기술이다. 한글로 풀어쓰면 제어의 역전인데, 사실 제어의 역전은 꼭 의존성 역전만을 의미하진 않지만, 주로 DI 패턴과 함께 등장하는 것은 사실이다.
@RestController
public class StudyController {
private StudyService studyService = new StudyService();
@GetMapping("/study")
public ResponseEntity<Void> study(@RequestBody StudyRequestDto studyRequestDto){
studyService.study(studyRequestDto);
return new ResponseEntity<>(HttpStatus.OK);
}
}
@RestController
public class StudyController {
private final StudyService studyService;
@Autowired
public StudyController(StudyService studyService) {
this.studyService = studyService;
}
@GetMapping("/study")
public ResponseEntity<Void> study(@RequestBody StudyRequestDto studyRequestDto){
studyService.study(studyRequestDto);
return new ResponseEntity<>(HttpStatus.OK);
}
}
상단의 코드는 Service를 직접 생성한다. 그렇기 때문에 Service를 임의로 조정할 수 없고 Controller 의 단위테스트가 어려워진다.
반면, 아래의 코드는 Service를 주입받는 방식을 사용한다(DI) 그렇기 때문에 이 서비스는 MockBean이 될 수도, 개발자가 임의로 만든 테스트용 서비스가 될 수도 있다.
그리고 Service와 같은 빈의 생명주기를 관리하여 주입해주는 것이 스프링의 IoC 컨테이너이다.
개발자는 두 번째 코드와 같은 방식으로 작성하며 "내가 이렇게 작성해도 누군가가 넣어주겠지" 라고 확신할 수 있다.
스프링의 IoC 컨테이너 중 가장 널리 쓰이는 것이 ApplicationContext이다.
이 또한 빈이기 때문에 불러와서 getBean을 호출할 수도 있지만, 실무에서도 매우 드문 일이라고 한다.
여기서 빈의 개념을 다시한번 정의하면 "IoC 컨테이너에서 생명주기를 관리하는 객체"로 정리할 수 있다.
1 - 1. 빈을 등록하는 방법
1. @ComponentScan
AnnotationProcessor에 의해 해당 애노테이션이 붙어있으면 @Component 가 붙어있는 클래스를 찾아 빈으로 등록한다. @Service, @Controller, @Repository 등도 그 내부에는 @Component 애노테이션이 숨어있다.
스프링부트를 사용하면 일반적으로 src 루트의 메인애플리케이션에 붙어있는 @SpringBootApplication 애노테이션에 @ComponentScan 이 숨어있다.
2. @Configuration 의 @Bean
@Configuration
public class DefaultConfig {
@Bean
public String hello(){
return "Hello";
}
}
1-2. 의존성을 주입하는 방법
@Autowird (@Inject, @Resource 와 같이 자바에서 지원하는 애노테이션도 있다.)
나는 항상 생성자 주입을 사용한다. 롬복과 final 키워드를 사용해서.
필드주입은 의존성 파악을 위한 가독성이 좋지 않다고 느꼈고, 세터는 의존성 변경에 대한 여지를 열어두기 때문에 매우 안좋다고 생각하기 때문이다.
이 강의에서도 아래와 같은 방법을 권장한다.
1순위) 생성자 - 반드시 필요한 의존성
2순위) 이미 사용중인 Setter가 있으면 Setter, 없으면 필드.
+ 번외) spring-data-jpa 에서 제공하는 JpaRepository가 @Repository 없이도 빈으로 등록되는 이유는?
spring-data-jpa 자체에 객체를 만들어서 ApplicationContext에 등록하는 기능이 구현되어있기 때문이다. ApplicationContext는 이와 같은 것도 가능하게 한다.
섹션 2. AoP
목적: 흩어진 코드를 한 곳에 모아라!
객체 A, B, C 는 모두 다른 책임이 있다. 그런데 동일한 코드가 사용된다면?
AoP를 이용하면 A,B,C 에 흩어진 동일한 로직을 Aspect로 정의한 클래스내에서 적용시킬 수 있다. 이를 통해 각 객체는 SRP 를 지킬 수 있게된다.
AoP를 구현하는 방법
1. ByteCode 조작
이미 컴파일되어 생성된 class파일에 부가기능을 하는 코드를 삽입한다.
2. Proxy 패턴
각 클래스를 감싸는 프록시객체를 만들어 부가기능을 프록시객체에게 위임한다.
Spring aop는 프록시패턴을 사용한다.
스프링 aop의 예제
@Transactional
@Transactional이 붙어있는 메서드는 aop를 통해 다음과 같은 로직이 자동으로 추가된다.(매우 단순화된 예제)
// 기존의 코드
@Transactional
public Long save(T entity){
Long id = repository.save(entity);
return id;
}
// AoP를 통해 실제로 동작하는 코드
public Long save(T entity){
try{
connection.setAutoCommit(false);
repository.save(entity);
connection.commit();
}catch(Exception ex){
// ... Rollback .../
}finally{
...
}
}
섹션 3. PSA(Portable Service Abstraction)
스프링을 수많은 PSA 로 구성되어있다.
PSA란 이식가능한 서비스추상화라는 뜻인데, 쉽게 말해 아주 잘 만들어진 "인터페이스"라는 의미이다.
스프링에서 제공하는 Resource, Validation, Transaction, 캐싱 등 수많은 애노테이션, 클래스들이 추상화된 인터페이스를 사용하고 있다.
'책, 강의 정리' 카테고리의 다른 글
[패스트캠퍼스] 나홀로 DDD 후기 (0) | 2020.04.26 |
---|