본문 바로가기

IT 살이/04. 기술 - 프로그래밍

개발 프레임워크 만들기 대장정 22 - 샘플 프로젝트 및 Spring 컨테이너

이 예제는 Spring.NET 레퍼런스 문서의 QuickStart에서 설명되고 있는 예제중의 하나이다. 3.1.7절에 나와 있다.

이 예제를 통해서 설명할 주용 내용은 다음과 같다.

▶컨테이너에 객체들을 등록하는 설정

- 이게 무슨 말인지 기억나는가? Unity Application Block의 컨테이너 프레임워크에서와 유사 아니 동일한 개념의 작업이다. 물론 객체를 등록하는 설정 표현(syntax)은 다르다.

▶DI(dependencies Injection) 설정

- Unity Application Block의 setter injection, constructor injection을 기억하는가?

▶AOP 설정

- aspect(Cross concerns )를 메인 로직에 weaving(minxin)하는 작업에 대한 예제를 보게 될 것이다. aspect중에서 예제에서는 로깅 aspect가 예로 보여진다.

▶ 음...그리고 필요한대로.

- 다음 예제에서는 설명할 것이 아주 아주 많다. 간단한 샘플 코드를 보지도 않고 바로 예제로 건너뛰었기때문에 앞에서 말한 항목들외에도 Spring.NET의 기본 설정들에 대해서 먼저 설명이 필요할 것이다. 그리고 Spring.NET에서 제공하는 Web Services관련 기능도 이해해야 한다. ASP.NET Web Services를 만들때 지금까지 .asmx 파일을 추가했어야 했지만 Spring.NET에서는 그럴 필요가 없다. 이런 저런 얘기를 하다보면 다음 예제를 완전히 알아보는데 몇 회의 포스트가 필요할 것이다.

우선 예제 프로젝트를 보면 다음과 같다.

■ 프로젝트 구조

■ 프로젝트 설명

프로젝트 설명
Spring.Calculator.Contract 계산기의 기본적인 오퍼레이션을 정의하고 있는 인터페이스 ICalculator를 포함하고 있다. 그리고 IAdvancedCalculator도 포함하고 있는데 계산 결과가 저장될 메모리 계산에 사용될 인터페이스 메소드들이 정의되어 있단다. 그리고 이 프로젝트에는 도메인 객체 DivisionResult도 포함하고 있다. 도메인 객체라면 여러 레이어(주로 3계층의 애플리케이션이 주로 개발된다)에 걸쳐서 참조되는 객체들이다. 비즈니스 인터페이스와 도메인 객체는 서버측( 리모팅 서버, 웹 서비스 서버)과 클라이언트측( 윈폼 애플리케이션, 웹 애플리케이션)에서 사용될 것이기에 별도의 프로젝트에 분리시켜 놓고 있다.
Spring.Calculator.Services ICalculator와 IAdvancedCalculator에 대한 구현이 포함되어 있다. 이 구현이 서비스로서 노출될 것이다. 각각의 구현 클래스의 이름은 Calculator, AdvancedCalculator로 되어 있다. AdvancedCalculator는 IAdvancedCalculator를 구현했을뿐만 아니라 Calculator를 상속하고 있다. 필자는 솔직히 AdvancedCalculator가 확실히 정의되지 않는다. -_-;; 몰라도 상관없을 것 같기에 그냥 넘어간다.
Spring.Calculator.RemoteApp 리모트 객체 AdvancedCalculator 인스턴스를 호스팅할 서버측 애플리케이션을 포함하고 있다.
Spring.Aspects 리모트 객체에 적용할 로깅 advice들을 가지고 있다. 이 advice들을 통해서 AOP 프로그래밍을 적용하는 예를 보여줄 것이다.
Spring.Calculator.ClientApp 클라이언트측 애플리케이션을 포함하고 있다.  그러나 이번 예제에서는 사용하지 않을 것이다.
Spring.Calculator.Web Spring.Calculator.ClientApp대신에 클라이언트 애플리케이션으로 사용한다.

■ 프로젝트의 아키텍쳐

그림이 좀 이상하긴 하지만... 그림에서 나타내려고 하는 것은, 앞의 예제 프로젝트에서는  하나의 비즈니스 객체( Spring.Calculator.Services 프로젝트의 AdvancedCalculator 객체)를 .NET Remoting 서비스로도 노출시키고 웹 서비스로도 노출시키고 있다는 것을 보여주려고 했다. 그리고 그 객체를 COM+에 등록해서 사용하고 있다.

이 구조는 상황에 따라서 조금씩 변경된다. 웹 서비스를 이용해서 타겟 객체에 접근한다고 했을때 클라이언트는 웹 브라우저가 아니라 웹 애플리케이션을 나타내고 있다.  또 상황에 따라서는 .NET Remoting 애플리케이션, 웹 서비스 애플리케이션, COM+애플리케이션이 참조하는 타겟객체는 실제 객체에 대한 참조가 아니라 타겟 객체의 프락시에 대한 참조일 수도 있다.

클라이언트 애플리케이션은 타겟 객체에 대한 인터페이스를 호출하고 있고 서버측 애플리케이션도 타겟 객체에 대한 인터페이스를 참조하고 있다. 이때 인터페이스는 타겟 객체과 구현하고 있는 순수한 인터페이스는 아니다. 물론 순수한 인터페이스를 참조할 수도 있지만 현재 샘플에서는 AOP를 적용하고 있다. 타겟 객체를 호출할때 로그를 남기는 작업을 수행하고 있다. 이 구조에서 좀 더 정확히 표현하자면 "AOP 인터페이스"가 될 것이다. advice 코드가 적절한 pointcut에 weaving된 형태의 인터페이스이다. AOP 인터페이스의 메소드를 호출하게 되면 호출 전 or/and 후에 로그가 남게 된다. 이게 무슨 말인지는 뒤의 포스트에서 설명되고 있다: 시리즈 25 참조.

