1.4.2 의존성과 configuration by ks

이전 섹션에서 언급했다시피 내부에서 정의된 값 또는 빈(콜라보레이터)를 참조하는 생성자 인자와 프로퍼티들을 정의할 수 있다. 스프링의 XML 기반 configuration 메타데이터는 서브 엘리먼트 타입(<property/>, <constructor-arg>를 지원한다.

스트레이트 값(???? 검색해도 안나와... 느낌으로 알아줘..) (원시타입, String 등등)

<property/> 요소에서 value attribute는 string으로 보여지는, 사람이 볼 수 있는 형태로 생성자의 인자, 프로퍼티를 구체화한다. 스프링의 conversion service 은 이 값들을 String에서 실제 프로퍼티 또는 인자의 타입으로 변환하는데 사용된다. 아래 예제는 다양한 값들이 세팅되는 것을 보여준다.

<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="masterkaoli"/>
</bean>

아래는 p-namespace를 사용한 예제다.

p-namespace란 <property/>와 같은 기능을 가능하게 한다.

<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
    http://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="masterkaoli"/>

</beans>

XMl을 사용하는게 더 간결하다. 하지만 오타는 디자인타임보다 런타임에 발견된다 빈을 생성할때 프로퍼티를 자동완성하는 IDE를 사용하더라도. (하나씩 등록하는 방법이구,)

java.util.Properties 인스턴스를 구성할 수 있다. (여러 개 한번에 등록하는 방법이야)

<bean id="mappings"
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

    <!-- 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>

스프링 컨테이너는 <value/> 값을 java.util.Properties 인스턴스로 PropertyEditor 메카니즘을 이용해 변환한다. 이건 빠르고, 스프링 팀이 중첩된 <value/>요소를 사용하는 것을 속성 스타일보다 선호하는 몇 안되는 것 중 하나다.

propertyEditor

즉, PropertyEditor는 문자열로 표현 된 <value>의 값을 <property>의 type에 맞게 객체를 생성하는 역할을 한다. 출처: https://javaslave.tistory.com/63 [전산쟁이 블로그]

idref 요소

idref 요소는 간단하게 컨테이너의 또다른 빈의 id(참조가 아니라 문자열 값)를 <contructor-arg/> 나 <property/> 요소로 넘겨서 에러를 방지하는 방법이다.

<bean id="theTargetBean" class="..."/>

<bean id="theClientBean" class="...">
    <property name="targetName">
        <idref bean="theTargetBean"/>
    </property>
</bean>

빈 정의 스니펫은 정확하게 런타임 시점에 동등하다.

<bean id="theTargetBean" class="..." />

<bean id="client" class="...">
    <property name="targetName" value="theTargetBean"/>
</bean>

첫번째 형태는 두번째보다 더 선호될 수 있다. 왜냐하면 idref 태그를 사용하는 것은 컨테이너가 실제로 존재하는 빈을 참조하는 개발시점에 검증하게 하기 때문이다. 두번째는 client빈의 tagetName 속성에 값이 넘어가는 것을 검증 안할지도 모른다. 오타는 오직 (대부분 치명적인 결과를 낳는) client 빈이 실제로 인스턴스화될 때 발견된다. 만약 client 빈이 프로토타입 빈이면 이 오타와 결과로 나온 exception이 컨테이너가 배포된 후에 발견될지도 모른다. (idref를 쓰면 개발할때 즉 컴파일할때 알 수 있는거같아. 개발시점이고, value로 지정하면 인스턴스화는 빌드될 때 일어나니까)

프로토타입 빈

컨테이너는 기본적으로 싱글톤 빈으로 만들어 사용하는데, 때로는 하나의 빈으로 여러 객체를 만들어야할 때가 있다. 그럴때 프로토타입 빈을 사용한다. 프로토타입 빈은 컨테이너에게 빈을 요청할 때마다 매번 새로운 객체를 생성하여 반환한다.

참조 : https://nkcnow.tistory.com/234

보통의 bean 레퍼런스에 값을 제공하지 않기 때문에 idref의 local attribute는 4.0부터 더이상 지원되지 않는다. idref local 레퍼런스는 idref bean으로 4.0부터는 변경해야한다.

2.0보다 이른 버전에서 idref요소를 사용하는 곳에서는 ProxyFactoryBean 정의에서 AOP interceptor 의 configuration에서 값을 준다.(?) 인터셉터 이름을 구체화할 때 idref 요소를 사용하는 것은 오탈자가 나는 것을 예방해준다.

다른 빈들 참조 (Collaborators)

ref 요소(element)는 <contructor-args/> 나 <property/> 정의 요소(element) 안에 마지막 요소(element)다.(이하 요소 = element). 여기서 컨테이너가 관리하는 또다른 빈(collaborator) 를 참조하기 위한 빈의 속성을 구체화한다.(collaborator는 하나의 빈이 다른 빈을 참조할 때 참조된 그 빈을 collaborator라고 하는 것같아. ) 참조된 빈은 세팅된 프로퍼티를 가진 빈의 의존성을 가지고, 프로퍼티가 세팅되기 전에 초기화된다. (만약 collaborator가 싱글톤빈이면(참조할 빈이 싱글톤이라면! 이란 이야기겠지??) 이미 컨테이너에 의해 초기화되었을 수도 있다.) 모든 레퍼런스들은 궁극적으로 또다른 오브젝트를 참조한다. 범위와 검증은 bean, local, parent 로 다른 오브젝트의 이름이나 ID를 구체화하는지 여부에 의존한다.

<ref/> 태그의 bean attribute로 타겟 빈을 구체화하는 것은 가장 일반적인 형태이고 같은 XML 파일에 있는지 여부에 관계 없이 같은 컨테이너나 부모 컨테이너의 빈을 참조하는 것이다. bean attribute의 값은 타겟 빈의 name attribute의 값 중 하나와 같거나 타겟 빈의 id attriute와 같을지도 모른다. 아래 예제는 ref 요소를 어떻게 사용하는지를 보여준다.

<ref bean="someBean"/>

parent attribute 로 타겟 빈을 구체화하는 것은 동일한 컨테이너의 부모 컨테이너에 있는 빈을 참조하는 parent attribute를 통해 생성한다. parent attribute의 값은 타겟 빈의 name attribute 값 중 하나 또는 타겟 빈의 id attribute 중 하나와 같을지도 모른다. 타겟 빈은 현재 컨테이너의 부모 컨테이너안에 있을수도 있다. 이 빈의 참조는 주로 부모 밑의 이름과 같은 프록시를 가진 부모 컨테이너의 존재하는 빈을 감싸고 컨테이너들의 상하 구조(hierarchy)를 가질 때 사용해야만 한다. 아래는 어떻게 parent attribute를 사용하는지를 보여준다.

(부모 컨테이너는 자식 컨테이너에 접근할 수 없고, 자식 컨테이너는 부모 컨테이너에 접근할 수있어. 그래서 부모 컨테이너의 빈을 사용하겠다고 아래와 같이 선언하는 거 같아)

- in the parent context -->

<bean id="accountService" class="com.something.SimpleAccountService">
    <!-- insert dependencies as required as 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>

ref 요소에 local attribute는 4.0부터 지원하지 않는다. 존재하는 ref local 레퍼런스는 ref bean으로 4.0이후 부턴 변경해야한다.

이너 빈 (inner bean)

<property/>나 <contructor-arg/> 요소 안에서 local 요소는 이너 빈을 정의한다.

<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>

이너 빈은 ID 나 이름을 요구하지 않는다. 구체화 되면 컨테이너는 식별자로서 값을 사용하지 않는다. 컨테이너는 또한 scope 플래그를 생성시에 무시한다. 왜냐하면 이너 빈은 항상 익명이고 아우터빈과 함께 생성되기 때문이다. 이너빈에 의존성없이 접근하는것은 불가능하고 콜라보레이팅 빈(참조한 빈)이나 둘러싼 빈으로 주입하는 것도 불가능하다.

엣지 케이스와 코너케이스

엣지케이스 : 값이 수용가능한 범위를 넘으면 발생한다. 비슷하게 경계 케이스(boundary case)

코너케이스 : 여러 변수와 환경의 복합적 요인으로 발생한다. 테스트때는 정상 작동하지만 라이브때 오류가 발생한다던지.. 오후 2시엔 괜찮았는데 오후 7시엔 문제가 생긴다던지.. 발생 상황을 재현하기 어렵다.

코너케이스로 커스텀 스코프에서 콜백들을 파기할 수 있다. 예를 들어서 싱글톤 빈 안에 포함된 request-scoped 이너 빈 같은 경우. 이너 빈 인스턴스의 생성은 포함하는 빈에 묶이지만 콜백 파기는 request scope의 라이프사이클에 참여시킨다. 이는 평범한 시나리오는 아니다. 이너 빈은 전형적으로 간단하게 포함하는 빈의 스코프를 공유한다.

inner bean 과 autowired

이너 빈이 빈 안에 빈이라면 @autowired랑 같은 기능일까 하고 찾아봤는데, 결론부터 말하면 아니야. 이너 빈은 위에서 말했던 것 처럼 익명이야. 그리고 프로토타입 빈이라서 요청이 들어올때만 생성돼. ID도 필요없는 반면 빈은 기본적으로 ID가 있고 싱글톤이잖아. 그래서 아니래

컬렉션

<list/>, >, <set/>, <map/>, <props/>는 자바 컬렉션 타입 List, Set, Map, Properties의 인자와 프로퍼티를 세팅한다.

<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>

맵 키와 밸류의 값, 나 셋 밸류의 값은 또한 아래 요소들의 어떤 것으로도 될 수 있다.

bean | ref | idref | list | set | map | props | value | null

컬렉션 머지

스프링 컨테이너는 또한 컬렉션을 머지할 수 있다. 어플리케이션 개발자는 부모 < List/>,<map/>,<set/>,<props/>요소를 정의할 수 있고 부모 컬렉션으로 부터 값을 오버라이드하고 상속하여 차일드 <List/>,><map/>,<set/>,<props/>를 가질 수 있다. 즉, 자식 컬렉션의 값은 부모의 컬렉션에서 구체화된 것을 오버라이드한 자식 컬렉션 요소와, 부모와 자식 요소를 머지한 결과이다.

이 섹션은 부모-자식 빈을 머지하는 메커니즘에 대해 얘기한다. 독자들은 부모와 자식 빈을 정의하는게 어색할 수 도 있다. 그러면 계속 하기 전에 relevant section 를 읽고 와라.(내가 먼저 읽고올게!)

1.7이네.. 자식 빈은 부모 정의의 configuration 정보를 상속받아 정의한다. 오버라이드할 수도 있고 다른것을 필요하면 추가할 수도 있다. 이 방식은 타이핑하는걸 줄일 수 있다. 효과적으로 하면 탬플릿화 하는 서이다. ApplicationContext로 동작한다면 ChileBeanDefinition class로 자식 빈을 표현한다.

말그대로, 부모자식 빈(상속받는 관계)를 의미하는 것 같아.

아래 예제는 컬렉션 머지하는 것을 보여준다.

<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>

자식 빈의 정의에서 adminEmails 값의 <props/>요소에 merge=true 를 사용해라. child 빈이 컨테이너에 의해 초기화되고 나눠질때 인스턴스는 부모의 adminEmails로 자식의 adminEmail컬렉션을 머지한 결과를 포함하는 adminEmails Properties 컬렉션을 가진다.

administrator=administrator@example.com
sales=sales@example.com
support=support@example.co.uk

자식 Properties 컬렉션의 값은 부모 <props/> 의 모든 프로퍼티 요소를 상속하고 자식의 support 값은 부모 컬렉션의 값을 오버라이드한다.

이 머지하는 행위는 <list/>,>map/>,<set/> 컬렉션 타입에 유사하게 적용된다. <list/>의 경우에는 List컬렉션과 관련된 의미(시맨틱)가 유지된다(즉, 순서가 있는 개념). 부모의 값은 자식 리스트의 값의 전부를 앞선다. Map, Set, Properties 컬렉션 타입에 경우에는 순서가 없다. 이런 까닭에 순서가 없는 것은 컨테이너가 내부적으로 사용하는 Map, Set, Properties 구체화 타입에 기초가 되는 컬렉션 타입에 효과적이다.

컬렉션 머지의 한계

가령 Map , List같은 컬렉션 타입같이 다른 타입을 머지할 수 없다. 만약 그렇게 하려고 하면 Exception 이 던져진다. merge attribute는 더 낮고 상속되고 자식 정의에 구체화되어야 한다(상속받은 자식 컬렉션에 정의가 되어야돼!). 부모 컬렉션 정의에 merge attribute를 구체화하는 것은 많고 바라는 대로 머지대로 결과가 나오지도 않는다.

강하게 타입화된 컬렉션(Stringly-typed collection)

자바 5에서 제네릭 타입을 소개해서 강하게 타입화된 컬렉션을 사용할 수 있다. 즉, 가령 오직 String 요소를 포함하는 Collection 타입이라 할 수 있다. 만약 스프링이 강하게 타입화된 컬랙션을 빈 안에 의존성 주입한다면 컬렉션에 추가되기 전에 적절한 타입으로 변환되는 강하게 타입화된 컬렉션 인스턴스의 요소를 스프링의 타입 변환을 지원하는 이점을 취할 수 있다. 아래는 자바 클래스와 빈의 정의이다.

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 이라는 빈의 account 프로퍼티가 주입할 준비가 되었을 때, 강하게 타입화된 Map<String, Float> 의 요소 타입에 대한 제네릭 정보는 반영될 수 있다. 그러므로 스프링의 타입 변환은 실제 Float타입으로 변환되는 string값(9.99,2.75,3.99와 같은 문자열) 과 Float타입이 될 수 있는 다양한 값들을 알게된다. (강제 형변환 시켜주는 거같아. 위에서 9.99가 ""로 감싸져 있어서 문자열이지만 Float로 변환되는거지)

Null과 빈 문자열

스프링은 빈 String처럼 프로퍼티스의 빈 인자를 다룬다. 아래 XML기반 configuration 메타데이터 스니펫이 email 프로퍼티를 String ""로 세팅하는걸 보여준다.

<bean class="ExampleBean">
    <property name="email" value=""/>
</bean>

아래는 같은 기능을 하는 자바 코드다.

exampleBean.setEmail("");

<null/>요소는 null값을 다룬다.

<bean class="ExampleBean">
    <property name="email">
        <null/>
    </property>
</bean>

같은 기능을 하는 자바 코드다.

exampleBean.setEmail(null);

XML p-namespace shortcut

p-namespace는 bean 요소의 (감싸진 <property/>요소 대신에) attribute를 사용해서 bean을 콜라보하는 프로퍼티 값을 설명하거나 둘 다 설명할 수 있다.

스프링은 XML 스키마 정의에 기반하여 with namespaces 로 configuration 포맷을 확장하는 걸 지원한다. 이 챕터에서 논의될 bean configuration 포맷은 XML 스키마 문서에 정의된다. 하지만 p-namespace는 XSD파일에정의되지 않고 스프링 코어에 존재한다.

아래 졔네느 두개의 XML 스니펫(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
        http://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>

빈 정의에서 email 이라고 불리는 p-namespace에서 attribute를 보여준다. 이는 스프링이 프로퍼티 선언을 포함한다는 것을 말해준다. 이전에 얘기했던 것 처럼 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
        http://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-namespace를 사용한 프로퍼티 값 뿐만 아니라 프로퍼티 참조를 선언하기 위해 특별한 포맷을 사용하도 포함한다. 첫번째 빈이 <property name="spous" ref="jane"/> 를 john빈에서 jane빈을 참조하는 것을 생성하기 위해 사용하므로, 두번째 빈은 p:spouse-ref="jane" 을 같은 의미를 수행하기 위해 attribute로서 사용한다. 이러한 경우에 spous는 프로퍼티 이름이고 -ref 부분은 straight 값이 아니라 이게 또다른 빈으로의 참조라는 것 가리킨다. (jane이라는 빈을 사용할건데 그걸 spouse라고 하겠다는 의미 인듯. 아래는 p:a-ref="jane"인거면 jane을 a라고 하는 거겠지?)

p-namespace는 XML 포맷 표준으로서 유연하진 않다. 예를들어서 Ref의 끝에 프로퍼티와 함께 프로퍼티 참조를 선언하는 포맷과 충돌이 나므로 표준 XML 포맷은 없다. 팀 메버들과 모더 상의하고 쇰스럽게 버근하길 바란다. XML문서를 피하는것을.

XML shortcut with the c-namespace

XML Shortcut with the p-namespace 와 비슷하게 c-namespace는 스프링 3.1에 포함되어있고, 중첩된 constructor-arg 요소보다 생성자 요소로 configure하기 위해 인라인된 attribute를 허가한다.

아래 예제는 c:namespace를 사용한 것이다.(생성자 빈 의존성 주입)

<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
        http://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:namespace는 이름으로 생성자 인자를 세팅하기 위해 p: 랑 같은 컨벤션을 사용한다. 유사하게 XML파일에 선언하는게 필요하다. 비록 XSD스키마에 정의하지않더라도.(스프링 코어에 존재한다.)

드문 상황으로 생상자 인자 이름 유효하지 않으면 아래와 세팅 인자 인덱스로 fallback을 사용한다.(보통 바이트코드는 디버깅 정보 없이 컴파일된다.)

fallback mechanism. 브라우저마다 지원하는 능이 라긔 때문에 의도한 기능이 렌더링 되지 않을 경우 유사하게 동작하도록 한다.

<!-- c-namespace index declaration -->
<bean id="beanOne" class="x.y.ThingOne" c:_0-ref="beanTwo" c:_1-ref="beanThree"
    c:_2="something@somewhere.com"/>

XML 문법 때문에 인덱스 표기법은 _ 이 먼저 나올 것을 요구한다. XML attribute 이름은 숫자로 시작할 수 없다. (비록 IDE가 허락하더라도). 올바른 인덱스 표기법은 또한 <constructor-arg>요소에 사용가능하지만 보통 일반적인 선언 순서가 충분하다면 사용하지 않는다.

생성자 해결 매커니즘은 인자들을 매칭하는데 꽤 효과적이다. 그래서 정말 필요로하지않으면 configuration을 통해 이름 표기법을 사용할 것을 추천한다.

프로퍼티 이름 혼합

빈 프로퍼티를 세팅할 때 중첩된 프로퍼티 이름을 중첩하거나 합성할 수 있다. 마지막 프로퍼티 이름을 제외하고 패스에 있는 모든 컴포넌트들은 null이 아니다.

<bean id="something" class="things.ThingOne">
    <property name="fred.bob.sammy" value="123" />
</bean>

something빈은 fred 프로퍼티, bob프로퍼티, sammy프로퍼티를 가지고, 그 마지막 sammy프로퍼티는 123으로 세팅된다. 이 작업을 하기 위해서 something의 fred프로퍼티와 fred의 bob 프로퍼티는 빈이 생성된 후에 null이면 안된다. 마찬가지로 NullPointerException이 발생된다.

Last updated