본문 바로가기

스프링 프레임워크

뉴렉처[스프링 프레임워크] 10강~15강

10강 - 생성자 DI

Exam exam = new NewlecExam(30, 40, 40, 50); 을 xml파일에서는 필드의 순서대로 넣어주면 된다.

(반드시 NewlectExam 클래스에 생성자(디폴트 생성자 아닌 매개변수 있는 생성자)를 만들어준 상태에서 하기!!)

 

=> bean객체(NewlectExam클래스의 exam 객체)를 생성시 값 할당

<bean id="exam" class="spring.di.entity.NewlecExam" >

   <constructor-arg value="30" /> //kor

   <constructor-arg value="40" /> //eng

   <constructor-arg value="40" /> //math

   <constructor-arg value="50" /> //com

</bean>

 

위와 같이 넣으면 어떤 필드값에 값이 할당 되는지 헷갈릴 수 있다.

 

case1) 필드 순서를 나타내는 index값을 넣어줌으로써 헷갈리는 것을 해결할 수 있다.

<bean id="exam" class="spring.di.entity.NewlecExam">

   <constructor-arg index="0" value="10" />  //kor

   <constructor-arg index="1" value="30" />  //eng

   <contstructor-arg index="3" value="50" />  //com

   <constructor-arg index="2" value="10" /> //math

</bean>

 

case2)  필드명을 나타내는 name값을 넣어줌으로써 해결할 수 있다.

<bean id="exam" class="spring.di.entity.NewlecExam">

   <constructor-arg name="kor" value="10" />

   <constructor-arg name="eng" value="30" />

   <constructor-arg name="com" value="50" />

   <constructor-arg name="math" value="10" />

</bean> 

 

예외 상황 발생 ) 필드명은 같은데 필드 타입은 다른 상황인경우에는 어떻게 지정해야할까?

==> 필드값을 set할때 type을 지정할 수 있다.

 

위와 같이 속성을 설정하는데 너무 길다는 문제점이 발생!!!!!

==> 한줄로 속성 설정을 처리하는 방법

 

p:kor="10" 을 쓰려고 하니 p:kor="10" 을 처리하는 처리기를 xml파일에 불러와야한다.

 

 

네임스페이스p가 xml파일에 추가된 상황

※ 네임스페이스를 쓰는 이유 <namespace:bean> </namespace:bean>

 

1. 네임스페이스를 쓴 태그는 특정한 처리기에 의해 실행되기 위함

2. 태그의 이름을 식별하기 위해

 

ex.

<홍길동:bean> </홍길동:bean>

<김길동:bean> </김길동:bean>

 

==> 처리기에서 홍길동을 불렀을때는 김길동은 쳐다보지 않고 홍길동만 처리기에 의해 실행됨

 

   

위에서도 역시 xmln:p = "...." 로 네임스페이스를 p로 설정하였기에

<bean id="exam" class="spring.di.entity.NewlecExam" p:kor="10" p:eng="10" p:com="10" p:math="10" /> 으로

p를 호출했을때 위의 xmls:p = "..." 가 실행되어 처리할 수 있게 된다.

 

11강 - 콜렉션 생성과 목록 DI

List<Exam> exams = new ArrayList<>();

exams.add(new NewlecExam(1, 1, 1, 1));

 

for(Exam e : exams){

   System.out.println(e);

}

 

위의 내용을 클래스 파일에서가 아닌 xml파일에서는 어떻게 만들까?

Step1) ArrayList 객체 만들기


[class 파일]
 List<Exam> exams = new ArrayList<>(); 

 

[xml 파일]

<bean id="exams" class="java.util.ArrayList" />

 

만든 exams 객체를 사용하려면,

List<Exam> exams = (List<Exam>) context.getBean("exams");

 

Step2)

ArrayList 생성할때 Collection 객체를 생성자에 넣을 수 있다.

 

[class 파일]

exams.add(new NewlecExam(1,1,1,1));

 

[xml 파일]

생성자에서 List라는 Collection을 넣어준다.

 

* List에 NewlectExam(exam)객체를 넣어주는 방법

 

case1) 객체를 직접 생성하는 방법

<bean class="spring.di.entity.NewlecExam" p:kor="1" p:eng="1" p:com="1" p:math="1" />

 

case2)  xml파일에서 만들었던 객체를 가져오는 방법

<ref bean="exam" />

//exam 객체(bean)을 참조(ref)한다.

 

ex.

<bean id="exams" class="java.util.ArrayList">

   <constructor-arg>

     <list>

        <bean class="spring.di.entity.NewlectExam" p:kor="1" p:eng="1" p:com="1" p:math="1" />

        <ref bean="exam" />

     </list>

   </constructor-arg>

</bean>

 

위와 같이 컬렉션을 가진 ArrayList를 만드는 것이 아니라

 

<list>

           <bean class="spring.di.entity.NewlecExam" p:kor="1" p:eng="1" p:com="1" p:math="1" />

           <ref bean="exam"/>