여튼 앞에서 구성하고 있는 Visual Studio.NET 솔루션에 포함된 프로젝트들의 전체적인 구조는 이렇다는 것이고 필요하다면 상황별로 자세한 설명을 하도록 하겠다. 그러나 이 중에서 웹 서비스를 호출하는 구조를 중심으로 알아볼 것이다.

■ configuration

Spring.Calculator.Web.2005 프로젝트의 web.config 파일을 보면 다음과 같다. 원래 소스에서는 logging섹션이 spring섹션보다 먼저 나오는데, spring섹션을 먼저 설명해야 할 것 같아서 순서를 조금 변경했다.

\par ?? \par ?? <\cf13 object\cf2 \cf6 id\cf2 =\cf0 "\cf2 CommonLoggingAroundAdvice\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Aspects.Logging.CommonLoggingAroundAdvice, Spring.Aspects\cf0 "\cf2 >\par ??\tab \tab \tab \tab <\cf13 property\cf2 \cf6 name\cf2 =\cf0 "\cf2 Level\cf0 "\cf2 \cf6 value\cf2 =\cf0 "\cf2 Debug\cf0 "\cf2 />\par ??\tab \tab \tab \par ?? \par ?? \par ??\tab \tab \tab \par ?? <\cf13 object\cf2 \cf6 id\cf2 =\cf0 "\cf2 calculator\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services\cf0 "\cf2 />\par ??\tab \tab \tab \par ?? <\cf13 object\cf2 \cf6 id\cf2 =\cf0 "\cf2 calculatorWeaved\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop\cf0 "\cf2 >\par ??\tab \tab \tab \tab <\cf13 property\cf2 \cf6 name\cf2 =\cf0 "\cf2 target\cf0 "\cf2 \cf6 ref\cf2 =\cf0 "\cf2 calculator\cf0 "\cf2 />\par ??\tab \tab \tab \tab <\cf13 property\cf2 \cf6 name\cf2 =\cf0 "\cf2 interceptorNames\cf0 "\cf2 >\par ??\tab \tab \tab \tab \tab <\cf13 list\cf2 >\par ??\tab \tab \tab \tab \tab \tab <\cf13 value\cf2 >\cf0 CommonLoggingAroundAdvice\cf2 \par ??\tab \tab \tab \tab \tab \par ??\tab \tab \tab \tab \par ??\tab \tab \tab \par ??\tab \tab \par ?? \par ??\tab \par ?? \par ??\tab \par ?? <\cf13 system.web\cf2 >\par ??\tab \tab <\cf13 httpHandlers\cf2 >\par ??\tab \tab \tab <\cf13 add\cf2 \cf6 verb\cf2 =\cf0 "\cf2 *\cf0 "\cf2 \cf6 path\cf2 =\cf0 "\cf2 *.asmx\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Web.Services.WebServiceHandlerFactory, Spring.Web\cf0 "\cf2 />\par ??\tab \tab \par ??\tab \tab <\cf13 httpModules\cf2 >\par ??\tab \tab \tab <\cf13 add\cf2 \cf6 name\cf2 =\cf0 "\cf2 Spring\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Context.Support.WebSupportModule, Spring.Web\cf0 "\cf2 />\par ??\tab \tab \par ?? <\cf13 compilation\cf2 \cf6 debug\cf2 =\cf0 "\cf2 true\cf0 "\cf2 />\par ?? <\cf13 customErrors\cf2 \cf6 mode\cf2 =\cf0 "\cf2 RemoteOnly\cf0 "\cf2 />\par ?? <\cf13 authentication\cf2 \cf6 mode\cf2 =\cf0 "\cf2 Windows\cf0 "\cf2 />\par ?? <\cf13 authorization\cf2 >\par ?? <\cf13 allow\cf2 \cf6 users\cf2 =\cf0 "\cf2 *\cf0 "\cf2 />\par ?? \par ?? <\cf13 trace\cf2 \cf6 enabled\cf2 =\cf0 "\cf2 false\cf0 "\cf2 \cf6 requestLimit\cf2 =\cf0 "\cf2 10\cf0 "\cf2 \cf6 pageOutput\cf2 =\cf0 "\cf2 true\cf0 "\cf2 \cf6 traceMode\cf2 =\cf0 "\cf2 SortByTime\cf0 "\cf2 \cf6 localOnly\cf2 =\cf0 "\cf2 true\cf0 "\cf2 />\par ?? <\cf13 sessionState\cf2 \cf6 mode\cf2 =\cf0 "\cf2 InProc\cf0 "\cf2 \cf6 stateConnectionString\cf2 =\cf0 "\cf2 tcpip=127.0.0.1:42424\cf0 "\cf2 \cf6 sqlConnectionString\cf2 =\cf0 "\cf2 data source=127.0.0.1;Trusted_Connection=yes\cf0 "\cf2 \cf6 cookieless\cf2 =\cf0 "\cf2 false\cf0 "\cf2 \cf6 timeout\cf2 =\cf0 "\cf2 20\cf0 "\cf2 />\par ?? <\cf13 globalization\cf2 \cf6 requestEncoding\cf2 =\cf0 "\cf2 utf-8\cf0 "\cf2 \cf6 responseEncoding\cf2 =\cf0 "\cf2 utf-8\cf0 "\cf2 />\par ?? \par ??\par ?? <\cf13 common\cf2 >\par ?? <\cf13 logging\cf2 >\par ?? <\cf13 factoryAdapter\cf2 \cf6 type\cf2 =\cf0 "\cf2 Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net\cf0 "\cf2 >\par ?? \par ?? \par ?? \par ?? <\cf13 arg\cf2 \cf6 key\cf2 =\cf0 "\cf2 configType\cf0 "\cf2 \cf6 value\cf2 =\cf0 "\cf2 INLINE\cf0 "\cf2 />\par ?? \par ?? \par ?? \par ??\par ?? <\cf13 log4net\cf2 >\par ??\tab \tab <\cf13 appender\cf2 \cf6 name\cf2 =\cf0 "\cf2 RollingFileAppender\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 log4net.Appender.RollingFileAppender\cf0 "\cf2 >\par ??\tab \tab \tab <\cf13 file\cf2 \cf6 value\cf2 =\cf0 "\cf2 Logs/log.txt\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 appendToFile\cf2 \cf6 value\cf2 =\cf0 "\cf2 true\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 rollingStyle\cf2 \cf6 value\cf2 =\cf0 "\cf2 Size\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 maxSizeRollBackups\cf2 \cf6 value\cf2 =\cf0 "\cf2 10\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 maximumFileSize\cf2 \cf6 value\cf2 =\cf0 "\cf2 100KB\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 staticLogFileName\cf2 \cf6 value\cf2 =\cf0 "\cf2 true\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 lockingModel\cf2 \cf6 type\cf2 =\cf0 "\cf2 log4net.Appender.RollingFileAppender+MinimalLock\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 layout\cf2 \cf6 type\cf2 =\cf0 "\cf2 log4net.Layout.PatternLayout\cf0 "\cf2 >\par ??\tab \tab \tab \tab <\cf13 conversionPattern\cf2 \cf6 value\cf2 =\cf0 "\cf2 %date [%-5level] %logger - %message%newline\cf0 "\cf2 />\par ??\tab \tab \tab \par ??\tab \tab \par ??\tab \tab \par ??\tab \tab <\cf13 root\cf2 >\par ??\tab \tab \tab <\cf13 level\cf2 \cf6 value\cf2 =\cf0 "\cf2 DEBUG\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 appender-ref\cf2 \cf6 ref\cf2 =\cf0 "\cf2 RollingFileAppender\cf0 "\cf2 />\par ??\tab \tab \par ??\tab \tab \par ??\tab \tab <\cf13 logger\cf2 \cf6 name\cf2 =\cf0 "\cf2 Spring.Aspects\cf0 "\cf2 >\par ??\tab \tab \tab <\cf13 level\cf2 \cf6 value\cf2 =\cf0 "\cf2 DEBUG\cf0 "\cf2 />\par ??\tab \tab \par ?? \par ?? <\cf13 logger\cf2 \cf6 name\cf2 =\cf0 "\cf2 Spring.Calculator\cf0 "\cf2 >\par ?? <\cf13 level\cf2 \cf6 value\cf2 =\cf0 "\cf2 DEBUG\cf0 "\cf2 />\par ?? \par ?? \par ?? <\cf13 logger\cf2 \cf6 name\cf2 =\cf0 "\cf2 Spring\cf0 "\cf2 >\par ?? <\cf13 level\cf2 \cf6 value\cf2 =\cf0 "\cf2 INFO\cf0 "\cf2 />\par ?? \par ??\tab \par ?? \par ??\par ??} -->

