이전 글 : https://jaedam.tistory.com/5
[Spring] 스프링 DI를 이용한 객체 생성(1)
DI란? DI는 Dependency Injection의 줄임말로서 의존성 주입이라고도 부른다. 스프링은 기본적으로 DI를 기반으로 동작하기 때문에 DI에 대한 이해가 필수이다. 여기서 말하는 의존(Dependency)이란 한 클래
jaedam.tistory.com
앞서 DI의 개념과 스프링 컨테이너 및 빈 객체를 설정하는 방식을 간략하게 살펴보았다.
이번 글에서는 스프링 컨테이너의 종류와 XML 파일의 각 태그에 대해서 살펴보자.
스프링 컨테이너 종류
스프링은 BeanFactory와 ApplicationContext의 두 가지 타입의 컨테이너를 제공한다. 이 중에서 BeanFactory 계열은 단순히 컨테이너에서 객체를 생성하고 DI를 처리해주는 기능만을 제공하기 때문에 거의 사용하지 않는다. 반면 ApplicationContext 계열은 트랜잭션 처리, 자바 코드 기반 스프링 설정, 어노테이션 빈 설정, 웹 개발, 메시지 처리 등 다양한 부가 기능을 제공하기 때문에 ApplicationContext 계열을 주로 사용한다.
다음은 실제로 사용되는 구현 클래스들이다.
- GenericXmlApplicationContext : XML 파일을 설정 정보로 사용하는 스프링 컨테이너. 독립형 애플리케이션을 개발할 때 사용
- AnnotationConfigApplicationContext : 자바 코드를 설정 정보로 사용하는 스프링 컨테이너. 독립형 애플리케이션을 개발할 때 사용
- GenericGroovyApplicationContext : 그루비 언어로 작성된 설정 정보로 사용하는 스프링 컨테이너. 독립형 애플리케이션을 개발할 때 사용
- XmlWebApplicationContext : XML 파일을 설정 정보로 사용하는 스프링 컨테이너. 웹 애플리케이션을 개발할 때 사용
- AnnotationConfigWebApplicationContext : 자바 코드를 설정 정보로 사용하는 스프링 컨테이너. 웹 애플리케이션을 개발할 때 사용
이들 중 WebApplicationContext로 끝나는 두 개의 클래스는 코드에서 직접 사용할 일은 없으며, web.xml과 같은 웹 애플리케이션 설정 파일에서 간접적으로 사용하게 된다.
XML을 이용한 DI 설정
<bean> 태그 : 생성할 객체 지정
<bean id="sampleProject" class="[패키지경로].Project"></bean>
주요 속성은 id와 class인데, class 속성은 패키지 경로를 포함한 완전 클래스 이름이어야 한다. id 속성 값은 <bean> 스프링 빈 객체의 고유한 이름으로 사용한다.
AbstractApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationContext.xml");
Project project = ctx.getBean("sampleProject", Project.class);
위 코드에서 getBean 메서드로 빈 객체를 구할 때에 사용되는 것이 id 속성이다. 만약 id 속성을 지정하지 않으면
[패키지경로].Project#0과 같은 임의의 이름을 생성한다.
<constructor-arg> 태그 : 생성자 방식 설정
public class User {
private String id;
private String password;
public User(String id, String password) {
this.id = id;
this.password = password;
}
// 이하 생략
...
}
<bean id="user" class="[패키지경로].User">
<constructor-arg value="jaedam" />
<constructor-arg value="qwer" />
</bean>
User 객체를 스프링 빈으로 설정하려면 생성자에 전달할 값을 설정해야 되는데 이때 사용되는 태그가 <constructor-arg> 태그이다. <constructor-arg> 태그는 생성자의 파라미터 개수만큼 지정해야 하고, <constructor-arg> 태그의 순서가 곧 전달될 파라미터의 순서가 된다. 즉 다음과 같이 객체를 생성하는 것과 비슷하다. (실제로는 자바의 리플렉션이라는 기능을 이용해서 생성한다.)
new User("jaedam", "qwer");
value 속성 대신 ref 속성을 사용할 수도 있다. ref 속성은 다른 빈 객체의 이름을 사용한다. 여기서 말하는 이름이란 위에서 설명한 <bean> 태그의 id 속성이다.
<bean id="userRepository" class="[패키지경로].UserRepository">
...
</bean>
<bean id="pwChangeSvc" class="[패키지경로].PasswordChangeService">
<constructor-arg><ref bean="userRepository"/></constructor-arg>
</bean>
<property> 태그 : 프로퍼티 방식 설정
<bean id="mvnBuildRunner" class="[패키지경로].MavenBuildRunner">
<property name="mavenPath">
<value>c:\maven-3.8.4</value>
</property>
</bean>
name 속성을 이용해서 프로퍼티 이름을 지정한다. <value> 태그나 value 속성, <ref> 태그나 ref 속성을 이용해서 값을 설정할 수 있다. <property> 태그를 사용하면 setPropertyName() 형식의 메서드를 이용해서 값을 설정한다. 위 설정은 다음과 같이 set 메서드를 이용한다. 이때 프로퍼티 이름의 첫 글자를 대문자로 변환한 이름을 사용해서 set 메서드를 선택한다.
setMavenPath("c:\maven-3.8.4");
<list>, <map>, <set> 태그 : List, Map, Set 타입의 컬렉션 설정
각각 <list>, <map>, <set> 태그를 사용한다. 먼저 <list> 태그를 보자.
<bean id="user1" class="[패키지경로].User">
...
</bean>
<bean id="user2" class="[패키지경로].User">
...
</bean>
<bean id="userRepository" class="[패키지경로].UserRepository">
<property name="users">
<list>
<ref bean="user1" />
<ref bean="user2" />
</list>
</property>
</bean>
위 설정은 users 프로퍼티에 원소로 user1 빈과 user2 빈 객체를 담은 List를 전달하도록 설정하고 있다. 즉, 다음 코드와 유사하다.
List<User> refs = new ArrayList<>();
refs.add(user1);
refs.add(user2);
userRepository.setUsers(refs);
리스트로 전달할 목록이 객체가 아니라 Integer나 String과 같은 타입이라면 <value> 태그를 사용해서 값 목록을 전달할 수도 있다.
다음은 <map> 태그를 보자.
<bean id="sensor1" class="[패키지경로].Sensor">
...
</bean>
<bean id="sensor2" class="[패키지경로].Sensor">
...
</bean>
<bean id="monitor" class="[패키지경로].Monitor">
<property name="sensorMap">
<map>
<entry>
<key>
<value>frontDoor</value>
</key>
<ref bean="sensor1" />
</entry>
<entry key="backDoor" value-ref="sensor2" />
</map>
</property>
</bean>
<map> 태그는 <entry> 태그를 이용해서 (키, 값) 쌍 목록을 전달한다. 위 설정을 보면, 첫 번째 <entry> 태그는 키로 "frontDoor"를 사용하고, 값으로 sensor1 빈 객체를 사용한다. 두 번째 <entry> 태그는 키로 "backDoor"를 사용하고, 값으로는 sensor2 빈 객체를 사용한다. 두 번째 <entry> 태그는 value-ref 속성을 사용했는데, 이는 값으로 빈 객체를 사용한다는 의미이다.
다음은 <set> 태그를 보자.
<bean id="sensor2" class="[패키지경로].Sensor">
<property name="agentCodes">
<set>
<value>200</value>
<value>300</value>
</set>
</property>
</bean>
Set 타입의 프로퍼티를 설정하는 방법은 List 타입과 유사하다. 그냥 <list> 태그 대신, <set> 태그를 사용하면 된다.
<props>, <prop> 태그 : Properties 타입 값 설정
(키, 값) 쌍이 필요할 때 Map을 사용하지만, (키, 값) 쌍의 목록이 설정 값의 목록을 의미하는 경우에는 java.util.Properties를 사용하는 경우가 더 많다. Properties는 주로 다음과 같은 외부 설정 파일을 읽어올 때 사용된다.
# 서버 관련 설정
servers.list=10.20.30.40:9001, 10.20.30.40:9002
servers.timeout=3000
Sensor 클래스가 Properties 타입의 프로퍼티를 갖고 있다고 하자.
public class Sensor {
private Properties additionalInfo;
public void setAdditionalInfo(Properties additionalInfo) {
this.additionalInfo = additionalInfo;
}
// 이하 생략
...
}
이때, additionalInfo 프로퍼티에 Properties 타입의 객체를 값으로 전달하고 싶다면, 아래 설정처럼 <props>, <prop> 태그를 이용하면 된다.
<bean id="sensor1" class="[패키지경로].Sensor">
<property name="additionalInfo">
<props>
<prop key="threshold">1500</prop>
<prop key="retry">3</prop>
</props>
</property>
</bean>
<prop> 태그의 key 속성은 Properties 객체의 프로퍼티 이름이며, <prop> 태그의 몸체 값은 해당 프로퍼티의 값이 된다. 즉, 위 설정은 다음과 같은 결과를 만들어낸다.
Properties prop = new Properties();
prop.setProperty("threshold", "1500");
prop.setProperty("retry", "3");
sensor1.setAdditionalInfo(prop);
다음과 같이 간결한 방법으로 Properties 타입의 프로퍼티를 설정할 수도 있다.
bean id="sensor2" class="[패키지경로].Sensor">
<property name="additionalInfo">
<value>
threshold = 3000
retry = 5
</value>
</property>
</bean>
다음글 : https://jaedam.tistory.com/9
[Spring] 스프링 DI를 이용한 객체 생성(3)
이전 글 : https://jaedam.tistory.com/7 [Spring] 스프링 DI를 이용한 객체 생성(2) 이전 글 : https://jaedam.tistory.com/5 [Spring] 스프링 DI를 이용한 객체 생성(1) DI란? DI는 Dependency Injection의 줄임..
jaedam.tistory.com
Reference
- 웹 개발자를 위한 Spring 4.0 프로그래밍 (최범균 저)
'Spring' 카테고리의 다른 글
| [Spring] @Qualifier 어노테이션 (0) | 2022.02.11 |
|---|---|
| [Spring] @Autowired 어노테이션 (0) | 2022.02.11 |
| [Spring] 자바 설정 빈 객체 생성 방법 (0) | 2022.02.10 |
| [Spring] 스프링 DI를 이용한 객체 생성(3) (0) | 2022.02.10 |
| [Spring] 스프링 DI를 이용한 객체 생성(1) (0) | 2022.02.08 |