5. 스프링 IoC <스프링 IoC 컨테이너>
IoC 컨테이너는 ApplicationContext 또는 BeanFactory를 사용한다.(주로 전자)
ㄴ 소스코드를 직접 살펴보기엔 수준이 어렵다.
ㄴ 대신 알아 둘 만한 점은, 문서를 보면 ApplicationContext 가 BeanFactory를 상속받는다.
IoC 컨테이너의 주요한 일
ㄴ빈 만들고, 빈들 사이의 의존성을 엮어줌, 빈들 제공
ㄴ 의존성 주입은 빈 끼리만 가능하다!! 즉, IoC컨테이너 안의 객체끼리만 주입해준다.
(빈으로 등록되어있는지 확인하는 법? -> Intellij 사용할 시 클래스 이름 옆에 콩 아이콘을 확인할 수 있음..)
모든 빈 살펴보기(테스트코드)
public class FooTest{
@Autowired
ApplicationContext applicationContext;
@Test
public void getBean(){
//applicationContext.getBeanDefinitionNames() // 모든 bean 가져오기
TrialController bean = applicationCONtext.getBean(TrialController.class); // 특정 빈 가져오기
assertThat(bean).isNotNull(); // -> 잘 주입됐다면 Null이 아닐 예정
}
}
그러나.. ApplicationContext 타입을 직접 사용할 일은 없음. ApplicationContext가 등록된 Bean을 알아서 주입해주기 때문.
-> 직접 IoC 컨테이너에서 꺼내나(위 예제 코드), 자동 주입해주나 객체 해시값 찍어보면 똑같음!
6. 스프링IoC<스프링 빈(Bean)>
빈: IoC 컨테이너에서 관리하는 객체
ㄴ TrialController con = new TrialController(); // new로 만든건 빈이 아님
어떻게 특정한 인스턴스를 빈으로 등록하는가? -> ComponentScan 또는 직접 빈으로 등록
ComponentScan 으로 등록하기
ㄴ 애노테이션 프로세서 중 IoC컨테이너에 빈 등록할 때 사용하는 인터페이스가 많은데 이 인터페이스들을 라이프 사이클 콜백이라고 부르고,
ㄴ @Component라는 어노테이션이 붙어있는 클래스를 찾아서 인스턴스 생성하여 빈으로 등록하는 애노테이션 프로세서가 작동한다.
ㄴ @SpringBootApplication -> 안에 @ComponentScan 어노테이션이 어디부터~어디까지 스캔하라고 알려준다.
ㄴ @ComponentScan이 붙어있는 클래스부터 하위 클래스까지 다 훑어보면서 @Component를 사용한 어노테이션이 붙은 모든 클래스를 찾아서 빈으로 등록해준다. 스프링이 알아서 IoC 컨테이너를 만들 때 빈 등록해준다.
ㄴ 빈 등록에 사용할 수 있는 어노테이션으론 @Repository, @Service, @Controller, @Configuration 등 이 있다.
** 특이한 JpaRepository 구현체 등록 ㄴ Reposiitory는 특이한 형태로 Spring Data Jpa가 제공해주는 기능에 의해 빈으로 등록된다. 특정한 애노테이션이 없어도 특정 인터페이스를 상속받고 있는 클래스를 찾아서 내부적으로 구현체를 만들어서 빈으로 등록한다. |
직접 빈으로 등록하기
ㄴ 스프링부트 기반으로 테스트 작성하는 방법
@RunWith(SpringRunner.class)
@SpringBootTest
public class FooTest{
//...
}
ㄴ 빈 설정 파일 작성(자바 설정파일 많이 쓰는 추세, 또는 xml파일): 자바 설정 파일-> @Configuration 붙인다.
@Configuration
public class SampleConfig { // 빈 설정 파일
@Bean
public TrialController trialController(){ // 1. 리턴하는 TrialController를 빈으로 등록.
return new TrialController();
}
}
//@Controller -> 2. 더 이상 어노테이션을 붙일 필요가 없다.
public class TrialController{
//...
}
=> 이렇게 작성하면 @Configuration도 빈이기 때문에 ComponentScan에 읽히게 되고, IoC컨테이너 안에 빈으로 등록된다.
빈 꺼내서 쓰기
ㄴ 지금까진 ApplicationContext에서 직접 getBean으로 꺼내서 썼지만
ㄴ @Autowired 를 사용해서도 꺼내 쓸 수 있다.
ㄴ 직접 꺼내서 쓰기보단 스프링 IoC가 빈 주입해주는 방법(@Autowired사용)을 더 많이 쓰게된다.
7. 스프링 IoC<의존성 주입(DI)>
@Autowired(또는 @Inject) 를 어디에 붙일까?
ㄴ 필드, setter, 생성자
생성자로 주입 (필드에 final 가능)
ㄴ 생성자에 원랜 @Autowired까지 붙여줘야 빈 주입이됐다. (아래처럼)
@Autowired
public TrialController(TrialRepository repo){
this.respo = repo;
}
ㄴ 스프링 4.3버전부터 "어떤 클래스에 생성자가 하나뿐이고 그 생성자로 주입받는 레퍼런스 변수들이 빈으로 등록돼있다면, 그 빈을 자동으로 주입"하도록 업데이트됐으므로 지금은 안붙여줘도된다.
필드로 주입 (무조건 인스턴스를 생성 후 주입하기 때문에 final 붙이면 안된다)
@Autowired
private TrialRepository repo;
setter로 주입 (필드 주입과 같은 이유로 필드에 final을 붙이면 안된다.)
@Autowired
public void setTrials(TrialRepository repo){
this.repo = repo;
}
** 잘 주입되는지 확인하기 : 프로젝트 실행으로 확인 ㄴ 빈으로 등록되지 않은 객체를 주입하려고 할 경우 “No qualifying bean of type….” 에러 문구가 뜬다. |
스프링에서 권장하는 빈 주입 방법 -> 생성자 주입
public class TrialController {
private final TrialReposiitory repo;
public TrialController(TrialRepository repo){
this.repo = repo;
}
}
ㄴ TrialRepository가 없으면 이 클래스를 만들 수 없도록 강제할 수 있기 때문
ㄴ 필드, setter 인젝션은 강제할 수 없다. 의존성 없이도 만들 수 있다.
ㄴ 순환 참조(a->b, b->a참조 방향으로 a,b 둘 다 빈 주입을 못 하는 경우임) 의 발생을 방지할 수 있다.
ㄴ 이런 경우는 생성자 인젝션보다 필드, setter 인젝션이 나음.
ㄴ 필드, setter 인젝션은 일단 인스턴스를 만든 다음에 서로 인스턴스 주입을 하기 때문에 순환 참조 해결 가능
ㄴ but, 가능하면 순환 참조가 생기지 않는 구조를 만드는게 중요하고.. 정 안될 때 필드, setter 주입을 사용
과제) OwnerController에 PetRepository주입하기
- 필드 인젝션
@Autowired
private PetRepository repo;
- 생성자 인젝션
private TrialRepository repo;
private PetRepository petRepo;
public TrialController(PetRepository petRepo, TrialRepository repo){
this.repo = repo;
this.petRepo = repo;
}
- setter 인젝션
private PetRepository repo;
@Autowired
public void setPetRepository(PetRepostiory repo){
this.repo = repo;
}
8. 스프링 AOP<스프링AOP>
스프링 주요 개념 3가지: IoC, AOP. PSA
AOP: aspect oriented programming (측면.. 방향..관심사.. 지향적인 프로그래밍)
ㄴ method1, 2, 3에서 공통적으로 수행하는 부분을 공통으로 모은다.
ㄴ 기존의 코드를 건들이지 않고 객체를 다른 객체로 바꾸는 방법
ㄴ@Transactional 애노테이션을 Spring AOP가 적용돼있는 예시로 들 수 있음
StopWatch (스프링에서 제공하는 성능 측정 시계)을 사용한 예제
public String foo1(){
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//로직
stopWatch.stop();
System.out.println(stopWatch.prettyPrint());
}
// foo2(), foo3()...에서도 같은 방법으로 시간 측정한다고 가정.
이런 방식은 전혀 AOP가 아님
ㄴ StopWatch에 대한 로직이 없어도 있는것처럼 동작해야함.
AOP 구현하는 방법 크게 3가지
ㄴ 컴파일:
ㄴ .java엔 아무 코드 없는데
ㄴ 컴파일 후 class 엔 코드 생김(StopWatch코드 추가)
ㄴ 순서: A.java -> (AOP끼워넣기) -> A.class , AspectJ가 제공
ㄴ 바이트코드 조작: A.java -> A.class
ㄴ 컴파일 후 .class 파일에도 아무 코드 추가 안됐는데,
ㄴ classLoader가 클래스를 읽어와서 메모리에 올릴 때 코드가 조작(StopWatch코드가 들어감)
ㄴ 프록시 패턴(스프링 AOP가 사용)
ㄴ 디자인 패턴 중의 하나를 사용해서 AOP와 같은 효과를 내는 방법.
'Spring Boot' 카테고리의 다른 글
인프런 - 예제로 배우는 스프링 입문 (개정판) 정리(3) (0) | 2021.06.06 |
---|---|
인프런 - 예제로 배우는 스프링 입문 (개정판) 정리(1) (0) | 2021.06.06 |
댓글