<?xml version="1.0"?>

<configuration>


  <configSections>

     <sectionGroup name="spring">

      <section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web"/>

      <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core"/>

    </sectionGroup>

    <sectionGroup name="common">

      <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />

    </sectionGroup>

    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>

  </configSections>


  <spring><!-- 이번 포스트에서 설명한다-->

     <context>

      <resource uri="config://spring/objects"/>

      <resource uri="~/Config/webServices.xml"/>

      <resource uri="~/Config/webServices-aop.xml"/>

    </context>


    <objects xmlns="http://www.springframework.net">

      <description>Definitions of objects to be exported.</description>


      <!-- Aspect -->


      <object id="CommonLoggingAroundAdvice" type="Spring.Aspects.Logging.CommonLoggingAroundAdvice, Spring.Aspects">

        <property name="Level" value="Debug"/>

      </object>


      <!-- Service -->


      <object id="calculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"/>


      <object id="calculatorWeaved" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">

        <property name="target" ref="calculator"/>

        <property name="interceptorNames">

          <list>

            <value>CommonLoggingAroundAdvice</value>

          </list>

        </property>

      </object>


    </objects>

   </spring>


  <system.web> <!-- 나중에 설명한다.-->

    <httpHandlers>

      <add verb="*" path="*.asmx" type="Spring.Web.Services.WebServiceHandlerFactory, Spring.Web"/>

    </httpHandlers>

    <httpModules>

      <add name="Spring" type="Spring.Context.Support.WebSupportModule, Spring.Web"/>

    </httpModules>

    <compilation debug="true"/>

    <customErrors mode="RemoteOnly"/>

    <authentication mode="Windows"/>

    <authorization>

      <allow users="*"/>

    </authorization>

    <trace enabled="false" requestLimit="10" pageOutput="true" traceMode="SortByTime" localOnly="true"/>

    <sessionState mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes" cookieless="false" timeout="20"/>

    <globalization requestEncoding="utf-8" responseEncoding="utf-8"/>

  </system.web>


  <common> <!-- 나중에 설명한다.-->

    <logging>

      <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net">

        <!-- choices are INLINE, FILE, FILE-WATCH, EXTERNAL -->

        <!-- otherwise BasicConfigurer.Configure is used -->

        <!-- log4net configuration file is specified with key configFile -->

        <arg key="configType" value="INLINE" />

      </factoryAdapter>

    </logging>

  </common>


  <log4net> <!-- 나중에 설명한다-->

    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">

      <file value="Logs/log.txt"/>

      <appendToFile value="true"/>

      <rollingStyle value="Size"/>

      <maxSizeRollBackups value="10"/>

      <maximumFileSize value="100KB"/>

      <staticLogFileName value="true"/>

      <lockingModel type="log4net.Appender.RollingFileAppender+MinimalLock"/>

      <layout type="log4net.Layout.PatternLayout">

        <conversionPattern value="%date [%-5level] %logger - %message%newline"/>

      </layout>

    </appender>

    <!-- Set default logging level -->

    <root>

      <level value="DEBUG"/>

      <appender-ref ref="RollingFileAppender"/>

    </root>

    <!-- Set logging for Spring.Aspects -->

    <logger name="Spring.Aspects">

      <level value="DEBUG"/>

    </logger>

    <!-- Set logging for Spring.Calculator -->

    <logger name="Spring.Calculator">

      <level value="DEBUG"/>

    </logger>

    <!-- Set logging for Spring -->

    <logger name="Spring">

      <level value="INFO"/>

    </logger>

  </log4net>


