22.09.08 - [ Spring ] @Component , @Autowired , injection , IoC 와 DI
-- INDEX --
1. @Component 사용 이유 |
2. @Component | 3. @Autowired | 4. injectrion | 5. IoC 와 DI |
context 바구니에 가지고있어야할 객체를 알려준다. |
@Controller @Service @Repository |
spring에게 객체를 채워달라고 알려준다. |
생성자 인젝션 세터 인젝션 필드 인젝션 |
제어의 역전과 객체 채워주기 |
1. @Component 탄생 과정 살펴보기
1-1 : home() 메서드 Controller - Service - Dao 에서 각각 구현하기
1-2 : C - S - D ㅡ 각 부분에서 수정할 부분 수정하기
#1. Controller에서 수정할 부분 수정하기
- 메서드 안에서 new HomeService() 로 객체 만들어주는 부분 안 좋다.
- 메서드 위쪽에 필드로 만들어주기.
- 이것뿐만 아니라 – HomeService() 객체가 모든 작업에 필요하다.
- = 즉, 컨트롤러 태어날 때 HomeService객체 필요하다.
- = 생성자로 받게 해 주자
#2. Service에서 작업
- > new HomeDao 만드는 부분 메서드 밖으로 빼기
- > 메서드 밖으로 빼놔도 문제가 있다. - 구체적인 타입을 적어주어야 하니까
- > HomeService 레이어에 추가해 줄 모든 메서드들은 작업을 하려면
- 무조건 HomeDao객체가 필요하다.
- 생성자에 넣어주자
#3. dao 쪽도 작업해주기
1-3 : 기본 생성자 추가해서 서버 실행해보기
우리는 new HomeController 한적 없는데 태어난 이유는?
- 어노테이션 때문에 생성자가 호출되고 있다 –
어떤 객체가 만들어지고 있다.
1-4 : @Component로 서비스 객체와 dao객체 태어나게 해 주기
기본 생성자로 태어난 HomeController는
[ HomeService ] 객체를 가지고 태어나지 못해서 에러가 난다.
해결방법은?
Service와 Dao쪽에
@Component 와 기본생성자 추가
우리는 생성자를 한 번도 호출한 적이 없는데 애들이 다 태어났다!
서버 실행하는 작업밖에 안 했는데 애들이 다 태어났다.
아직 요청을 보낸 게 아무것도 없는데 애들이 다 태어났다.
모두 기본 생성자를 통해서 태어났다.
가능한 이유는??
@Component 라는 어노테이션 때문에 !!
2. @Component { @Controller , @Service , @Repository }
- 톰캣을 실행한 것일 뿐인데 - spring이 자동으로
- 컨트롤러 객체 / 서비스 객체 / dao 객체 만들어 놓은 상태
- spring이 객체를 자동으로 만들어주는 기준은?
- @Component라는 어노테이션 달려있으면 - 인식해서 객체를 만들어주는구나 체크
2-1 : @Controller @Service @Repository 사용하는 이유
- @Component와 마찬가지로 spring의 context 바구니 안에 객체를 만들어주어야겠다 하는 것이다.
- 다른 점은 이름이 다른 것이다.
- 마치 우리가 <div>대신 <header><nav> 같은 시멘틱 태그 사용했듯이
- 유지보수 측면에서 유리하기 위해서 사용
사실 @Component 는 잘 안 쓴다. - 어떤 건지 모를 때, 역할 애매할 때 쓰는 것이다.
@Component -> @Service 로 수정!
@Component -> @Repository 로 수정!
3. @Autowired
- 우리가 home()를 실행하는데 필요한 C –S- D객체 다 만들어진 상태
- spring은 이미 생성되어서 context(바구니)에 가지고 있는 객체를 가지고 –
- 들어온 요청에 필요한 애들 뽑아서 - 연결 연결해서 요청을 처리한다.
#현재 상태로 메서드를 실행한다면?
- 컨트롤러 객체에 서비스 객체가 없어서 에러 난다 – nullpoint Exception
#객체 만들어놓으면 스프링이 태어날 때 필요한 거 자동으로 넣어준다 그랬는데 왜 안 되냐??
- 기본 생성자로 태어난 애들이라 – 태어날 때 필요한 것들을 가지고 태어나지 못한다.
# 해결 방법
- 컨트롤러가 만들어질 때 기본 생성자가 아니라 파라미터가 있는 생성자로 태어나게 해 주어야 된다
- spring이 파라미터 있는 생성자로 객체를 만들어주었으면 좋겠다 생각했다.
3-1 : 기본 생성자 지우고 테스트
- 이제 기본 생성자도 없으니 – 어쩔 수 없이 파라미터 있는 생성자로 만들어주겠지?
- 컨트롤러가 태어나게 해 주기 위해 – 서비스 객체를 넣어서 만들어주겠지?
- 안된다. ㅡ 기본 생성자 없다고 에러 발생한다.
- spring 은 기본생성자 아니고도 만들어주는데
- 저 HomeService객체를 내가 채워야 하는 게 맞는 건가? 채워도 되는 건가? 몰라서 안된다.
- spring에게 채워달라고 알려주어야 한다
- 방법은? ㅡ @Autowired
3-2 : @Autowired
@Autowired로 spring에게 채워달라고 알려주고 나니
기본 생성자가 아닌 – 파라미터 받는 생성자로 – 컨트롤러 태어난 것 확인!
서비스 객체도 – 기본 생성자로 태어나는 것이 아닌
파라미터 가진 생성자로 태어나게 해주어야 한다
태어날 때 dao객체를 가지고 태어나게 해주어야 한다..
dao에서는 작업할 거 없다. ( 기본 생성자로 태어나도 괜찮다 )
4. injection의 3가지 방법
- Autowired를 통해 객체를 넣는 것 = injection (주입)
4-1 : @Autowired - infection의 3가지 방법
- 생성자 인젝션 -- C
- 세터 인젝션 -- S
- 필드 인젝션 -- F
# 생성자 인젝션을 가장 권장한다.
- 스프링의 권장사항
- 생성자 인젝션 사용 시 - final키워드 사용가능( 변수가 선언되는 시점부터 값을 가지고있어야하므로 )
# 필드 인젝션, 세터 인젝션 사용시
- 좀 더 편하게 사용 가능하다는 장점이 있지만
- 객체의 불변성 깨진다. , 순환 의존성
- 실행이 되는 시점에서야 문제점을 발견할 수 있다.
- 순환 참조라는 문제 사항 생길 가능성이 있다.
장단점보다는 뚜렷한 권장사항이 있다.
객체를 만들 때 어떻게 만드는 게 좋은 방법이었나를 생각해보면 똑같다.
인젝션이라는게 결국엔 어떤 객체를 만들어서 다른 객체를 만들어 주는 것
즉, 객체를 만드는 것이다.
4-2 : 사용법 살펴보기
- #1. 컨트롤러 인젝션은 위에서 사용해보았다.
- 필드 인젝션과 세터 인젝션 사용해보기
- 굳이 생성자를 통해서 @Autowired 해주지 않아도 괜찮다.
- 그럼, 기본 생성자로 태어난 객체에 – 필요한 객체를 어떻게 채워줄까? - 뒤늦게라도 채워주면 좋을 텐데.
#2. 필드 인젝션
- 해당 클래스 객체가 태어나는데 필요한 필드에 @Autowired
- 컨트롤러 객체가 태어나는데 필요한 서비스 객체 -
- 컨트롤러 클래스에서 작업 - 필드 변수에 @Autowired
- 서비스 객체가 태어나는데 필요한 다오 객체 -
- 서비스 클래스에서 작업 - 필드변수에 @Autowired
이 필드 spring 너가 관리해라 알려주기 - 잘 작동된다.
#3. 세터 인젝션
- 세터를 만들어주고 거기에 @Autowired
잘 작동한다.
spring 이
이 필드 내가 건드려도 괜찮은 건가??
이 세터 내가 건드려도 괜찮은 건가??
괜찮다고 알려주는 것이 -- @Autowired
Spring은 이 객체를 여기에 넣어주어도 되나?
판단하는 기준은 – 타입
5. IoC 와 DI
스프링의 가장 큰 특징 2가지 – IoC , DI
spring은 클래스 파일 쭉 읽어오면서
@Component 되어있는 애들 생성자로 만들면서
그중에 @Autowired있는 애들한테 객체를 넣어준다.
5-1 : IoC 란?
- 제어의 역전
- 개발자가 직접 객체를 생성하고, 메서드를 호출하고 했었는데
- 이런 거를 이제 spring이 자동으로 알아서 해준다.
- 매 요청마다 새로운 객체가 생기는 것이 아니라 – 객체가 생성되어있고, 메서드가 호출되도록 동작을 만들어 놓은 것
- 개발자가 클래스 파일만 잘 만들어놓으면, 프레임워크가 읽어서 파악해서, 객체를 만들어주고, 메서드를 호출해주고 한다.
- 즉, 개발자가 직접 객체를 생성하고 메서드 호출하는 것이 아닌 – 클래스 파일만 작성해놓으면 프레임워크가 알아서 작업 해주는 것.
# 이 과정에서 class파일에 있는 객체가 태어나는데 필요한 객체를 넣어주는 것이 - DI
5-2 : DI
- @Autowired 되어있는 애들한테 – spring이 객체를 넣어준다 – injection 해준다.
- 이렇게 어떤 객체가 태어나는데 필요한 객체를 넣어주는 작업을
- Dependency Injection = DI라고 한다.
- ( 이거 DI좀 해줘 )