4. 익명 빈 선언
설정 파일에서 빈을 선언할 때 빈의 이름을 지정하지 않을 수 있다. 이런 빈을 '익명(anonymous) 빈'이라고 부른다. 어떻게 선언하고 사용하는지 살펴본다.
- 실습 패키지 생성
exam 패키지 아래에 test03 패키지를 생성한다. test02 패키지의 모든 파일을 test03 패키지에 복사한다.
- beans.xml 빈 설정 파일
exam/test03/beans.xml 파일을 열고 다음과 같이 편집한다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="exam.test03.Score"/>
<bean class="exam.test03.Score"/>
</beans>
<bean class="exam.test03.Score"/>
이전 실습 때와는 달리 빈을 선언할 때 id나 name 값을 지정하지 않는다. 이렇게 빈의 이름을 지정하지 않으면 컨테이너에 보관할 때 "패키지 이름 + 클래스 이름 + #인덱스"를 빈의 이름으로 사용한다. 동일한 클래스의 객체가 여러 개 생성될 경우를 대비해 빈 이름 뒤에 "#인덱스"가 자동으로 붙는 것이다. 인덱스는 0부터 시작한다. 앞의 경우 첫 번째 선언된 빈의 이름은 exam.test03.Score#0이 되고, 두 번째 선언된 빈의 이름은 exam.test03.Score#1이 된다. 익명 빈의 경우 클래스 이름은 (exam.test03.Score) 첫 번째 빈(exam.test03.Score#0)에 대한 별명이 된다.
- 빈 컨테이너 테스트
빈 컨테이너를 테스트할 exam.test03.Test 클래스를 다음과 같이 편집한다.
package exam.test03;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
//IoC 컨테이너 준비하여 빈 생성
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("exam/test03/beans.xml");
System.out.println("[컨테이너에 보관된 객체의 이름 출력]");
for(String name : ctx.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println("[exam.test03.Score#0의 별명 출력]");
for(String alias : ctx.getAliases("exam.test03.Score#0")) {
System.out.println(alias);
}
System.out.println("[exam.test03.Score#1의 별명 출력]");
for(String alias : ctx.getAliases("exam.test03.Score#1")) {//별명 없음
System.out.println(alias);
}
System.out.println("[익명 빈 꺼내기]");
Score score1 = (Score)ctx.getBean("exam.test03.Score");
Score score2 = (Score)ctx.getBean("exam.test03.Score#0");
if(score1 == score2) System.out.println("score == score#0");
System.out.println("[두 번째로 선언된 익명 빈과 비교]");
Score score3 = (Score)ctx.getBean("exam.test03.Score#1");
if(score1 != score3) System.out.println("score != score#1");
System.out.println("[클래스 타입으로 빈 꺼내기]");
Score score4 = (Score)ctx.getBean(exam.test03.Score.class);
}
}
[예 1]
for(String name : ctx.getBeanDefinitionNames()) {
System.out.println(name);
}
익명 빈의 이름을 확인하기 위해 getBeanDefinitionNames()를 호출하였다. 실행 결과를 보면 두 개의 익명 빈이 보관되어 있음을 알 수 있다. 빈의 이름은 패키지 이름을 포함한 클래스 이름이고, 뒤에 인덱스가 붙는다.
[예 2]
for(String alias : ctx.getAliases("exam.test03.Score#0")) {
System.out.println(alias);
}
for(String alias1 : ctx.getAliases("exam.test03.Score#1")) {//별명 없음
System.out.println(alias1);
}
익명 빈의 별명이 있는지 확인하기 위해 getAliases() 메서드를 호출하였다. 실행 결과를 보면 클래스 이름(exam.test03.Score)이 별명으로 등록되었음을 확인할 수 있다.
(추가로 궁금해서 exam.test03.Score#1의 별명을 출력했으나 없었다.)
[예 3]
Score score1 = (Score)ctx.getBean("exam.test03.Score");
Score score2 = (Score)ctx.getBean("exam.test03.Score#0");
if(score1 == score2) System.out.println("score == score#0");
getBean() 메서드를 호출하여 익명 빈을 꺼낼 때는 빈의 이름으로 "패키지명 + 클래스명#인덱스"를 사용한다. 반환된 인스턴스를 비교해 보면 당연히 'exam.test03.Score'는 'exam.test03.Score#0'의 별명이기 때문에 같은 객체라는 것을 확인할 수 있다.
[예 4]
Score score3 = (Score)ctx.getBean("exam.test03.Score#1");
if(score1 != score3) System.out.println("score != score#1");
두 번째로 선언된 익명 빈을 꺼내고 싶으면 빈의 이름에 #1을 붙인다. 실행 결과를 보면 클래스 이름으로 꺼낸 빈과 다르다는 것을 확인할 수 있다.
[예 5]
Score score4 = (Score)ctx.getBean(exam.test03.Score.class);
클래스 타입으로도 객체를 꺼낼 수 있다. getBean() 메서드를 호출할 때 Score 클래스에 대한 정보를 담은 java.lang.Class 객체를 넘긴다. 즉 exam.test03.Score.class 객체를 넘기면 빈 컨테이너에서 이 클래스의 인스턴스를 찾는다. 만약 같은 타입의 객체가 여러 개 있을 경우 예외가 발생한다. 빈 컨테이너 입장에선 어떤 객체를 반환해야 할지 알 수 없기 때문이다. 실행 결과를 보면 exam.test03.Score 인스턴스가 여러 개 있다고 오류를 보고하고 있다.
참고도서 : https://freelec.co.kr/book/1674/
[열혈강의] 자바 웹 개발 워크북
[열혈강의] 자바 웹 개발 워크북
freelec.co.kr
'교재 실습 > 자바 웹 개발 워크북' 카테고리의 다른 글
136. 생성자와 프로퍼티 설정 (2) (0) | 2022.10.20 |
---|---|
135. 생성자와 프로퍼티 설정 (1) (0) | 2022.10.19 |
133. XML 기반 빈 관리 컨테이너 (3) (0) | 2022.10.17 |
132. XML 기반 빈 관리 컨테이너 (2) (2) | 2022.10.15 |
131. XML 기반 빈 관리 컨테이너 (1) (2) | 2022.10.14 |
댓글