</configuration>

■ configuration과 Spring 컨테이너

configuration 구조는 .NET의 표준 구조를 그대로 이용하고 있다. web.config를 이용하고 있으니 당연한 이야기다. 대부분 Spring.NET용 설정만 포함되어 있지만, 기존에 알고 있는 web.config 설정 요소들도 포함될 수 있다.  system.web 섹션을 보면 httpHandler와 httpModule을 등록하는 ASP.NET 설정이 포함되어 있다. spring.net 관련 설정은, spring섹션을 보면 알겠지만 Spring만의 configuration 내용을 별도의 파일에 xml형태로 저장할 수도 있다.

이렇게 설정된 정보들은 Spring 컨테이너가 생성되면서 모두 컨테이너에 읽혀진다. 다음은 레퍼런스 문서에 나와있는 Spring 컨테이너를 설명하는 그림이다.

\par ?? \par ?? <\cf13 object\cf2 \cf6 id\cf2 =\cf0 "\cf2 CommonLoggingAroundAdvice\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Aspects.Logging.CommonLoggingAroundAdvice, Spring.Aspects\cf0 "\cf2 >\par ??\tab \tab \tab \tab <\cf13 property\cf2 \cf6 name\cf2 =\cf0 "\cf2 Level\cf0 "\cf2 \cf6 value\cf2 =\cf0 "\cf2 Debug\cf0 "\cf2 />\par ??\tab \tab \tab \par ?? \par ?? \par ??\tab \tab \tab \par ?? <\cf13 object\cf2 \cf6 id\cf2 =\cf0 "\cf2 calculator\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services\cf0 "\cf2 />\par ??\tab \tab \tab \par ?? <\cf13 object\cf2 \cf6 id\cf2 =\cf0 "\cf2 calculatorWeaved\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop\cf0 "\cf2 >\par ??\tab \tab \tab \tab <\cf13 property\cf2 \cf6 name\cf2 =\cf0 "\cf2 target\cf0 "\cf2 \cf6 ref\cf2 =\cf0 "\cf2 calculator\cf0 "\cf2 />\par ??\tab \tab \tab \tab <\cf13 property\cf2 \cf6 name\cf2 =\cf0 "\cf2 interceptorNames\cf0 "\cf2 >\par ??\tab \tab \tab \tab \tab <\cf13 list\cf2 >\par ??\tab \tab \tab \tab \tab \tab <\cf13 value\cf2 >\cf0 CommonLoggingAroundAdvice\cf2 \par ??\tab \tab \tab \tab \tab \par ??\tab \tab \tab \tab \par ??\tab \tab \tab \par ??\tab \tab \par ?? \par ??\tab \par ?? \par ??\tab \par ?? <\cf13 system.web\cf2 >\par ??\tab \tab <\cf13 httpHandlers\cf2 >\par ??\tab \tab \tab <\cf13 add\cf2 \cf6 verb\cf2 =\cf0 "\cf2 *\cf0 "\cf2 \cf6 path\cf2 =\cf0 "\cf2 *.asmx\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Web.Services.WebServiceHandlerFactory, Spring.Web\cf0 "\cf2 />\par ??\tab \tab \par ??\tab \tab <\cf13 httpModules\cf2 >\par ??\tab \tab \tab <\cf13 add\cf2 \cf6 name\cf2 =\cf0 "\cf2 Spring\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Context.Support.WebSupportModule, Spring.Web\cf0 "\cf2 />\par ??\tab \tab \par ?? <\cf13 compilation\cf2 \cf6 debug\cf2 =\cf0 "\cf2 true\cf0 "\cf2 />\par ?? <\cf13 customErrors\cf2 \cf6 mode\cf2 =\cf0 "\cf2 RemoteOnly\cf0 "\cf2 />\par ?? <\cf13 authentication\cf2 \cf6 mode\cf2 =\cf0 "\cf2 Windows\cf0 "\cf2 />\par ?? <\cf13 authorization\cf2 >\par ?? <\cf13 allow\cf2 \cf6 users\cf2 =\cf0 "\cf2 *\cf0 "\cf2 />\par ?? \par ?? <\cf13 trace\cf2 \cf6 enabled\cf2 =\cf0 "\cf2 false\cf0 "\cf2 \cf6 requestLimit\cf2 =\cf0 "\cf2 10\cf0 "\cf2 \cf6 pageOutput\cf2 =\cf0 "\cf2 true\cf0 "\cf2 \cf6 traceMode\cf2 =\cf0 "\cf2 SortByTime\cf0 "\cf2 \cf6 localOnly\cf2 =\cf0 "\cf2 true\cf0 "\cf2 />\par ?? <\cf13 sessionState\cf2 \cf6 mode\cf2 =\cf0 "\cf2 InProc\cf0 "\cf2 \cf6 stateConnectionString\cf2 =\cf0 "\cf2 tcpip=127.0.0.1:42424\cf0 "\cf2 \cf6 sqlConnectionString\cf2 =\cf0 "\cf2 data source=127.0.0.1;Trusted_Connection=yes\cf0 "\cf2 \cf6 cookieless\cf2 =\cf0 "\cf2 false\cf0 "\cf2 \cf6 timeout\cf2 =\cf0 "\cf2 20\cf0 "\cf2 />\par ?? <\cf13 globalization\cf2 \cf6 requestEncoding\cf2 =\cf0 "\cf2 utf-8\cf0 "\cf2 \cf6 responseEncoding\cf2 =\cf0 "\cf2 utf-8\cf0 "\cf2 />\par ?? \par ??\par ?? <\cf13 common\cf2 >\par ?? <\cf13 logging\cf2 >\par ?? <\cf13 factoryAdapter\cf2 \cf6 type\cf2 =\cf0 "\cf2 Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net\cf0 "\cf2 >\par ?? \par ?? \par ?? \par ?? <\cf13 arg\cf2 \cf6 key\cf2 =\cf0 "\cf2 configType\cf0 "\cf2 \cf6 value\cf2 =\cf0 "\cf2 INLINE\cf0 "\cf2 />\par ?? \par ?? \par ?? \par ??\par ?? <\cf13 log4net\cf2 >\par ??\tab \tab <\cf13 appender\cf2 \cf6 name\cf2 =\cf0 "\cf2 RollingFileAppender\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 log4net.Appender.RollingFileAppender\cf0 "\cf2 >\par ??\tab \tab \tab <\cf13 file\cf2 \cf6 value\cf2 =\cf0 "\cf2 Logs/log.txt\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 appendToFile\cf2 \cf6 value\cf2 =\cf0 "\cf2 true\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 rollingStyle\cf2 \cf6 value\cf2 =\cf0 "\cf2 Size\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 maxSizeRollBackups\cf2 \cf6 value\cf2 =\cf0 "\cf2 10\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 maximumFileSize\cf2 \cf6 value\cf2 =\cf0 "\cf2 100KB\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 staticLogFileName\cf2 \cf6 value\cf2 =\cf0 "\cf2 true\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 lockingModel\cf2 \cf6 type\cf2 =\cf0 "\cf2 log4net.Appender.RollingFileAppender+MinimalLock\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 layout\cf2 \cf6 type\cf2 =\cf0 "\cf2 log4net.Layout.PatternLayout\cf0 "\cf2 >\par ??\tab \tab \tab \tab <\cf13 conversionPattern\cf2 \cf6 value\cf2 =\cf0 "\cf2 %date [%-5level] %logger - %message%newline\cf0 "\cf2 />\par ??\tab \tab \tab \par ??\tab \tab \par ??\tab \tab \par ??\tab \tab <\cf13 root\cf2 >\par ??\tab \tab \tab <\cf13 level\cf2 \cf6 value\cf2 =\cf0 "\cf2 DEBUG\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 appender-ref\cf2 \cf6 ref\cf2 =\cf0 "\cf2 RollingFileAppender\cf0 "\cf2 />\par ??\tab \tab \par ??\tab \tab \par ??\tab \tab <\cf13 logger\cf2 \cf6 name\cf2 =\cf0 "\cf2 Spring.Aspects\cf0 "\cf2 >\par ??\tab \tab \tab <\cf13 level\cf2 \cf6 value\cf2 =\cf0 "\cf2 DEBUG\cf0 "\cf2 />\par ??\tab \tab \par ?? \par ?? <\cf13 logger\cf2 \cf6 name\cf2 =\cf0 "\cf2 Spring.Calculator\cf0 "\cf2 >\par ?? <\cf13 level\cf2 \cf6 value\cf2 =\cf0 "\cf2 DEBUG\cf0 "\cf2 />\par ?? \par ?? \par ?? <\cf13 logger\cf2 \cf6 name\cf2 =\cf0 "\cf2 Spring\cf0 "\cf2 >\par ?? <\cf13 level\cf2 \cf6 value\cf2 =\cf0 "\cf2 INFO\cf0 "\cf2 />\par ?? \par ??\tab \par ?? \par ??\par ??} -->
먼저 spring 섹션 중심으로 설명을 할 것이다. 이 섹션이 Spring 컨테이너를 이해하는 기본 설정을 포함하고 있기 때문이다. system.web, common/logging, log4net 섹션은 나중에 설명한다. 미리 간단하게나만 설명하면 system.web 섹션에 등록되어 있는 httpHandlers때문에 개발자는 asmx 파일을 만들지 않고도 웹 서비스를 노출시킬 수 있게 된다. 그리고 common/logging, log4net은 실제로 로깅을 구현하는 모듈과 로깅 정책을 등록하는 곳이다.