</list>

 

이것 자체가 ArrayList에 전달되는 Collection임으로 Collection을 개별적으로 따로 만드는 방법은 없을까?

=> 가능하다!

 

Step1) util이라는 namespace 추가

<util:list> </util:list> 를 쓸 수 있게 된다.

 

Step2) 컬렉션의 종류를 list-class="리스트 종류" 에 정의하기

ex. ArrayList 컬렉션 사용 예)

<util:list list-class="java.util.ArrayList"> //ArrayList의 객체를 만들겠다.

    <bean class="spring.di.entity.NewlecExam" p:kor="1" p:eng="1" p:com="1" p:math="1" />

    <ref bean="exam" />

</util:list>

 

Step3) 만든 ArrayList를 가져다 쓰기 위해 id값 정의하기

<util:list id="exams" list-class="java.util.ArrayList">

    <bean class="spring.di.entity.NewlecExam" p:kor="1" p:eng="1" p:com="1" p:math="1" />

    <ref bean="exam" />

</util:list>

 

12강 - 어노테이션을 이용할 때의 장점과 @Autowired를 이용한 DI해보기

@Autowired 어노테이션

 

현재 InlineExamConsole 클래스의 console 객체가 exam 객체를 injection 하는 부분을 xml파일로 설정한 것이다.

 

setter에서 사용하는 속성 또는 setter 에다가 @Autowired 라는 키워드를 붙여주면 xml파일 설정을 안해도 된다.

 

 

@Autowired를 사용하면 Spring은 어떤 프로세스로 Setter을 설정할까?

 

Step1) console객체를 만들때 InlineExamConsole 클래스 파일을 쭉 읽는다.

<bean id="console" class="spring.di.ui.InlineExamConsole">

        .....

</bean>

 

Step2) InlineExamConsole 클래스 파일에서 @Autowired 라고 붙어진 setter을 찾게 된다.

@Autowired

@Override

public void setExam(Exam exam){

    this.exam = exam;

}

==> 자동으로 객체를 연결해달라는 의미

 

단!  주의!!!!!!

Spring에서 알아서 @Autowired를 찾는게 아니고 xml파일에서 bean객체를 설정할때

@Autowired를 찾아서 세팅해주라는 키워드를 넣어주어야한다.

 

※  context라는 네임 스페이스가 필요!! (위에서 namespace를 추가했던 방법대로 똑같이 추가하기)

 

<context:annotation-config /> 을 xml파일 상단에 적어줌으로써 bean객체들은 어노테이션 객체를 갖고 있다 는 의미

==> bean객체 중에 어노테이션 객체가 있으니 찾아서 세팅해주세요!!

 

13강 - @Autowired의 동작방식 이해와 @Qualifier 사용하기

번호 순서대로 1 -> 2 -> 3 으로 객체를 생성하고 Injection을 한다. 

 

그런데 1번에서 @Autowired를 찾을때 어떤 기준으로 찾을까?

클래스 타입으로 찾을까? 변수명으로 찾을까?

 

TEST1) 변수명을 바꿔보자(id="exam" ~> id = "exam1")

 

<bean id="exam1" class="spring.di.entity.NewlecExam" p:kor="10" p:eng="10" p:com="10" p:math="10" />

 

==> 결과가 잘 나온다.

 

TEST2) 변수명을 없애보자! 

 

<bean class="spring.di.entity.NewlecExam" p:kor="10" p:eng="10" p:com="10" p:math="10" />

 

==> 결과가 잘 안나온다.

 

결론적으로!!

변수명으로 찾는것이 아니라 클래스타입으로 찾는다는 것을 알 수 있다.

 

@Autowired

@Override

public void setExam(Exam exam){

    this.exam = exam;

}

에서 매개변수 'Exam" 타입을 찾아서 자동으로 할당 해주는 것

 

Spring은

NewlecExam은 Exam의 interface를 구현한 것임으로 생성된 NewlecExam의 bean 객체를 매개변수로 넣어준다.

 

만약 객체 아이디는 없고

 

<bean class="spring.di.entity.NewlecExam" p:kor="10" p:eng="10" p:com="10" p:math="10" />

<bean class="spring.di.entity.NewlecExam" p:kor="20" p:eng="20" p:com="20" p:math="20" />

 

필드값이 다른 똑같은 객체가 두개 생성한 상황에서는 어떻게 Autowired를 할까?

 

TEST1) 하나의 bean객체를 설정하는 id값을 setter매개변수 명과 같은 이름으로 객체를 생성하면 어떨까?

 

<bean id="exam" class="spring.di.entity.NewlecExam" p:kor="10" p:eng="10" p:com="10" p:math="10" />

<bean class="spring.di.entity.NewlecExam" p:kor="20" p:eng="20" p:com="20" p:math="20" />

 

@Autowired

@Override

public void setExam(Exam exam){

    this.exam = exam;

}

 

==> 결과가 잘 나온다.

