본문 바로가기

학원/복기

[Spring] Bean 컬렉션 주입 / autowire 속성

예제)

 

CollectionBean 클래스

package xyz.itwill05.di;

import java.util.List;
import java.util.Set;

public class CollectionBean {
	private Set<String> nameSet;
	private List<String> nameList;
	
	public CollectionBean() {
		System.out.println("### CollectionBean 클래스의 기본 생성자 호출 ###");
	}

	public Set<String> getNameSet() {
		return nameSet;
	}

	public void setNameSet(Set<String> nameSet) {
		this.nameSet = nameSet;
	}

	public List<String> getNameList() {
		return nameList;
	}

	public void setNameList(List<String> nameList) {
		this.nameList = nameList;
	}
	
	
}

 

[05-2_collection.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="xyz.itwill05.di.CollectionBean" id="collectionBean"/>
</beans>

 

[ClloectionBeanApp]

package xyz.itwill05.di;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CollectionBeanApp {
	public static void main(String[] args) {
		System.out.println("================ Spring Container 초기화 전 ================");
		ApplicationContext context=new ClassPathXmlApplicationContext("05-2_collection.xml");
		System.out.println("================ Spring Container 초기화 후 ================");
		CollectionBean bean=context.getBean("collectionBean", CollectionBean.class);
		
		//CollectionBean 객체의 필드값(Collection 객체)을 반환받아 출력
		// => Collection 객체의 toString() 메소드 호출 
		System.out.println("nameSet = "+bean.getNameSet());//nameSet = null
		System.out.println("nameSet = "+bean.getNameList());//nameSet = null
		System.out.println("============================================================");
		((ClassPathXmlApplicationContext)context).close();
	}
}

 

 


set 엘리먼트와 value 엘리먼트를 이용해 의존 관계를 구현해보자

 

 

set 엘리먼트 : set 객체를 생성하여 필드에 저장하기 위한 엘리먼트

value 엘리먼트 : Collection 객체의 요소에 값을 전달하여 요소로 추가하는 엘리먼트 

 

<!-- Setter Injection을 사용하여 객체 필드에 Collection 객체에 저장하여 의존관계 구현 - DI -->
<bean class="xyz.itwill05.di.CollectionBean" id="collectionBean">
	<property name="nameSet">
		<!-- set 객체를 만들어 값을 요소로 추가한다. (중복값은 허용되지 않는다) -->
		<set>
			<value>홍길동</value>
			<value>임꺽정</value>
			<value>전우치</value>
			<value>홍길동</value>
		</set>
	</property>
</bean>

 

main 실행

 

 

set 객체를 만들어 값을 요소로 추가할 때는 중복값은 허용되지 않는다.

 


 

list 엘리먼트 : List 객체를 생성하여 필드에 저장하기 위한 엘리먼트

 

<bean class="xyz.itwill05.di.CollectionBean" id="collectionBean">
	<property name="nameSet">
		<!-- set 객체를 만들어 값을 요소로 추가한다. (중복값은 허용되지 않는다) -->
		<set>
			<value>홍길동</value>
			<value>임꺽정</value>
			<value>전우치</value>
			<value>홍길동</value>
		</set>
	</property>
		
	<property name="nameList">
		<list>
			<value>홍길동</value>
			<value>임꺽정</value>
			<value>전우치</value>
			<value>홍길동</value>
		</list>
	</property>
</bean>

 

main 실행

 

list는 순서가 존재하며 중복값이 저장된다.

 


LogoutController 클래스와 ListController 클래스 선언 

package xyz.itwill05.di;

//인터페이스
public interface Controller {
	//추상메소드 선언
	void handleRequest();
}


public class LogoutController implements Controller {
	@Override
	public void handleRequest() {
		// TODO Auto-generated method stub
	}
}


public class ListController implements Controller {
	@Override
	public void handleRequest() {
		// TODO Auto-generated method stub
		
	}
}

 

 

컬렉션 객체의 제네릭을 인터페이스로 설정하면 컬렉션 객체의 요소에는 인터페이스를 상속받은 자식클래스(위에 클래스들...)로 생성된 객체를 요소로 추가할 수 있다 

 

[CollectionBean]

package xyz.itwill05.di;

import java.util.List;
import java.util.Set;

public class CollectionBean {
	...
	private Set<Controller> controllerSet;
	private List<Controller> controllerList;
	
	...
	public Set<Controller> getControllerSet() {
		return controllerSet;
	}

	public void setControllerSet(Set<Controller> controllerSet) {
		this.controllerSet = controllerSet;
	}

	public List<Controller> getControllerList() {
		return controllerList;
	}

	public void setControllerList(List<Controller> controllerList) {
		this.controllerList = controllerList;
	}
}

 

Controller 인터페이스를 상속받은 자식클래스를 Spring Bean으로 등록

<bean class="xyz.itwill05.di.LoginController" id="loginController"/>
<bean class="xyz.itwill05.di.LogoutController" id="logoutController"/>
<bean class="xyz.itwill05.di.ListContoller" id="listContoller"/>

 

ref 엘리먼트를 통해 컬렉션 객체에 Spring Bean을 전달하여 요소로 추가한다.

  • bean 속성 : 요소로 추가될 Spring Bean의 식별자(beanName)를 속성값으로 설정해준다.
...
<property name="controllerSet">
	<set>
		<ref bean="loginController"/>
		<ref bean="logoutController"/>
		<ref bean="listController"/>
	</set>
</property>

<property name="controllerList">
	<list>
		<ref bean="loginController"/>
		<ref bean="logoutController"/>
			<ref bean="listController"/>
	</list>
</property>
...


 

이번엔 Map 객체를 저장해보자

 

  • map 엘리먼트로 Map 객체를 생성하여 필드에 저장할 수 있다.
  • map 엘리먼트의 하위 엘리먼트로 entry 엘리먼트를 이용해 Map 객체에 엔트리(Entry - Key & Value)를 추가할 수 있다.
  • key 엘리먼트를 이용해 엔트리의 맵키(MapKey)를 설정한다. 
  • ref 엘리먼트를 이용해 엔트리의 맵값(MapValue - Controller)를 설정한다. 
...
<property name="controllerMap">
	<!-- map : Map 객체를 생성하여 필드에 저장하기 위한 엘리먼트 -->
	<map>
		<!-- entry : Map 객체에 엔트리(Entry - Key & Value)를 추가하기 위한 엘리먼트 -->
		<entry>
			<!-- key : 엔트리의 맵키(Map Key - String)를 설정하기 위한 엘리먼트 -->
			<key>
				<value>login</value>
			</key>
			<!-- ref : 엔트리의 맵값(Map Value - Controller)를 설정하기 위한 엘리먼트 -->
			<ref bean="loginController"/>
		</entry>
		<entry>
			<key>
				<value>logout</value>
			</key>
				<ref bean="logoutController"/>
		</entry>
		<entry>
			<key>
				<value>list</value>
			</key>
				<ref bean="listController"/>
		</entry>
	</map>
</property>
...

Properties 객체

 

 

props 엘리먼트를 이용해 Properties 객체를 생성하여 필드에 저장할 수 있다.

 

필드의 자료형이 Map<String, String>인 경우 props 엘리먼트로 Map 객체를 생성하여 객체 필드에 저장이 가능하다.

 

prop 엘리먼트를 이용해 Properties 엔트리를 추가해준다.

prop 엘리먼트의 내용으로 엔트리의 맵값으로 사용한다.

  • key 속성에는 엔트리의 맵키를 속성값으로 설정한다.

 

<property name="controllerProperties">
	<props>
        <prop key="login">xyz.itwill05.di.LoginController</prop>
        <prop key="logout">xyz.itwill05.di.LogoutController</prop>
        <prop key="list">xyz.itwill05.di.ListController</prop>
	</props>
</property>

 

 


[AutoWireApp]

package xyz.itwill05.di;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AutoWireApp {
	public static void main(String[] args) {
		System.out.println("================ Spring Container 초기화 전 ================");
		ApplicationContext context=new ClassPathXmlApplicationContext("05-3_autowire.xml");
		System.out.println("================ Spring Container 초기화 후 ================");
		...
        	...
		System.out.println("============================================================");
		((ClassPathXmlApplicationContext)context).close();
	}
}

 

[05-3_autowire.xml]

 

StudentDAO 인터페이스를 상속받은 자식클래스를 Spring Bean으로 등록해보자

<bean class="xyz.itwill05.di.StudentJdbcDAO" id="studentJdbcDAO"/>

 

StudentService 인터페이스를 상속받은 자식클래스를 Spring Bean으로 등록해보자.


단, StudentServiceImpl 클래스로 생성된 객체의 studentDAO 필드에 studentDAO 인터페이스를 상속받은 자식클래스의 객체가 저장되도록 의존성을 주입해야 한다. 그래야만 의존관계가 구현된다.


의존성 주입을 하지 않은 경우 StudentServiceImpl 클래스의 메소드에서 studentDAO 필드... 메소드를 호출할 경우 NullPointerException이 발생한다.

property 엘리먼트로 studentDAO 필드에 StudentDAO 인터페이스를 상속받은 자식클래스의 객체가 저장되도록 설정한다. - Setter Injection을 이용하여 DI를 구현

<bean class="xyz.itwill05.di.StudentServiceImpl" id="studentService">
	<property name="studentDAO" ref="studentJdbcDAO"/>
</bean>

 

main 메소드

StudentService service=context.getBean("studentService", StudentService.class);
service.addStudent(null);

 

 


의존성 주입을 수동으로 하는 것이 아니라 자동으로 하는 법을 알아보자

 

autowire 속성을 사용해 의존성 주입을 자동으로 설정할 수 있다.

 

autowire 속성은 클래스로 객체(Spring Bean)를 생성될 때 스프링 컨테이너가 자동으로 Spring Bean을 필드에 저장하는 속성이다. 

autowire 속성은 DI 기능을 자동으로 구현되도록 만들어주는 속성이다.

  • no(기본), byName, nyType, constructor 중 하나를 속성값으로 설정한다.

 

no 속성값

: 자동으로 의존관계를 구현하는 기능을 사용하지 않도록 해준다. (기본값)

→ 생성자 또는 Setter 메소드를 사용하여 필드에 Spring Bean을 저장한다. (수동으로 DI를 구현)

<bean class="xyz.itwill05.di.StudentServiceImpl" id="studentService" autowire="no">
	<property name="studentDAO" ref="studentJdbcDAO"/>
</bean>

 

byName 속성값

: Spring Bean으로 등록된 클래스의 필드명과 같은 이름의 식별자(beanName)로 등록된 Spring Bean을 제공받아 저장되도록 의존성 주입을 한다. - Setter Injection

→ 필드명과 같은 이름의 식별자로 선언된 Spring Bean이 없는 경우엔 의존성 주입이 되지 않아 NullPointerException이 발생한다. 

 

이름이 같아야 하기 때문에 id 속성값을 studentDAO 로 변경해준다.

 

<!-- StudentDAO 인터페이스를 상속받은 자식클래스를 Spring Bean으로 등록 -->
<!-- <bean class="xyz.itwill05.di.StudentJdbcDAO" id="studentJdbcDAO"/> -->
<bean class="xyz.itwill05.di.StudentJdbcDAO" id="studentDAO"/>
...
<bean class="xyz.itwill05.di.StudentServiceImpl" id="studentService" autowire="byName"/>

 

main 메소드 실행

 

 

byType 속성값

: 클래스의 필드와 같은 자료형의 Spring Bean을 제공받아 필드에 저장되도록 의존성을 주입한다. - Setter Injection 

→ 필드의 자료형이 인터페이스인 경우 인터페이스를 상속받은 자식클래스로 등록된 Spring Bean을 제공받아 필드에 저장되도록 의존성을 주입시킬 수 있다.

...
<bean class="xyz.itwill05.di.StudentJdbcDAO" id="studentJdbcDAO"/>  
...
<bean class="xyz.itwill05.di.StudentServiceImpl" id="studentService" autowire="byType"/>

 

main

 

필드의 자료형과 같은 Spring Bean이 2개 이상 등록된 경우 의존성 주입이 되지 않기 때문에 주의해야한다.

 

<!-- 에러 발생 -->
<bean class="xyz.itwill05.di.StudentJdbcDAO" id="studentJdbcDAO"/>  
<bean class="xyz.itwill05.di.StudentMybatisDAO" id="studentMybatisDAO"/>

 

constructor 속성값

: 클래스의 필드와 같은 자료형의 Spring Bean를 제공받아 필드에 저장되도록 의존성 주입 - Constructor Injection

  • 필드의 자료형이 인터페이스인 경우 인터페이스를 상속받은 자식클래스로 등록된 Spring Bean를 제공받아 필드에 저장되도록 의존성 주입
  • 필드의 자료형과 같은 Spring Bean이 2개 이상 등록된 경우 의존성 미주입 

 

<bean class="xyz.itwill05.di.StudentServiceImpl" id="studentService" autowire="constructor"/>

 

main