애플리케이션이 시작되면 Spring 컨테이너는 configuration 설정( 문서에서는 "configuration 메타데이터" 라고 하고 있다 )을 읽여들이는데, configuration 설정은 Spring 컨테이너에게 객체를 어떻게 생성하고(예를 들어, singleton으로 생성할지 prototype(일반 객체)으로 생성할지), 객체 생성에 필요한 정보 등을 알려주는 역할을 한다. Spring 컨테이너는 이런 설정 정보를 이용해서 애플리케이션에서 제공하고 있는 클래스들을 이용해서 필요하면 즉시 객체를 생성하는등 시스템이 가동될 준비를 마친다.

■ 컨테이너 생성에 필요한 설정들 - 리소스

실제로 Spring 컨테이너 객체를 생성할때는 첫번째로 필요한 것이 컨테이너를 설정할 리소스들에 대한 정보이다. 이런 리소스들이 대부분 객체들에 대한 정의가 될 것이다. 리소스들이 포함되어 있는 경로에 대한 정보는 <context/resource/>요소로 표현되는데, 이것을 파싱히는 녀석은 <configSections/>에 등록되어 있는 context 섹션 핸들러 WebContextHandler이다.

<configSections>

  <sectionGroup name="spring">

    <section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web"/>

  </sectionGroup>

</configSections>


<spring>

  <context>

    <resource uri="config://spring/objects"/>

    <resource uri="~/Config/webServices.xml"/>

    <resource uri="~/Config/webServices-aop.xml"/>

  </context>

</spring>

WebContextHandler가 Spring 컨테이너를 생성할때 필요한 객체들에 대한 정보는 <context/resource/>요소들을 통해서 얻는다. 이 예제에서는 Spring 컨테이너에 로딩될 객체들에 대한 정보를 <context/resource/>요소로 읽어들이고 있고 이것이 이 요소의 가장 일반적인 용도이다.  그렇지만 다른 리소스도 이 요소를 통해서 로딩할 수 있다.

