이전 섹션에서 언급한 것처럼 Bean 속성(property)과 생성자 인수를 다른 관리 대상 Bean(협력자)에 대한 참조로 정의하거나 인라인으로 정의된 값으로 정의할 수 있습니다. Spring의 XML 기반 구성 메타데이터는 이러한 목적을 위해 <property/>
및 <constructor-arg/>
요소 내에서 하위 요소 타입을 지원합니다.
<property/>
요소의 value
속성(attribute)은 속성(property)이나 생성자 인수를 사람이 읽을 수 있는 문자열 표현으로 지정합니다. Spring의 변환 서비스는 이러한 값을 String
에서 속성(property) 또는 인수의 실제 타입으로 변환하는 데 사용됩니다. 다음 예에서는 다양한 값이 설정되는 것을 보여줍니다.
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="misterkaoli"/>
</bean>
다음 예에서는 더욱 간결한 XML 구성을 위해 p-namespace를 사용합니다.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/mydb"
p:username="root"
p:password="misterkaoli"/>
</beans>
앞의 XML은 더 간결(succinct)합니다. 그러나 빈 정의를 생성할 때 자동 속성(property) 완성을 지원하는 IDE(예: IntelliJ IDEA 또는 Eclipse용 Spring 도구)를 사용하지 않는 한 오타(typo)는 디자인 타임이 아닌 런타임에 발견됩니다. 이러한 IDE 지원을 적극 권장합니다.
다음과 같이 java.util.Properties
인스턴스를 구성할 수도 있습니다.
<bean id="mappings"
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<!-- typed as a java.util.Properties -->
<property name="properties">
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
</property>
</bean>
Spring 컨테이너는 JavaBeans PropertyEditor
메커니즘을 사용하여 <value/>
요소 내부의 텍스트를 java.util.Properties
인스턴스로 변환합니다. 이것은 좋은 지름길이며 Spring 팀이 value
속성(attribute) 스타일보다 중첩된 <value/>
요소의 사용을 선호하는 몇 안 되는 곳 중 하나입니다.
idref
elementidref
요소는 컨테이너에 있는 다른 Bean의 id
(reference가 아닌 문자열 value)를 <constructor-arg/>
또는 <property/>
요소에 전달하는 오류 방지(error-proof) 방법일 뿐입니다. 다음 예에서는 사용 방법을 보여줍니다.
<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean"/>
</property>
</bean>
위의 Bean 정의 조각(snippet)은 (런타임 시) 다음 조각과 정확히 동일합니다.
<bean id="theTargetBean" class="..." />
<bean id="client" class="...">
<property name="targetName" value="theTargetBean"/>
</bean>
idref
태그를 사용하면, 참조(referenced)되고 명명된(named) bean이 실제로 존재하는지 컨테이너가 배포 시간(deployment time)에 확인할 수 있기 때문에 첫 번째 형식이 두 번째 형식보다 선호됩니다. 두 번째 변형에서는 client
Bean의 targetName
속성(property)에 전달된 값에 대해 유효성 검증이 수행되지 않습니다. 오타는 client
bean이 실제로 인스턴스화될 때만 발견됩니다(치명적인 결과가 발생할 가능성이 높음). client
bean이 prototype Bean인 경우 이 오타와 결과 예외는 컨테이너가 배포된 지 한참 후에야 발견될 수 있습니다.
[Note]
idref
요소의local
속성(attribute)은 더 이상 일반bean
참조에 대한 값을 제공하지 않으므로 4.0 Bean XSD에서 더 이상 지원되지 않습니다. 4.0 스키마로 업그레이드할 때 기존idref local
참조를idref bean
으로 변경하십시오.
<idref/>
요소가 값을 가져오는 일반적인 위치(적어도 Spring 2.0 이전 버전에서는)는 ProxyFactoryBean
빈 정의 내부의 AOP 인터셉터 구성에 있습니다. 인터셉터 이름을 지정할 때 <idref/>
요소를 사용하면 인터셉터 ID 철자가 틀린 것을 방지할 수 있습니다.
ref
요소는 <constructor-arg/>
또는 <property/>
정의 요소 내부의 마지막 요소입니다. 여기서는 컨테이너가 관리하는 다른 Bean(collabprator)에 대한 참조가 되도록 Bean의 지정된 속성(property) 값을 설정합니다. 참조된 Bean은 속성이 설정될 Bean의 종속성이며 속성이 설정되기 전에 필요에 따라(on demand) 초기화됩니다. (collaborator가 싱글톤 Bean인 경우 컨테이너에 의해 이미 초기화되었을 수 있습니다.) 모든 참조는 궁극적으로 다른 객체에 대한 참조입니다. 범위 지정(scoping) 및 유효성 검증(validation)은 bean
또는 parent
속성을 통해 다른 객체의 ID 또는 이름을 지정하는지 여부에 따라 달라집니다.
<ref/>
태그의 bean
속성(attribute)을 통해 대상 bean을 지정하는 것이 가장 일반적인 형식이며 동일한 XML 파일에 있는지 여부에 관계없이 동일한 컨테이너 또는 상위 컨테이너에 있는 모든 bean에 대한 참조를 생성할 수 있습니다. bean
속성(attribute)의 값은 대상(target) bean의 id
속성(attribute)과 동일하거나 대상 bean의 name
속성(attribute)에 있는 값 중 하나와 동일할 수 있습니다. 다음 예에서는 ref
요소를 사용하는 방법을 보여줍니다.
<ref bean="someBean"/>
parent
속성(attribute)을 통해 대상 Bean을 지정하면 현재 컨테이너의 상위 컨테이너에 있는 Bean에 대한 참조가 생성됩니다. parent
속성(attribute)의 값은 대상 bean의 id
속성(attribute)이나 대상 bean의 name
속성에 있는 값 중 하나와 동일할 수 있습니다. 대상 Bean은 현재 Bean의 상위 컨테이너에 있어야 합니다. 주로 컨테이너 계층이 있고 상위 컨테이너의 기존 Bean을 상위 Bean과 동일한 이름을 가진 프록시로 래핑하려는 경우, 이 Bean 참조 변형을 사용해야 합니다. 다음 목록 쌍은 parent
속성을 사용하는 방법을 보여줍니다.
<!-- in the parent context -->
<bean id="accountService" class="com.something.SimpleAccountService">
<!-- insert dependencies as required here -->
</bean>
<!-- in the child (descendant) context -->
<bean id="accountService" <!-- bean name is the same as the parent bean -->
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref parent="accountService"/> <!-- notice how we refer to the parent bean -->
</property>
<!-- insert other configuration and dependencies as required here -->
</bean>
[Note]
ref
요소의local
속성은 더 이상 일반 Bean 참조에 대한 값을 제공하지 않기 때문에 4.0 Bean XSD에서 더 이상 지원되지 않습니다. 4.0 스키마로 업그레이드할 때 기존ref local
참조를ref bean
으로 변경하세요.
<property/>
또는 <constructor-arg/>
요소 내의 <bean/>
요소는 다음 예제와 같이 내부 Bean을 정의합니다
<bean id="outer" class="...">
<!-- instead of using a reference to a target bean, simply define the target bean inline -->
<property name="target">
<bean class="com.example.Person"> <!-- this is the inner bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>
내부 Bean 정의에는 정의된 ID나 이름이 필요하지 않습니다. 지정된 경우 컨테이너는 해당 값을 식별자로 사용하지 않습니다. 내부 Bean은 항상 익명(anonymous)이고 항상 외부 Bean으로(with) 생성되기 때문에 컨테이너는 생성 시 scope
플래그도 무시합니다. 내부 Bean에 독립적으로 액세스하거나 이를 둘러싸는(enclosing) Bean이 아닌 collaborating Bean에 삽입(inject)하는 것은 불가능합니다.
특수한 경우(corner case)로 사용자 정의 범위(scope)에서 소멸 콜백(destruction callback)을 수신(receive)하는 것이 가능합니다. 예를 들어 싱글톤 Bean 내에 포함된 request-scope inner Bean의 경우입니다. inner Bean 인스턴스 생성은 그것을 포함하는 Bean과 연결되어 있지만 소멸 콜백(destruction callback)은 request scope의 lifecycle에 참여할 수 있게 해줍니다. 이는 일반적인 시나리오가 아닙니다. 내부 Bean은 일반적으로 포함하는 Bean의 범위를 공유합니다.
<list/>
, <set/>
, <map/>
및 <props/>
요소는 각각 Java Collection
유형 List
, Set
, Map
및 Properties
의 속성(property)과 인수를 설정합니다. 다음 예에서는 이를 사용하는 방법을 보여줍니다.
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
map 키나 값 또는 set 값은 다음 요소 중 하나일 수도 있습니다.
bean | ref | idref | list | set | map | props | value | null
Spring 컨테이너는 컬렉션 병합도 지원합니다. 애플리케이션 개발자는 상위 <list/>
, <map/>
, <set/>
또는 <props/>
요소를 정의하고 하위 <list/>
, <map/>
, <set/>
또는 <props/>
요소들이 상위 컬렉션의 값을 상속하게 하고 값을 재정의 할 수 있습니다. 즉, 하위 컬렉션의 값은, 상위 컬렉션에서 지정한 값을 하위 컬렉션에서 재정의함으로서 상위 및 하위 컬렉션의 요소를 병합한 결과입니다.
병합에 관한 이 섹션에서는 상위-하위 Bean 메커니즘에 대해 설명합니다. 상위 및 하위 Bean 정의에 익숙하지 않은 독자는 계속하기 전에 관련 섹션을 읽어보는 것이 좋습니다.
다음 예에서는 컬렉션 병합을 보여줍니다.
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.com</prop>
<prop key="support">support@example.com</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- the merge is specified on the child collection definition -->
<props merge="true">
<prop key="sales">sales@example.com</prop>
<prop key="support">support@example.co.uk</prop>
</props>
</property>
</bean>
<beans>
child
Bean 정의의 adminEmails
속성에 있는 <props/>
요소에 merge=true
속성을 사용하는 것에 주목하세요. child
Bean이 컨테이너에 의해 resolve되고 인스턴스화되면 결과 인스턴스에는 자식의 adminEmails
컬렉션을 부모의 adminEmails
컬렉션과 병합한 결과가 포함된 adminEmails
Properties
컬렉션이 있습니다. 다음 목록은 결과를 보여줍니다.
administrator=administrator@example.com
sales=sales@example.com
support=support@example.co.uk
하위 Properties
컬렉션의 값 세트는 상위 <props/>
의 모든 속성(property) 요소를 상속하며 support
값에 대한 하위 값은 상위 컬렉션의 값을 재정의합니다.
이 병합 동작은 <list/>
, <map/>
및 <set/>
컬렉션 유형과 유사하게 적용됩니다. <list/>
요소의 특정 경우에는 List
컬렉션 type과 관련된 semantic(즉, 순서가 지정된(ordered
) 값 컬렉션의 개념)가 유지됩니다. 상위 목록의 값은 모든 하위 목록 값보다 우선(precede)합니다. Map
, Set
및 Properties
컬렉션 유형의 경우 순서가 없습니다. 따라서 컨테이너가 내부적으로 사용하는 연관된 Map
, Set
및 Properties
구현 타입의 기초가 되는 컬렉션 유형에 대해서는 순서 의미 체계가 적용되지 않습니다.
서로 다른 컬렉션 유형(예: Map
과 List
)을 병합할 수 없습니다. 그렇게 하려고 시도하면 적절한 Exception
가 발생합니다. merge
속성(attribute)은 상속된, 하위, 자식 정의에 지정되어야 합니다. 상위 컬렉션 정의에 merge
속성(attribute)을 지정하는 것은 중복되며(redundant) 원하는 병합이 이루어지지 않습니다.
Java의 generic type 지원 덕분에 강력한 유형의 컬렉션을 사용할 수 있습니다. 즉, String
요소만 포함할 수 있도록 Collection
유형을 선언할 수 있습니다.
Spring을 사용하여 강력한 type의 Collection
을 Bean에 종속성 주입하는 경우 강력한 type의 Collection
인스턴스의 요소가 Collection
에 추가되기 전에 적절한 유형으로 변환되도록 Spring의 유형 변환 지원을 활용할 수 있습니다.
다음 Java 클래스 및 Bean 정의는 이를 수행하는 방법을 보여줍니다.
public class SomeClass {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
<beans>
<bean id="something" class="x.y.SomeClass">
<property name="accounts">
<map>
<entry key="one" value="9.99"/>
<entry key="two" value="2.75"/>
<entry key="six" value="3.99"/>
</map>
</property>
</bean>
</beans>
something
Bean의 accounts
속성(property)을 주입할 준비가 되면 강력한 형식의 Map<String, Float>
요소 유형에 대한 일반 정보를 리플렉션을 통해 사용할 수 있습니다. 따라서 Spring의 유형 변환 인프라는 다양한 값 요소를 Float
유형으로 인식하고 문자열 값(9.99
, 2.75
및 3.99
)을 실제 Float
유형으로 변환합니다.
Spring은 속성(property) 등에 대한 빈(empty) 인수를 빈(empty) String
로 처리합니다. 다음 XML 기반 구성 메타데이터 조각은 email
속성(property)을 빈 String
값("")으로 설정합니다.
<bean class="ExampleBean">
<property name="email" value=""/>
</bean>
앞의 예제는 다음 Java 코드와 동일합니다.
exampleBean.setEmail("");
<null/>
요소는 null
값을 처리합니다. 다음 목록은 예를 보여줍니다.
<bean class="ExampleBean">
<property name="email">
<null/>
</property>
</bean>
앞의 구성은 다음 Java 코드와 동일합니다.
exampleBean.setEmail(null);
p-네임스페이스를 사용하면 (내포된(nested) <property/>
요소 대신) bean
요소의 속성(attribute)을 사용하여 bean과 협력(collaborating)하는 속성(property) 값 또는 둘 다를 설명할 수 있습니다.
Spring은 XML 스키마 정의를 기반으로 하는 네임스페이스를 사용하여 확장 가능한 구성 형식을 지원합니다. 이 장에서 논의되는 beans
구성 형식은 XML 스키마 문서에 정의되어 있습니다. 그러나 p-네임스페이스는 XSD 파일에 정의되지 않고 Spring 코어에만 존재합니다.
다음 예에서는 동일한 결과를 resolve하는 두 개의 XML 조각(첫 번째는 표준 XML 형식을 사용하고 두 번째는 p-네임스페이스를 사용함)을 보여줍니다.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="classic" class="com.example.ExampleBean">
<property name="email" value="someone@somewhere.com"/>
</bean>
<bean name="p-namespace" class="com.example.ExampleBean"
p:email="someone@somewhere.com"/>
</beans>
예제에서는 Bean 정의에 있는 email
이라는 p-네임스페이스의 속성(attribute)을 보여줍니다. 이는 Spring에 속성(property) 선언을 포함하도록 지시합니다. 앞서 언급한 것처럼 p-namespace에는 스키마 정의가 없으므로 속성(attribute) 이름을 속성(property) 이름으로 설정할 수 있습니다.
다음 예제에는 다른 Bean을 참조하는 두 개의 Bean 정의가 더 포함되어 있습니다.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="john-classic" class="com.example.Person">
<property name="name" value="John Doe"/>
<property name="spouse" ref="jane"/>
</bean>
<bean name="john-modern"
class="com.example.Person"
p:name="John Doe"
p:spouse-ref="jane"/>
<bean name="jane" class="com.example.Person">
<property name="name" value="Jane Doe"/>
</bean>
</beans>
이 예에는 p-네임스페이스를 사용하는 속성(property) 값뿐만 아니라 속성(property) 참조를 선언하는 특수 형식도 포함됩니다. 첫 번째 bean 정의는 <property name="spouse" ref="jane"/>
를 사용하여 bean john
에서 bean jane
으로의 참조를 생성하는 반면, 두 번째 bean 정의는 p:spouse-ref="jane"
을 속성(attribute)으로 사용하여 똑같은 작업을 수행합니다. 이 경우 spouse
는 속성(property) 이름인 반면 -ref
부분은 이것이 직접적인 값(straight value)이 아니라 오히려 다른 bean에 대한 참조임을 나타냅니다.
[Note]
p-네임스페이스는 표준 XML 형식만큼 유연하지 않습니다. 예를 들어 속성(property) 참조 선언 형식은Ref
로 끝나는 속성(property)과 충돌하지만 표준 XML 형식은 그렇지 않습니다. 세 가지 접근 방식을 동시에 사용하는 XML 문서를 생성하지 않도록 접근 방식을 신중하게 선택하고 이를 팀 구성원에게 알리는 것이 좋습니다.
p-네임스페이스를 이용한 XML shortcut와 유사하게, Spring 3.1에 도입된 c-네임스페이스는 중첩된 constructor-arg
요소 대신 생성자 인수를 구성하기 위한 인라인 속성(attribute)을 허용합니다.
다음 예제에서는 c:
네임스페이스를 사용하여 생성자 기반 종속성 주입과 동일한 작업을 수행합니다.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
<!-- traditional declaration with optional argument names -->
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="something@somewhere.com"/>
</bean>
<!-- c-namespace declaration with argument names -->
<bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo"
c:thingThree-ref="beanThree" c:email="something@somewhere.com"/>
</beans>
c:
네임스페이스는 생성자 인수를 이름으로 설정하기 위해 p:
(bean 참조의 후행 -ref
)와 동일한 규칙을 사용합니다. 마찬가지로 XSD 스키마에 정의되지 않은 경우(Spring 코어 내부에 있음)에도 XML 파일에서 선언해야 합니다.
생성자 인수 이름을 사용할 수 없는 드문 경우(일반적으로 바이트코드가 디버깅 정보 없이 컴파일된 경우)에는 다음과 같이 인수 인덱스에 대한 대체(fallback)를 사용할 수 있습니다.
<!-- c-namespace index declaration -->
<bean id="beanOne" class="x.y.ThingOne" c:_0-ref="beanTwo" c:_1-ref="beanThree"
c:_2="something@somewhere.com"/>
[Note]
XML 문법으로 인해 인덱스 표기 시에는 앞에_
가 있어야 합니다. XML 속성 이름은 숫자로 시작할 수 없기 때문입니다(일부 IDE에서 허용하더라도). 해당 색인 표기법은<constructor-arg>
요소에도 사용할 수 있지만 일반 선언 순서로 충분하므로 흔히 사용되지 않습니다.
실제로 생성자 resolution 메커니즘은 인수 matching에 매우 효율적이므로 꼭 필요한 경우가 아니면 구성 전체에서 이름 표기법을 사용하는 것이 좋습니다.
최종 속성(property) 이름을 제외한 경로(path)의 모든 component가 null
이 아닌 한, Bean 속성을 설정할 때 복합(compound) 또는 중첩(nested) 속성(property) 이름을 사용할 수 있습니다. 다음 Bean 정의를 고려하십시오.
<bean id="something" class="things.ThingOne">
<property name="fred.bob.sammy" value="123" />
</bean>
something
Bean에는 sammy
속성(property)이 있는 bob
속성(property)이 있는 fred
속성(property)이 있으며 최종 sammy
속성의 값은 123
으로 설정됩니다. 이것이 작동하려면 something
의 fred
속성과 bob
속성이 필요합니다. 빈이 생성된 후에는 fred
의 속성이 null
이 아니어야 합니다. 그렇지 않으면 NullPointerException
이 발생합니다.