Loading...
Spring Framework Reference Documentation 7.0.2의 Dependencies and Configuration in Detail의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
이전 섹션에서 언급했듯이,
bean property와 constructor argument를 다른 managed bean(협력자)에 대한 reference로
또는 inline으로 정의된 value로 정의할 수 있습니다. Spring의 XML 기반 설정 메타데이터는
이 목적을 위해 <property/> 및 <constructor-arg/> element 내에서 sub-element type을 지원합니다.
<property/> element의 value attribute는 property 또는 constructor
argument를 사람이 읽을 수 있는 string 표현으로 지정합니다. Spring의
conversion service는 이러한
value를 String에서 property나 argument의 실제 type으로 변환하는 데 사용됩니다.
다음 예제는 다양한 value가 설정되는 방법을 보여 줍니다:
1<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 2 <!-- results in a setDriverClassName(String) call --> 3 <property name="driverClassName" value="com.mysql.jdbc.Driver"/> 4 <property name="url" value="jdbc:mysql://localhost:3306/mydb"/> 5 <property name="username" value="root"/> 6 <property name="password" value="misterkaoli"/> 7</bean>
다음 예제는 더 간결한 XML 설정을 위해 p-namespace를 사용합니다:
1<beans xmlns="http://www.springframework.org/schema/beans" 2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns:p="http://www.springframework.org/schema/p" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 https://www.springframework.org/schema/beans/spring-beans.xsd"> 6 7 <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" 8 destroy-method="close" 9 p:driverClassName="com.mysql.jdbc.Driver" 10 p:url="jdbc:mysql://localhost:3306/mydb" 11 p:username="root" 12 p:password="misterkaoli"/> 13 14</beans>
앞의 XML이 더 간결합니다. 그러나 bean definition을 생성할 때 property 자동 완성을 지원하는 IntelliJ IDEA나 Spring Tools와 같은 IDE를 사용하지 않는 한, 오타는 design time이 아니라 runtime에 발견됩니다. 이러한 IDE 지원을 적극 권장합니다.
다음과 같이 java.util.Properties 인스턴스를 구성할 수도 있습니다:
1<bean id="mappings" 2 class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"> 3 4 <!-- typed as a java.util.Properties --> 5 <property name="properties"> 6 <value> 7 jdbc.driver.className=com.mysql.jdbc.Driver 8 jdbc.url=jdbc:mysql://localhost:3306/mydb 9 </value> 10 </property> 11</bean>
Spring 컨테이너는 JavaBeans PropertyEditor mechanism을 사용하여 <value/> element 안의
text를 java.util.Properties 인스턴스로 변환합니다. 이것은 좋은 shortcut이며,
nested <value/> element 사용을 value attribute style보다 선호하는 몇 안 되는 경우 중 하나입니다.
idref elementidref element는 컨테이너 안의 다른 bean의 id(reference가 아닌 string value)를
<constructor-arg/> 또는 <property/> element에 전달하는 error-proof 방식일 뿐입니다.
다음 예제는 이를 사용하는 방법을 보여 줍니다:
1<bean id="collaborator" class="..." /> 2 3<bean id="client" class="..."> 4 <property name="targetName"> 5 <idref bean="collaborator" /> 6 </property> 7</bean>
앞의 bean definition snippet은 runtime 시점에서 다음 snippet과 정확히 동일합니다:
1<bean id="collaborator" class="..." /> 2 3<bean id="client" class="..."> 4 <property name="targetName" value="collaborator" /> 5</bean>
첫 번째 형식이 두 번째 형식보다 선호되는데, idref tag를 사용하면
컨테이너가 배포 시점에 reference된 이름의 bean이 실제로 존재하는지 검증할 수 있기 때문입니다.
두 번째 변형에서는 client bean의 targetName property에 전달되는 value에 대해
아무런 validation도 수행되지 않습니다. 따라서 오타는 client bean이 실제로
생성될 때(대부분 치명적인 결과와 함께) 발견됩니다. client bean이
prototype bean인 경우, 이 오타와 그로 인한
exception은 컨테이너가 배포된 후 한참이 지나서야 발견될 수 있습니다.
<idref/>element가 가치를 발휘하는 일반적인 위치(적어도 Spring 2.0 이전 버전에서는)는ProxyFactoryBeanbean definition에서 AOP interceptors를 설정할 때입니다. interceptor 이름을 지정할 때<idref/>element를 사용하면 interceptor ID를 잘못 입력하는 것을 방지할 수 있습니다.
ref element는 <constructor-arg/> 또는 <property/> definition element 안에서의 마지막 element입니다.
여기서 bean의 지정된 property value를 컨테이너가 관리하는 다른 bean(협력자)에 대한
reference로 설정합니다. reference된 bean은 property가 설정될 bean의 dependency이며,
property가 설정되기 전에 필요에 따라 on demand로 초기화됩니다.
(협력자가 singleton bean인 경우, 이미 컨테이너에 의해 초기화되어 있을 수 있습니다.)
모든 reference는 궁극적으로 다른 객체에 대한 reference입니다. scoping과 validation은
bean 또는 parent attribute를 통해 다른 객체의 ID나 name을 지정하는지에 따라 달라집니다.
<ref/> tag의 bean attribute를 통해 target bean을 지정하는 것은 가장 일반적인 형식이며,
같은 XML file에 있는지 여부와 관계없이 같은 컨테이너 또는 parent 컨테이너에 있는
어떤 bean에 대해서도 reference를 생성할 수 있게 해 줍니다. bean attribute의 value는
target bean의 id attribute와 같거나 target bean의 name attribute value 중 하나와 같을 수 있습니다.
다음 예제는 ref element를 사용하는 방법을 보여 줍니다:
1<ref bean="someBean"/>
parent attribute를 통해 target bean을 지정하면 현재 컨테이너의 parent 컨테이너에 있는
bean에 대한 reference가 생성됩니다. parent attribute의 value는 target bean의 id attribute와 같거나
target bean의 name attribute value 중 하나와 같을 수 있습니다. target bean은
반드시 현재 컨테이너의 parent 컨테이너에 있어야 합니다.
이 bean reference 변형은 주로
컨테이너 hierarchy가 있고 parent 컨테이너의 기존 bean을 parent bean과 동일한 이름을 가진
proxy로 wrapping하려는 경우에 사용해야 합니다. 다음 두 listing은 parent attribute를
사용하는 방법을 보여 줍니다:
1<!-- in the parent context --> 2<bean id="accountService" class="com.something.SimpleAccountService"> 3 <!-- insert dependencies as required here --> 4</bean>
1<!-- in the child (descendant) context, bean name is the same as the parent bean --> 2<bean id="accountService" 3 class="org.springframework.aop.framework.ProxyFactoryBean"> 4 <property name="target"> 5 <ref parent="accountService"/> <!-- notice how we refer to the parent bean --> 6 </property> 7 <!-- insert other configuration and dependencies as required here --> 8</bean>
refelement의localattribute는 더 이상 4.0 beans XSD에서 지원되지 않습니다. 이는 더 이상 일반적인beanreference보다 나은 가치를 제공하지 않기 때문입니다. 4.0 schema로 업그레이드할 때 기존의ref localreference를ref bean으로 변경하십시오.
<property/> 또는 <constructor-arg/> element 안의 <bean/> element는
다음 예제와 같이 inner bean을 정의합니다:
1<bean id="outer" class="..."> 2 <!-- instead of using a reference to a target bean, simply define the target bean inline --> 3 <property name="target"> 4 <bean class="com.example.Person"> <!-- this is the inner bean --> 5 <property name="name" value="Fiona Apple"/> 6 <property name="age" value="25"/> 7 </bean> 8 </property> 9</bean>
inner bean definition은 정의된 ID나 name을 필요로 하지 않습니다. 지정된 경우에도
컨테이너는 그러한 value를 identifier로 사용하지 않습니다. 또한 컨테이너는 생성 시
scope flag를 무시하는데, inner bean은 항상 anonymous이며 항상 outer bean과 함께 생성되기 때문입니다.
inner bean에 독립적으로 access하거나 enclosing bean 이외의 다른 협력 bean에 inner bean을 inject하는 것은 불가능합니다.
corner case로, custom scope에서 destruction callback을 받는 것이 가능합니다. 예를 들어, singleton bean에 포함된 request-scoped inner bean의 경우가 이에 해당합니다. inner bean 인스턴스의 생성은 이를 포함하는 bean에 묶여 있지만, destruction callback을 통해 request scope의 lifecycle에 참여할 수 있습니다.
이는 흔한 시나리오는 아닙니다. inner bean은 일반적으로 이를 포함하는 bean의 scope를 단순히 공유합니다.
<list/>, <set/>, <map/>, 그리고 <props/> element는 각각 Java Collection type인
List, Set, Map, 그리고 Properties의 property와 argument를 설정합니다.
다음 예제는 이를 사용하는 방법을 보여 줍니다:
1<bean id="moreComplexObject" class="example.ComplexObject"> 2 <!-- results in a setAdminEmails(java.util.Properties) call --> 3 <property name="adminEmails"> 4 <props> 5 <prop key="administrator">[email protected]</prop> 6 <prop key="support">[email protected]</prop> 7 <prop key="development">[email protected]</prop> 8 </props> 9 </property> 10 <!-- results in a setSomeList(java.util.List) call --> 11 <property name="someList"> 12 <list> 13 <value>a list element followed by a reference</value> 14 <ref bean="myDataSource" /> 15 </list> 16 </property> 17 <!-- results in a setSomeMap(java.util.Map) call --> 18 <property name="someMap"> 19 <map> 20 <entry key="an entry" value="just some string"/> 21 <entry key="a ref" value-ref="myDataSource"/> 22 </map> 23 </property> 24 <!-- results in a setSomeSet(java.util.Set) call --> 25 <property name="someSet"> 26 <set> 27 <value>just some string</value> 28 <ref bean="myDataSource" /> 29 </set> 30 </property> 31</bean>
map key나 value의 value, 또는 set value는 다음 element 중 어느 것이든 될 수 있습니다:
1bean | ref | idref | list | set | map | props | value | null
Spring 컨테이너는 collection merging도 지원합니다. 애플리케이션
개발자는 parent <list/>, <map/>, <set/> 또는 <props/> element를 정의하고
child <list/>, <map/>, <set/> 또는 <props/> element가 parent collection에서
value를 상속하고 override하도록 할 수 있습니다.
즉, child collection의 value는 parent와 child collection element를 merge한 결과이며, child collection element가 parent collection에 지정된 value를 override합니다.
이 merging 섹션은 parent-child bean mechanism에 대해 설명합니다. parent와 child bean definition에 익숙하지 않은 독자는 계속 진행하기 전에 관련 섹션을 읽는 것이 좋습니다.
다음 예제는 collection merging을 보여 줍니다:
1<beans> 2 <bean id="parent" abstract="true" class="example.ComplexObject"> 3 <property name="adminEmails"> 4 <props> 5 <prop key="administrator">[email protected]</prop> 6 <prop key="support">[email protected]</prop> 7 </props> 8 </property> 9 </bean> 10 <bean id="child" parent="parent"> 11 <property name="adminEmails"> 12 <!-- the merge is specified on the child collection definition --> 13 <props merge="true"> 14 <prop key="sales">[email protected]</prop> 15 <prop key="support">[email protected]</prop> 16 </props> 17 </property> 18 </bean> 19</beans>
child bean definition의 adminEmails property의 <props/> element에서 merge=true
attribute가 사용되는 것에 주목하십시오. child bean이 컨테이너에 의해
resolve되고 인스턴스화될 때, 결과 인스턴스는 child의 adminEmails collection과
parent의 adminEmails collection을 merge한 결과를 포함하는 adminEmails``Properties collection을 갖습니다.
다음 listing은 그 결과를 보여 줍니다:
child Properties collection의 value set은 parent <props/>의 모든 property element를 상속하며,
support value에 대한 child의 value가 parent collection의 value를 override합니다.
이 merging 동작은 <list/>, <map/>, 그리고 <set/> collection type에도 유사하게 적용됩니다.
특히 <list/> element의 경우, List collection type과 연관된 의미(즉, ordered
collection value의 개념)가 유지됩니다. parent의 value가 모든 child list value보다 먼저 옵니다.
Map, Set, 그리고 Properties collection type의 경우, ordering이 존재하지 않습니다.
따라서 컨테이너가 내부적으로 사용하는 관련 Map, Set, 그리고 Properties implementation type을
뒷받침하는 collection type에는 ordering semantic이 적용되지 않습니다.
서로 다른 collection type(예: Map과 List)을 merge할 수는 없습니다.
그렇게 시도하면 적절한 Exception이 발생합니다. merge attribute는
하위, 상속된 child definition에 지정해야 합니다. parent collection definition에
merge attribute를 지정하는 것은 중복되며 원하는 merging 결과를 가져오지 못합니다.
Java의 generic type 지원 덕분에 strongly typed collection을 사용할 수 있습니다.
즉, Collection type을 선언할 때 (예를 들어) String element만 포함할 수 있도록
선언하는 것이 가능합니다. Spring을 사용하여 strongly typed Collection을 bean에
dependency-inject하는 경우, strongly typed Collection 인스턴스의 element가
Collection에 추가되기 전에 적절한 type으로 변환되도록 하는 Spring의
type-conversion 지원을 활용할 수 있습니다.
다음 Java class와 bean definition은 이를 수행하는 방법을 보여 줍니다:
1public class SomeClass { 2 3 private Map<String, Float> accounts; 4 5 public void setAccounts(Map<String, Float> accounts) { 6 this.accounts = accounts; 7 } 8}
1class SomeClass { 2 lateinit var accounts: Map<String, Float> 3}
1<beans> 2 <bean id="something" class="x.y.SomeClass"> 3 <property name="accounts"> 4 <map> 5 <entry key="one" value="9.99"/> 6 <entry key="two" value="2.75"/> 7 <entry key="six" value="3.99"/> 8 </map> 9 </property> 10 </bean> 11</beans>
something bean의 accounts property가 injection을 위해 준비될 때,
strongly typed Map<String, Float>의 element type에 대한 generics 정보는
reflection을 통해 사용할 수 있습니다. 따라서 Spring의 type conversion infrastructure는
각각의 value element를 Float type으로 인식하고, string value(9.99, 2.75, 그리고
3.99)를 실제 Float type으로 변환합니다.
Spring은 property 등에 대한 empty argument를 empty String으로 취급합니다.
다음 XML 기반 설정 메타데이터 snippet은 email property를
empty String value("")로 설정합니다.
1<bean class="ExampleBean"> 2 <property name="email" value=""/> 3</bean>
앞의 예제는 다음 Java code와 동일합니다:
1exampleBean.setEmail("");
1exampleBean.email = ""
<null/> element는 null value를 처리합니다. 다음 listing은 예제를 보여 줍니다:
1<bean class="ExampleBean"> 2 <property name="email"> 3 <null/> 4 </property> 5</bean>
앞의 설정은 다음 Java code와 동일합니다:
1exampleBean.setEmail(null);
1exampleBean.email = null
p-namespace를 사용하면 nested <property/> element 대신 bean element의 attribute를 사용하여
property value, 협력 bean 또는 둘 다를 설명할 수 있습니다.
Spring은 XML Schema definition을 기반으로 하는 namespace를 사용하여
확장 가능한 설정 포맷을 지원합니다. 이 장에서 다루는 beans 설정 포맷은
XML Schema document에서 정의됩니다. 그러나 p-namespace는 XSD file에서 정의되지 않으며
Spring core에만 존재합니다.
다음 예제는 동일한 결과로 resolve되는 두 개의 XML snippet(첫 번째는 standard XML 포맷을 사용하고 두 번째는 p-namespace를 사용함)을 보여 줍니다:
1<beans xmlns="http://www.springframework.org/schema/beans" 2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns:p="http://www.springframework.org/schema/p" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 https://www.springframework.org/schema/beans/spring-beans.xsd"> 6 7 <bean name="classic" class="com.example.ExampleBean"> 8 <property name="email" value="[email protected]"/> 9 </bean> 10 11 <bean name="p-namespace" class="com.example.ExampleBean" 12 p:email="[email protected]"/> 13</beans>
이 예제는 bean definition에서 p-namespace에 있는 email이라는 attribute를 보여 줍니다.
이는 Spring에게 property declaration을 포함하도록 지시합니다. 앞에서 언급했듯이,
p-namespace는 schema definition을 가지고 있지 않으므로 attribute의 이름을
property name으로 설정할 수 있습니다.
다음 예제는 또 다른 bean에 대한 reference를 모두 포함하는 두 개의 bean definition을 포함합니다:
1<beans xmlns="http://www.springframework.org/schema/beans" 2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns:p="http://www.springframework.org/schema/p" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 https://www.springframework.org/schema/beans/spring-beans.xsd"> 6 7 <bean name="john-classic" class="com.example.Person"> 8 <property name="name" value="John Doe"/> 9 <property name="spouse" ref="jane"/> 10 </bean> 11 12 <bean name="john-modern" 13 class="com.example.Person" 14 p:name="John Doe" 15 p:spouse-ref="jane"/> 16 17 <bean name="jane" class="com.example.Person"> 18 <property name="name" value="Jane Doe"/> 19 </bean> 20</beans>
이 예제는 p-namespace를 사용한 property value뿐만 아니라 property reference를 선언하기 위한
특수 포맷도 사용합니다. 첫 번째 bean definition은 <property name="spouse" ref="jane"/>를 사용하여
bean john에서 bean jane으로의 reference를 생성하는 반면,
두 번째 bean definition은 동일한 작업을 attribute로 수행하기 위해 p:spouse-ref="jane"을 사용합니다.
이 경우, spouse는 property name이고, -ref 부분은 이것이 단순 value가 아니라
다른 bean에 대한 reference임을 나타냅니다.
p-namespace는 standard XML 포맷만큼 유연하지 않습니다. 예를 들어, property reference를 선언하기 위한 포맷은 이름이
Ref로 끝나는 property와 충돌하지만, standard XML 포맷은 그렇지 않습니다. 세 가지 approach를 동시에 사용하는 XML document가 생성되는 것을 방지하려면 approach를 신중하게 선택하고 이를 팀 구성원에게 알리는 것이 좋습니다.
XML Shortcut with the p-namespace와 유사하게,
Spring 3.1에 도입된 c-namespace는 nested constructor-arg element 대신
constructor argument를 구성하기 위한 inline attribute를 허용합니다.
다음 예제는
Constructor-based Dependency Injection에서와 동일한 작업을 수행하기 위해
c: namespace를 사용합니다:
1<beans xmlns="http://www.springframework.org/schema/beans" 2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns:c="http://www.springframework.org/schema/c" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 https://www.springframework.org/schema/beans/spring-beans.xsd"> 6 7 <bean id="beanTwo" class="x.y.ThingTwo"/> 8 <bean id="beanThree" class="x.y.ThingThree"/> 9 10 <!-- traditional declaration with optional argument names --> 11 <bean id="beanOne" class="x.y.ThingOne"> 12 <constructor-arg name="thingTwo" ref="beanTwo"/> 13 <constructor-arg name="thingThree" ref="beanThree"/> 14 <constructor-arg name="email" value="[email protected]"/> 15 </bean> 16 17 <!-- c-namespace declaration with argument names --> 18 <bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo" 19 c:thingThree-ref="beanThree" c:email="[email protected]"/> 20 21</beans>
c: namespace는 constructor argument를 name으로 설정하기 위해 p: namespace와 동일한
convention(bean reference의 경우 끝에 -ref를 붙임)을 사용합니다. 마찬가지로,
XSD schema에 정의되어 있지 않더라도 XML file에서 선언해야 합니다
(이는 Spring core 내부에 존재합니다).
constructor argument name이 사용 가능하지 않은 드문 경우(일반적으로 bytecode가
-parameters flag 없이 compile된 경우), 다음과 같이 argument index로
되돌아갈 수 있습니다:
1<!-- c-namespace index declaration --> 2<bean id="beanOne" class="x.y.ThingOne" c:_0-ref="beanTwo" c:_1-ref="beanThree" 3 c:_2="[email protected]"/>
XML grammar로 인해 index 표기에는 앞에
_가 필요합니다. XML attribute name은 일부 IDE에서 허용하더라도 숫자로 시작할 수 없기 때문입니다.<constructor-arg>element에도 해당 index 표기가 제공되지만, 단순 declaration 순서만으로도 보통 충분하기 때문에 일반적으로 사용되지는 않습니다.
실제로 constructor resolution mechanism은 argument를 매칭하는 데 상당히 효율적이므로, 정말 필요하지 않은 한 설정 전체에서 name 표기를 사용하는 것을 권장합니다.
bean property를 설정할 때, 마지막 property name을 제외한 path의 모든 component가
null이 아닌 한 compound 또는 nested property name을 사용할 수 있습니다.
다음 bean definition을 살펴보십시오:
1<bean id="something" class="things.ThingOne"> 2 <property name="fred.bob.sammy" value="123" /> 3</bean>
something bean에는 fred property가 있고, 그 안에 bob property가 있으며,
그 안에 sammy property가 있습니다. 그리고 마지막 sammy property가 value 123으로
설정되고 있습니다. 이것이 동작하려면, bean이 생성된 후 something의 fred property와
fred의 bob property가 null이 아니어야 합니다. 그렇지 않으면 NullPointerException이 발생합니다.
Dependency Injection
Using depends-on