<context/resource/>요소는 현재 컨테이너 컨텍스트( 애플리케이션 컨텍스트가 아니다. 애플리케이션과 컨테이너는 의미가 다르다. 뒤에 설명할 기회가 있을것이다. 있을가? )을 구성하는 리소스들에 대한 경로를 가지고 있는데, 리소스에 따라서 그것에 접근할 수 있는 다양한 경로 포맷을 갖는다. 리소스는 파일일 수도 있고, 어셈블리내에 포함된 리소스일 수도 있다. 현재 지원되고 있는 리소스의 종류 및 접근 포맷은 다음과 같다.

리소스 접근 포맷 접근 포맷 파싱 모듈
어셈블리에 포함된 데이터 assembly://<AssemblyName>/<NameSpace>/<ResourceName> AssemblyResource
.NET configuration 파일( web.config등)에 포함되어 있는 있는
커스텀 configuration 섹션에 저장된 데이터
config://<path to section> ConfigSectionResource
파일 시스템의 파일 file://<filename> FileSystemResource
Http, Https 프로토콜로 접근할 수 있는 데이터 표준적인 http, https 표현 UriResource

표에서 리소스컬럼은 어떤 리소스인지를 설명하고 있고 접근 포맷은 그 리소스에 접근하기 위해서 사용하고 있는 Uri 포맷을 나타낸다. 그리고 참조고 마지막 컬럼에 접근 포맷을 해석해서 해당 리소스에 접근해서 읽어오는 모듈명을 표시했다. 앞의 예제 web.config에서는 configuration 섹션의 리소스와 http 리소스를 이용하겠다고 설정하고 있다( 근데 "~"로 시작하는 리소스 접근 포맷이 파일 접근 포맷인지, http 접근 포맷인지 확신은 없다. 다만 ASP.NET에서 사용하는 "~"가 나타내는 것이 웹 경로인 것을 보면 http 리소스 일것으로 추측된다 ).

예제에서는 <context/resource/>에서 표시하는 리소스 경로의 내용을 읽어들여보면 모두 <objects/> 요소를 가지고 있다. 리소스 핸들러는 xml 파일이나 <objects> 섹션에 포함된 리리소스들이 모두 객체들에 대한  정의라는 것을 알게 된다. 핸들러는 <spring/objects/> 섹션에 설정되어 있는 <object/>들뿐만 아니라 두개의 xml 파일에 정의되어 있는 <object/>요소들을 읽어들인다. 필자도 이곳에 정의되어 있는 객체들에 대해서 아직은 잘 모른다. 이때 <objects/>를 파싱하기 위해서 호출되는 핸들러가 바로 <configSections/>에 등록된 DefaultSectionHandler이다.

\par ?? \par ?? <\cf13 object\cf2 \cf6 id\cf2 =\cf0 "\cf2 CommonLoggingAroundAdvice\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Aspects.Logging.CommonLoggingAroundAdvice, Spring.Aspects\cf0 "\cf2 >\par ??\tab \tab \tab \tab <\cf13 property\cf2 \cf6 name\cf2 =\cf0 "\cf2 Level\cf0 "\cf2 \cf6 value\cf2 =\cf0 "\cf2 Debug\cf0 "\cf2 />\par ??\tab \tab \tab \par ?? \par ?? \par ??\tab \tab \tab \par ?? <\cf13 object\cf2 \cf6 id\cf2 =\cf0 "\cf2 calculator\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services\cf0 "\cf2 />\par ??\tab \tab \tab \par ?? <\cf13 object\cf2 \cf6 id\cf2 =\cf0 "\cf2 calculatorWeaved\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop\cf0 "\cf2 >\par ??\tab \tab \tab \tab <\cf13 property\cf2 \cf6 name\cf2 =\cf0 "\cf2 target\cf0 "\cf2 \cf6 ref\cf2 =\cf0 "\cf2 calculator\cf0 "\cf2 />\par ??\tab \tab \tab \tab <\cf13 property\cf2 \cf6 name\cf2 =\cf0 "\cf2 interceptorNames\cf0 "\cf2 >\par ??\tab \tab \tab \tab \tab <\cf13 list\cf2 >\par ??\tab \tab \tab \tab \tab \tab <\cf13 value\cf2 >\cf0 CommonLoggingAroundAdvice\cf2 \par ??\tab \tab \tab \tab \tab \par ??\tab \tab \tab \tab \par ??\tab \tab \tab \par ??\tab \tab \par ?? \par ??\tab \par ?? } -->

  <configSections>

    <sectionGroup name="spring">

      <section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web"/>

      <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core"/>

    </sectionGroup>

  </configSections>


  <spring>

     <context>

      <resource uri="config://spring/objects"/>

    </context>

     <objects xmlns="http://www.springframework.net">

     ...

    </objects>


  </spring>

두 섹션 <spring/context/>와 <spring/objects/>이 바로 Spring 컨테이너를 정의하는 섹션이다. 두 섹션이 바로 new를 통한 컨테이너 객체 생성 코드에 해당한다는 것이다( 실제로 프로그램적으로도 컨테이너 객체를 생성할 수있는 API가 있다). 예제에서처럼 컨테이너를 설정하는 내용이 별도의 xml 파일로도 존재할 수 있는데, 그런 경우에는 컨테이너를 생성할때 해당 파일의 모든 내용들을 읽어들인다.

■ 객체 정의 <object/>요소

Spring configuration은 최소한 하나의 객체 정의를 가지고 있어야 한다. 그러다 대부분 하나 이상의 객체를 정의하는 요소 <object/>가 <objects/>에 포함된다. 이렇게 <object/>요소에 객체에 대한 정보( 타입과 어셈블리등)를 제공하는 것을 "Spring 컨테이너에 객체를 등록한다"고 표현하고 있다. 이 객체 정의 요소는 애플리케이션이 시작되면 실제 객체에 해당된다. 즉 new를 사용해서 생성한 실제 객체에 해당한다. 그러나 이렇게 configuration에 등록하면 Spring 컨테이너가 대신 자동으로 생성해준다.

