bean-container는 가상의 공간입니다. 일종의 공장이라고 보셔도 좋습니다.
이 공장은 완제품을 미리 생산해뒀다가 사용자가 제품을 주문하면 바로조립해서 가져다 주는 공장입니다.
=의존성에 대한 설계도를 넘긴다고 생각하면됨.
미리 만들어져 있다는 특성으로 인해 사용자가 객체를 필요로 할 떄는 직접 new 연산자를 이용해 객체를 생성하는 방식이 아니라 bean-container에 미리 완성되어 있던 객체를 받다 쓴느 형태로 진행
의존성 주입 테스트(spring 방식)
스프링에서 사용하는 의존성 주입 개념을 활용하기 위해서는 먼저 객체 생성을 bean-container에 요청해서 진행
따라서 bean-container에 객체를 등록하는 것이 제일 먼저 할 일.
의존성 주입을 위한 component-scan 설정
(bean-container에 특정 클래스 파일을 집어 넣기 위해서 사용하기 위해)
context 네임스페이스를 활용한 컴포넌트 스캔 지정
src / main / webapp / WEB-INF / spring / root-context.xml
root-context.xml
하단 namespace탭에서 context 체크하고 저장
이렇게 하면 <context:component-scan>태그를 사용 가능하고,
component-scan 태그의 속성에는 base-package가 있으며 이 곳에 스캔의 범위를 지정할 수 있다.
com.ict.controller.di.classfile 여기를 스캔 대상으로 삼겠다는 의미
제공이 됐는지 체크
Beans Graph를 눌러 확인이 가능하다.
만약 Beans Graph 이 안보인다면,
root-context.xml / 우클릭 Spring / add as ~ 누루면 된다.
add as~ -> Remove as 를 바뀌면 Beans Grap를 생깁니다.
= 제공받은 설계도는 Beans Grap 여기에 설계됩니다.
컴포넌트 스캔 할용 및 객체 bean-container에 등록하기
1. 스캔 범위에 들 것. (위에서 완료)
2. 클래스명 윗줄에 어노테이션을 사용 할 것.
사용하는 어노테이션은 크게 4종류가 있습니다.
@Component -> 용도가 애매한 객체에 사용합니다.
@Controller -> 컨트롤러에 사용합니다.
@Service -> 서비스 객체에 사용합니다.
@Repository -> DAO 객체에 사용합니다.
Singer
@Component 임폴트까지 해준다.
에스가 붙는걸 확인 할 수 있다.
(에스가 붙으면 설계도가 넘어간것임)
확인해 보면
root-context.xml - Beans Graph 에 singer 생기는걸 확인 가능
(singer 설계도를 받았다)
Stage
@Component 임폴트까지 해준다.
s 생기는거 확인
root-context.xml - Beans Graph 에 stage 생기는거 확인
(stage 설계도를 받았다)
사용해 보겠습니다.
com.ict.controller.di / 우클릭 new / clss / DiMainSpringver 생성(main 체크)
DiMainSpringver
root-context라는 공장에 저장된 객체를 뽑아서 써야합니다.
가져오기 위한 호출코드를 작성해보겠습니다.
GenericXmlApplicationContext context =
new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/root-context.xml");
-> root-context.xml 경로를 지정
공장 내부 객체 가져오기
context.getBean("공장 내부 명칭", 클래스파일명.class);
->getter를 이용해 뽑아옵니다.
예)
Singer를 가져온다면
Singer singer = context.getBean("singer", Singer.class);(임폴트)
= 싱어 싱어는 콘텍스트 겟빈에 잇는 싱어를 가져오겠다. 원본클라스
가져온 객체 사용하기.
singer.sing();
run as 해보면
가수가 노래를 합니다 라고 뜨는걸 확인할 수 있습니다.
Stage를 가져온다면
Stage stage = context.getBean("stage", Stage.class);
= 스테이지에 스테이지는 = context.getBean 에 있는 stage지를 가져오겠다. 원본클라스
stage.perform();
run as 해보면
무대에서 가수가 노래를 합니다 뜨는걸 확인 할 수 있습니다.
=============================
@Autowired를 입력시 해당 자료형과 일치하는 부품이 공장 내에 존재하면 자동으로 결합해줍니다.
// 변수 위, 생성자 위중 하나를 고르시면 됩니다.
// @AUtowired는 @Inject로 대체할 수 있습니다.
// 4번전까지 @Autowried 사용시 아무 작업도 하지 않는 디폴트 생성자가 추가되어야 합니다.
public Stage() {}
=============================
등록된 객체 간 주입을 구현하는 어노테이션.
컴포넌트 스캔이 된 상태라면 우선 빈 컨테이너 내부에 객체가 만들어져 있는 상태입니다.
단, 객체는 만들어 졌으되, 주입은 일어나지 않은 상태입니다.
따라서 주입관계를 우리가 설정해야 합니다.
스프링에서는 @Autowired 어노테이션을 이용해 자동 주입을 구현합니다.
의존 객체 위에 @Autowired 어노테이션을 쓰면 bean-container가 알아서 일치하는 자료형이 있으면 넣어줍니다.
결국 사용자는 @Autowired를 정확하게 사용했다는 전제하에 최종 완성 객체 하나만 신경써도 됩니다.
==========================
문제)
방송이 무대에 의존하기 때문에
1. Broadcast 클래스를 만들어주시고, Stage를 입력받아야만 생성가능하게 해주세요.
com.ict.controller.di.classfile / 우클릭 new / class / Broadcast 생성
Broadcast의 송출기능을 담당하는 onAir 메서드는
"방송 송출중인 무대에서 가수가 노래를 합니다. " 라는 문장이 나오도록 세팅
DimainSpringver에서 Stage와 Singer를 건너뛰고 바로 Broadcast를 만들어서 실행할 수 있도록 세팅을 마친 다음 셀제로 실행까지 해 주세요.
실행 run as
방송 송출중인 무대에서 가수가 노래를 합니다.
방송 송출중인 = onAir
무대에서 가수가 노래를 합니다 = Stage(singer)
결국 = singer -> stage(singer) -> broadcast(stage(singer))
=======================================
실제 객체 생성을 돕는 GenericXmlApplicationContext 객체
(통신기기 역활)
GenericXmlApplicationContext context =
new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/root-context.xml");
=====================================
어노테이션을 활용한 의존성 주입의 한계
현재 @Autowired에 따르면 자료형이 일치하는 객체는 자동으로 주입이 되고 있습니다.
그렇다면 다형성 원리에 의해서 둘 이상의 객체가 의존성 주입의 타겟이 될 수 있다면 어떻게 처리되는지가 중요합니다.
불행하게도 스프링의 @Autowired는 일치하는 자료형이 두 개 이상이면 객체 주입을 포기하고 오류를 발생시켜버립니다.
요컨대, 둘 이상의 객체가 주입의 타겟이 되는 경우는 특정 객체를 지목해서 주입해야 한다는 것입니다.
따라서 @Qualifier 어노테이션을 활용해 둘 이상의 객체가 주입되는 경우는 교통정리를 해 줘야 합니다.
Singer
@Component 주석처리 하고
Singer를 상속한 발라드가수와 팝 가수를 생성해서 빈 컨테이너에 등록해보겠습니다.
com.ict.controller.di.classfile / 우클릭 class / BalladSinger 생성
BalladSinger
extends를 이용해서 상속
public class BalladSinger extends Singer {
DimainSpringver
만약 발라드 가수를 만들어 쓰고 싶다하면
실행해보면
발라드 가수가 소몰이 창법으로 노래를 합니다. 확인할 수 있습니다.
브로드 캐스트로 실행해보면
방송 송출 중인 무대에서 발라드 가수가 소몰이 창법으로 노래를 합니다.
방송 송출 중인 = 브로드캐스트
무대에서 = 스테이지
발라드 가수가 소몰이 창법으로 노래를 합니다. = 발라드가수
PopSinger를 생성해주세요.
com.ict.controller.di.classfile / 우클릭 class / PopSinger 생성
Singer를 상속
public class PopSinger extends Singer {
sing() 메서드를 오버라이딩해 "팝가수가 영어로 노래를 합니다. "
빈 컨테너 등록 까지
@Component
여기까지 했으면, 이젠
BalladSinger,PopSinger 둘 중에 누굴 받아야할지 문제.
이때
@Qualifier 어노테이션을 활용해 둘 이상의 객체가 주입되는 경우는 교통정리를 해 줘야 합니다.
Stage
5버전에서도 @Qualifier 어노테이션 사용시는 디폴트 생성자가 필요합니다. public Stage() {}
발라드 싱어를 넣어주면 발라드 가수가 나오고
팝싱어를 넣으면 팝가수가 나온다.
어노테이션을 활용한 의존성 주입의 더 큰 문제
@Component 스캔으로 만들수 있는 갯수는 1개
넣어 주는게 두개이면 @Qualifier 사용해서 우선권..?을 줌
근데 각각의 객체가 주입된 객체가 모두 필요한 상황이라면 결국 같은 종류의 객체의 두 개 이상 xml파일 내부에 만들어야 함
xml파일에 빈 객체 직적 생성하기
root-context.xml 파일 내부에는 라는 태그가 있습니다.
말 그대로 객체들을 모아두는 태그로 내부에 이라는 태그를 이용해 개별 객체들을 하나하나 만들어줄 수 있습니다.
bean = 자바객체
beans = 복수형
bean 태그의 속성
id => 컨테이너 내부적으로 사용할 명칭을 부여합니다.
*class => 필수 속성으로 패키지명을 포함한 클래스파일의 경로를 입력하면 그 클래스파일을 활용한 객체가 bean-container 내부에 생성됩니다.
빈즈 그래프 -
Stage 1 / Stage2를 만들어 보겠습니다.
< bean id="stage2" class="com.ict.controller.di.classfile.Stage">
stage 1 / stage2 가 빈즈그래프에 만들어진걸 확인 할 수 있습니다.
balladSinger / broadcast / popSinger / stage = 자동생성
stage 1 / stage2 = 수동 생성
DiMainSpringver
수동생성 bean인 stage1 / stage2 가져와서 사용하기
Stage stage1 = context.getBean("stage1", Stage.class);
stage1.perform();
Stage stage2 = context.getBean("stage2", Stage.class);
stage2.perform();
@Qualifier 가 팝가수로 우선권을 주고 있어서 실행해보면
무대에서 팝가수가 노래를 합니다. 라고 나옵니다.
bean 태그 내부에서 사용할 수 있는 태그
constructor-arg>생성자 주입을 위해 사용하는 태그입니다.
property> setter주입을 위해 사용하는 태그입니다.
확인해보면
팝 싱어랑 발라드 싱어를 주입 받았다.
실행 해 보면