bean객체의 id값과 setter 매개변수명과 같은 이름으로 하니까 같은 이름의 bean객체가 Autowired 된다.

 

TEST2) bean객체의 id값을 "exam1" "exam2" 로 가질때 실행이 될까?

 

<bean id="exam1" class="spring.di.entity.NewlecExam" p:kor="10" p:eng="10" p:com="10" p:math="10" />

<bean id="exam2" class="spring.di.entity.NewlecExam" p:kor="20" p:eng="20" p:com="20" p:math="20" />

 

==> 결과가 잘 안나온다. 이름이 달라서 바인딩이 되지 않는다

 

그러면 bean 객체의 id값에 따라 setter 메서드의 매개변수 명을 계속 바꿔주어야 하나?

==> 이때 나온게 @Qualifier("bean 객체 id 값");

 

@Autowired

@Qualifier("exam2") //"exam2객체를 바인딩한다"

@Override

public void setExam(Exam exam){

    this.exam = exam;

}

 

14강 - @Autowired의 위치와 required 옵션

 

인잭션 방법 3가지

 

1) 필드 위 : 기본 생성자를 호출하면서 injection

==> 기본 생성자를 없을때는 에러메세지가 뜬다. 반드시 기본 생성자가 있어야한다.

 

@Autowired
@Qualifier("exam2")
private Exam exam;

 

2) 생성자(디폴트 생성자X) 위

 

@Autowired

@Qualifier("exam2")

public InlineExamConsole(Exam exam, Exam exam2){

         this.exam = exam;

}

으로 쓰면 에러 표시가 뜬다.

 

이유는 생성자의 매개변수가 여러개일 수 도 있기 때문에 그것을 지정해주는데 명확히 해주어야하기 때문이다.

 

case1) 매개변수 1개일때

@Autowired

public InlineExamConsole(@Qualifier("exam1") Exam exam){

         System.out.println("overloaded constructor");

         this.exam = exam;

}

 

case2) 매개변수 1개 이상일때

@Autowired

public InlineExamConsole(@Qualifier("eam1") Exam exam1, @Qualifier("exam2") Exam exam2){

         System.out.println("overloaded constructor");

         this.exam1 = exam1;

         this.exam2 = exam2;

}

 

3) setter 메서드 위 : setter함수가 호출되면서 injection

 

@Autowired

@Qualifier("exam2")

@Override

public void setExam(Exam exam){

  this.exam = exam;

}

 

====== [required 옵션] ======

@Autowired

@Qualifier("exam1")

private Exam exam;

 

@Autowired를 세팅했을때 반드시 xml파일에 bean객체를 등록해야한다.(없으면 에러가 뜬다.)

그런데 필요에 따라 bean객체가 없어도 그냥 실행되게 하고 싶을때가 있다.

 

ex. exam객체가 null 일때는 디폴트 프린트를 출력해준다.

@Override

public void print() {

         if(exam == null) {

                  System.out.printf("total is %d, avg is %f \n", 0, 0.0);

         }

         System.out.printf("total is %d, avg is %f \n", exam.total(), exam.avg());

}

 

==> 이럴때 required 옵션을 사용한다.

@Autowired(required = false) //xml파일에 exam1이라는 bean객체가 없어도 괜찮다.
@Qualifier("exam1")
private Exam exam;

 

15강 - 어노테이션을 이용한 객체 생성

객체 생성과 @Component

 

@Component 어노테이션을 이용하여 InlineExamConsole 객체를 등록한다.

==> 오류가 발생한다. 

왜? Spirng에서 @Component 어노테이션을 읽으라고 명령을 하지 않았기 때문이다.

 

(이전 시간에 @Autowired 도 역시 단순히 어노테이션만 쓰면 Spring이 읽지 않는다.

xml파일에서 <context:annotation-config /> 를 설정해줌으로써 읽었다.)

 

 

<context:component-scan base-package="spring.di.ui" />

spring.di.ui 패키지에 가서 클래스들이 있을텐데 component 가 있는지 스캔해서 있으면 객체화 시켜라!

 

InlineExamConsole 클래스의 @Component 어노테이션을 스캔하면 @Autowired 도 자연스럽게 읽게 됨으로써 xml파일에 있던 <context:annotation-config /> 설정은 없애도 된다.

 

@Component(객체id) 를 지정해줌으로써 만든 객체의 id값을 정해준다.

ex.

@Component("console")

public class InlineExamConsole implements ExamConsole{

      ....

}

 

ExamConsole console = (ExamConsole) context.getBean("console");

 

*만약 여러 패키지 내의 클래스의 component를 스캔하려고 한다면

<context:component-scan base-package="spring.di.ui , spring.di.entity" /> 와 같이

콤마로 패키지를 추가하면 된다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

출처: 뉴렉쳐

www.youtube.com/watch?v=XtXHIDnzS9c&list=PLq8wAnVUcTFWxnsrMu5kS_jt_o8gpEiTR&index=1