\par ?? \par ?? <\cf13 object\cf2 \cf6 id\cf2 =\cf0 "\cf2 ...\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 ...\cf0 "\cf2 >\par ?? \par ?? \par ?? \par ??\par ??\par ??} -->

<objects xmlns ="http://www.springframework.net">

  <object id="..." type="...">

    <!-- 이 객체가 의존하고 있는 다른 객체 그리고 필요한 설정이 있다면 이곳에 표현한다-->

  </object>

  <object id="..." type="...">

    <!-- 이 객체가 의존하고 있는 다른 객체 그리고 필요한 설정이 있다면 이곳에 표현한다-->

  </object>

  <!-- 더 많은 객체 정의가 가능하다.-->


</objects>

      
\par ?? \par ?? <\cf13 object\cf2 \cf6 id\cf2 =\cf0 "\cf2 CommonLoggingAroundAdvice\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Aspects.Logging.CommonLoggingAroundAdvice, Spring.Aspects\cf0 "\cf2 >\par ??\tab \tab \tab \tab <\cf13 property\cf2 \cf6 name\cf2 =\cf0 "\cf2 Level\cf0 "\cf2 \cf6 value\cf2 =\cf0 "\cf2 Debug\cf0 "\cf2 />\par ??\tab \tab \tab \par ?? \par ?? \par ??\tab \tab \tab \par ?? <\cf13 object\cf2 \cf6 id\cf2 =\cf0 "\cf2 calculator\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services\cf0 "\cf2 />\par ??\tab \tab \tab \par ?? <\cf13 object\cf2 \cf6 id\cf2 =\cf0 "\cf2 calculatorWeaved\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop\cf0 "\cf2 >\par ??\tab \tab \tab \tab <\cf13 property\cf2 \cf6 name\cf2 =\cf0 "\cf2 target\cf0 "\cf2 \cf6 ref\cf2 =\cf0 "\cf2 calculator\cf0 "\cf2 />\par ??\tab \tab \tab \tab <\cf13 property\cf2 \cf6 name\cf2 =\cf0 "\cf2 interceptorNames\cf0 "\cf2 >\par ??\tab \tab \tab \tab \tab <\cf13 list\cf2 >\par ??\tab \tab \tab \tab \tab \tab <\cf13 value\cf2 >\cf0 CommonLoggingAroundAdvice\cf2 \par ??\tab \tab \tab \tab \tab \par ??\tab \tab \tab \tab \par ??\tab \tab \tab \par ??\tab \tab \par ?? \par ??\tab \par ?? \par ??\tab \par ?? <\cf13 system.web\cf2 >\par ??\tab \tab <\cf13 httpHandlers\cf2 >\par ??\tab \tab \tab <\cf13 add\cf2 \cf6 verb\cf2 =\cf0 "\cf2 *\cf0 "\cf2 \cf6 path\cf2 =\cf0 "\cf2 *.asmx\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Web.Services.WebServiceHandlerFactory, Spring.Web\cf0 "\cf2 />\par ??\tab \tab \par ??\tab \tab <\cf13 httpModules\cf2 >\par ??\tab \tab \tab <\cf13 add\cf2 \cf6 name\cf2 =\cf0 "\cf2 Spring\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 Spring.Context.Support.WebSupportModule, Spring.Web\cf0 "\cf2 />\par ??\tab \tab \par ?? <\cf13 compilation\cf2 \cf6 debug\cf2 =\cf0 "\cf2 true\cf0 "\cf2 />\par ?? <\cf13 customErrors\cf2 \cf6 mode\cf2 =\cf0 "\cf2 RemoteOnly\cf0 "\cf2 />\par ?? <\cf13 authentication\cf2 \cf6 mode\cf2 =\cf0 "\cf2 Windows\cf0 "\cf2 />\par ?? <\cf13 authorization\cf2 >\par ?? <\cf13 allow\cf2 \cf6 users\cf2 =\cf0 "\cf2 *\cf0 "\cf2 />\par ?? \par ?? <\cf13 trace\cf2 \cf6 enabled\cf2 =\cf0 "\cf2 false\cf0 "\cf2 \cf6 requestLimit\cf2 =\cf0 "\cf2 10\cf0 "\cf2 \cf6 pageOutput\cf2 =\cf0 "\cf2 true\cf0 "\cf2 \cf6 traceMode\cf2 =\cf0 "\cf2 SortByTime\cf0 "\cf2 \cf6 localOnly\cf2 =\cf0 "\cf2 true\cf0 "\cf2 />\par ?? <\cf13 sessionState\cf2 \cf6 mode\cf2 =\cf0 "\cf2 InProc\cf0 "\cf2 \cf6 stateConnectionString\cf2 =\cf0 "\cf2 tcpip=127.0.0.1:42424\cf0 "\cf2 \cf6 sqlConnectionString\cf2 =\cf0 "\cf2 data source=127.0.0.1;Trusted_Connection=yes\cf0 "\cf2 \cf6 cookieless\cf2 =\cf0 "\cf2 false\cf0 "\cf2 \cf6 timeout\cf2 =\cf0 "\cf2 20\cf0 "\cf2 />\par ?? <\cf13 globalization\cf2 \cf6 requestEncoding\cf2 =\cf0 "\cf2 utf-8\cf0 "\cf2 \cf6 responseEncoding\cf2 =\cf0 "\cf2 utf-8\cf0 "\cf2 />\par ?? \par ??\par ?? <\cf13 common\cf2 >\par ?? <\cf13 logging\cf2 >\par ?? <\cf13 factoryAdapter\cf2 \cf6 type\cf2 =\cf0 "\cf2 Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net\cf0 "\cf2 >\par ?? \par ?? \par ?? \par ?? <\cf13 arg\cf2 \cf6 key\cf2 =\cf0 "\cf2 configType\cf0 "\cf2 \cf6 value\cf2 =\cf0 "\cf2 INLINE\cf0 "\cf2 />\par ?? \par ?? \par ?? \par ??\par ?? <\cf13 log4net\cf2 >\par ??\tab \tab <\cf13 appender\cf2 \cf6 name\cf2 =\cf0 "\cf2 RollingFileAppender\cf0 "\cf2 \cf6 type\cf2 =\cf0 "\cf2 log4net.Appender.RollingFileAppender\cf0 "\cf2 >\par ??\tab \tab \tab <\cf13 file\cf2 \cf6 value\cf2 =\cf0 "\cf2 Logs/log.txt\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 appendToFile\cf2 \cf6 value\cf2 =\cf0 "\cf2 true\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 rollingStyle\cf2 \cf6 value\cf2 =\cf0 "\cf2 Size\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 maxSizeRollBackups\cf2 \cf6 value\cf2 =\cf0 "\cf2 10\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 maximumFileSize\cf2 \cf6 value\cf2 =\cf0 "\cf2 100KB\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 staticLogFileName\cf2 \cf6 value\cf2 =\cf0 "\cf2 true\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 lockingModel\cf2 \cf6 type\cf2 =\cf0 "\cf2 log4net.Appender.RollingFileAppender+MinimalLock\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 layout\cf2 \cf6 type\cf2 =\cf0 "\cf2 log4net.Layout.PatternLayout\cf0 "\cf2 >\par ??\tab \tab \tab \tab <\cf13 conversionPattern\cf2 \cf6 value\cf2 =\cf0 "\cf2 %date [%-5level] %logger - %message%newline\cf0 "\cf2 />\par ??\tab \tab \tab \par ??\tab \tab \par ??\tab \tab \par ??\tab \tab <\cf13 root\cf2 >\par ??\tab \tab \tab <\cf13 level\cf2 \cf6 value\cf2 =\cf0 "\cf2 DEBUG\cf0 "\cf2 />\par ??\tab \tab \tab <\cf13 appender-ref\cf2 \cf6 ref\cf2 =\cf0 "\cf2 RollingFileAppender\cf0 "\cf2 />\par ??\tab \tab \par ??\tab \tab \par ??\tab \tab <\cf13 logger\cf2 \cf6 name\cf2 =\cf0 "\cf2 Spring.Aspects\cf0 "\cf2 >\par ??\tab \tab \tab <\cf13 level\cf2 \cf6 value\cf2 =\cf0 "\cf2 DEBUG\cf0 "\cf2 />\par ??\tab \tab \par ?? \par ?? <\cf13 logger\cf2 \cf6 name\cf2 =\cf0 "\cf2 Spring.Calculator\cf0 "\cf2 >\par ?? <\cf13 level\cf2 \cf6 value\cf2 =\cf0 "\cf2 DEBUG\cf0 "\cf2 />\par ?? \par ?? \par ?? <\cf13 logger\cf2 \cf6 name\cf2 =\cf0 "\cf2 Spring\cf0 "\cf2 >\par ?? <\cf13 level\cf2 \cf6 value\cf2 =\cf0 "\cf2 INFO\cf0 "\cf2 />\par ?? \par ??\tab \par ?? \par ??\par ??} -->
애플리케이션별로 예를 들어 웹 애플리케이션에서는 이곳에 어떤 객체들을 등록시키수 있을까 하는 문제는 나중에 좀 고민해서 실전 애플리케이션 개발 전략을 다루는 포스트를 별도로 제작해 볼 계획이다. 미리 예상해보면 비즈니스 레어어 또는 데이터 액세스 레이어의 객체들이 이곳에 등록될 수 있지 않을까 하는 추측을 해 볼 수 있겠다. 지금은 Spring.NET 프레임워크의 개념 파악에 집중하도록 한다.

객체를 생성하는데 필요한 정보들이 있다. 어떤 정보들이 필요할까.

* 타입 이름 : 컨테이너에 생성될 객체가 정의되어 있는 실제 클래스( concrete class)

* 객체가 어떻게 거동할 것인가에 대한 설정 즉 singleton이냐 아니면 prototype(singleton이 아닌 객체를 말한다)이냐. 생명주기 콜백함수( 객체가 초기화되거나 해제될때 호출될 함수)가 있다면 어떤 함수인가.

* 객체가 자신의 작업을 하기 위해서 의존하고 있는 다른 객체들이 있다면 그 의존 객체들( dependencies 또는 collaborators로 표현한다)에 대한 정보 설정

* 또 있는데 무슨 말인지 잘 모르겠다-_-;;

이런 정보들을 표현하기 위해서 <object/>의 어트리뷰트 또는 인라인 <object/> ( <object/>하위에 포함된 다른 <object/>요소)및 여러 요소들을 이용하고 있다.

특징 객체 정보
type 객체를 정의하고 있는 클래스 및 클래스를 포함하고 있는 어셈블리명
id/name 등록되는 객체들은 고유한 아이디를 가지고 있다. 고유한 객체를 나타내기 위해서 <object/>요소의 "id" 또는 "name" 어트리뷰트를 사용한다.
singleton 객체를 singleton으로 생성할지에 대한 여부를 알리는 어트리뷰트. 기본값은 true로서 아무 표시가 없으면 기본적으로 singleton으로 생성된다. 즉 컨테이너별로 객체가 하나 생성된다. singleton으로 표시된 객체는 컨테이너가 생성되면서 객체들도 생성된다. singleton="false"로 되어 prototype으로 설정된 객체들은 실제로 코드상에서 객체가 요청될때 생성된다.
<object/>하위요소  
<constructor-arg/>하위 요소  
<property />하위 요소  

뒤의 3개의 하위 요소들은 DI( dependencies injection)과 관련된 설정들이다. 뒤에서 별도로 공간을 마련해서 설명하도록 하겠다( ^^). 퇴근하자. 아자. 졸려!

다 써 놓고 보니 포스트 구조가 좀 이상하다. 샘플을 제일 먼저 보여주고서는 Spring 컨테이너 얘기만 하고 끝나다니. 야튼 이 샘플은 계속 가지고 가겠다.