Whiteship's Note


스프링 + OSGi(스프링 DM) 개발 필독 레퍼런스 3종 세트

Spring DM/etc : 2008.12.08 14:13


스프링 DM 레퍼런스: http://static.springframework.org/osgi/docs/current/reference/html/
스프링 DM 서버 사용자 가이드: http://static.springsource.com/projects/dm-server/1.0.x/user-guide/html/index.html
스프링 DM 서버 개발자 가이드: http://static.springsource.com/projects/dm-server/1.0.x/programmer-guide/html/index.html

맨 위에껀 제가 번역/편역 해서 올린적이 있는데 지금은 또 많이 바껴서 다시 봐야겠고, 아래 두 문서도 분량이 얼마 되지 않으니 금방 읽어 보실 수 있습니다. 나머지 두 문서도 한글화를 할까 생각해봤는데 그럴 여유가 없더군요. 나중에 시간이 되면 블로그에 간단 요약 정도는 가능할지도 모르겠습니다.

읽는 순서는 일단 DM 레퍼런스를 보시는게 좋겠구요. 그 다음은 별로 순서가 필요없을 것 같습니다. 서버 사용법이 궁금하면 사용자 가이드를 보고, 개발할 때 dm 서버가 어떤 도움을 주는지 궁금하시다면 개발자 가이드를 보시면 됩니다. 개발자는 당연히 두 개 다 봐야겠죠? ㅋ

스프링을 사용하여 OSGi 개발이 상당히 편리해지고 있지만, 역시 핵심은 모듈화를 어떻게 할 것인가 인데.. 이건 삽질을 좀 해봐야겠습니다.

어찌됐든, dm 서버로 인해서 한층 OSGi 개발이 편리해진 것 같습니다. 손수 타겟 플랫폼 만들지 않아도 되고, 로깅 걱정 안 해도 되고, 에러 분석도 해주고, 배포 방법 다양하고, PAR 패키징 지원해서 여러 번들을 애플리케이션 별로 구분 할 수도 있고, 이클립스에서 편하게 사용할 수도 있으니 말이죠.

전 이제 자야겠습니다. 한국은 오후 2시 일텐데;;
신고
top


오호.. 스프링소스 manifest 헤더가 OSGi에 추가되는군요

Spring DM/etc : 2008.11.27 21:57


참조: http://blog.springsource.com/2008/11/27/springsource-manifest-headers-registered-with-osgi/

OSGi 진영에서 public registry에 밴더별 헤더를 등록해서 중복하는 헤더를 방지하고자 하는 것 같습니다.

추가된 스프링소스의 헤더 7개
- Import-Bundle
- Import-Library
- Module-Scope
- Modeul-Type
- Web-Contextpath
- Web-DispatcherServletUrlPatterns
- Web-FilterMappings

추가된 bnd 헤더 2개
- Include-Resource
- Private-Package

오호~~ 귿~~ 다시 한 번 스프링 DM 공부를 하고 가야겠습니다. S1A에 가서 스프링 DM과 DM 서버 관련 세션을 집중적으로 듣고 올 계획입니다. 이틀 남았네 빡쎄게 공부해야겠군..
신고
top


스프링 DM 프로젝트 빌드하기

Spring DM/exercise : 2008.10.16 14:59


메이븐 기반 프로젝트기 때문에, 간단하게 mvn package로 빌드 할 수 있을 거라고 생각했는데;;; 땡.. 틀렸습니다. mvn packae로 빌드하면 다음과 같은 에러를 볼 수 있습니다.

[ERROR]

Mojo:

    org.apache.maven.plugins:maven-compiler-plugin:2.0.2:compile

FAILED for project:

    org.springframework.osgi:spring-osgi-mock:bundle:1.2.0-m1

Reason:

C:\java\spring-osgi-1.2.0-m1\src\mock\src\main\java\org\springframework\osgi\mock\MockServiceReference.java:[23,25] package org.osgi.framework does not exist

OSGi 플랫폼이 없어서 발생하는 에러로, 스프링 DM 프로젝트를 빌드 할 때 프로파일을 선택해줘야 한다는 군요. 그래서 스프링 DM 프로젝트에 있는 프로파일을 살펴봤습니다.

사용자 삽입 이미지

여러가지가 있었습니다. 맨 위에 세 개는 OSGi 플랫폼이고, jdk 버전을 1.5 이상용도로 빌드해서 애노테이션 지원 기능을 사용할 수 있게 빌드 할 수 있나보네요. it은 통합 테스트(이 옵션을 안 주면 단위테스트만 합니다.)

mvn -Pequinox

통합 테스트까지 하면서 빌드 하려면

mvn -Pequinox,it

굳이 빌드를 안 해도 dist 폴더에 들어있긴 하지만... 오픈 소스쓰는 기본 자세라는 사부님 말씀. 캬~ 덕분에 오늘도 한 수 배웠습니다.

메이븐 프로파일은 안 써봤는데, 저걸 사용해서 빌드 하면 여러 환경에 따른 빌드 커스터마이징이 가능하군요. 특히 저 통합테스트가 눈에 띄는데 빌드 시간을 엄청 오래 잡아먹는 통합 테스트들은 주기 적으로만 실행하고 한 번의 커밋당 실행하는 빌드는 단위테스트만 실행하게 할 수도 있겠습니다.. 흠.. 프로파일 좋구나.


신고
top


스프링 DM 1.2.0 M1 배포

Spring DM/etc : 2008.09.05 20:43


참조 : http://www.springframework.org/node/754

눈에 띄는 변경 사항은 딱 하나

"스프링 MVC 예제, 그것도 애노테이션 기반의 예제를 추가했다."
신고
top


Spring DM Extentions

Spring DM/Appendix B : 2008.07.07 23:32


이번 Appendix 장에서는 1.0 배포판부터 추가된 핵심 기능을 확장한 기능들을 다루지만, 이 다음 배포판에서도 그대로 확장으로 있을지는 보장하지 못한다. 이 기능들을 핵심 기능 쪽으로 옮기는 것을 생각하고 있기 때문이다.

B.1. 애노테이션 기반 주입

org.springframework.osgi.extensions.annotation 번들은 OSGi 서비스 레퍼런스를 주입하는 애노테이션을 제공한다. 이 기능을 사용하려면 JDK 1.5 이상을 사용해야 한다.

Bean 클래스 세터 메소드 위에 org.springframework.osgi.extensions.annotation.ServiceReference 애노테이션을 사용할 수 있다. 기본으로 속성 타입으로 OSGi 서비스 레지스트리에서 매치하는 서비스 인터페이스를 찾아서 주입해준다. 예를 들어,

<bean id="annotationDriven" class="MyAnnotationDrivenBeanClass"/>

위의 클래스를 다음과 같이 정의한다면,

public class MyAnnotationDrivenBeanClass {

  @ServiceReference
  public void setMessageService(MessageService aService) { ... }

}

MessageService 인터페이스를 구현한 서비스를 찾아서 가장 적합한 레퍼런스를 주입해준다.(이 때 적합한 레퍼런스를 찾는 방법은 reference 엘리먼트와 동일함)

서비스 룩업을 하는 과정에 몇 가지 설정을 할 수 있게 reference 엘리먼트에 상응하는 속성을 가지고 있다. 자세한건 javadoc을 참조하라.


신고

'Spring DM > Appendix B' 카테고리의 다른 글

Spring DM Extentions  (0) 2008.07.07
top


A.1. Configuration Admin

Spring DM/Appendix A : 2008.07.07 23:20


A.1.1. Property placeholder support

스프링 DM은 빈 속성 값을 OSGi Configuration Administration 서비스에서 가져오는 기능을 지원한다. 이 기능은 property-placeholder 엘리먼트를 이용하여 사용할 수 있다.  property placeholder 엘리먼트는 "${...}" 이런 형태의 구분자를 사용한 부분의 빈 속성 값을 Configuration Administratino 서비스에서 가져와서 설정해준다. 이 때 persistent-id 속성으로 Configuration dictionary의 키에 해당하는 id를 설정해준다.

나중에 이 부분은 스프링 프레임워크에 있는 방법과 동일하게 변결 될 거라고 합니다.

<osgix:property-placeholder persistent-id="com.xyz.myapp"/>

<bean id="someBean" class="AClass">
  <property name="timeout" value="${timeout}"/>
</bean>

someBean의 timeout 속성 com.xyz.myapp 라는 persistent id로 등록된 Configuration Ditionary 안에 있는 timeout의 값으로 대치 한다.

placeholder 문자열은 빈을 생성할 시점에 대치가 된다. 프로퍼티 값을 변경했다고 해서 생성한 빈 속성을 다시 주입하지는 않는다. 이런 방법이 필요하면 Appendix B의 managed-service와 managed-service-reference를 참조하라. placeholder-prefix와 placeholder-suffix를 사용하여 구분자를 변경할 수 있다.

프로퍼티 값들을 Configuration Dictionary에 두지 않고 직접 생성해서 사용해도 된다. default-propertiies라는 내부 엘리먼트를 사용한다.

<osgix:property-placeholder persistent-id="com.xyz.myapp">
  <default-properties>
     <property name="productCategory" value="E792"/>
     <property name="businessUnit" value="811"/>
  </default-properties>
</osgix:property-placeholder>

이때 persistent-id 속성은 OSGi ManagerdService를 참조해야 한다. ManagedServiceFactory를 참조하면 에러난다.

A.1.2.  Configuration Dictionaries

설정 객체 및 그와 연관된 딕셔너리에 접근하는 방법을 제공하며, 설정 객체에서 직접 빈 객체를 생성하는 것이 스프링 DM 로드맵으로 잡혀있다. Appendix F. Roadmap을 참조하라.
신고

'Spring DM > Appendix A' 카테고리의 다른 글

A.1. Configuration Admin  (0) 2008.07.07
Compendium Services  (0) 2008.07.07
top


Compendium Services

Spring DM/Appendix A : 2008.07.07 23:04


OSGi Service Platform Service Compendium 스펙에는 OSGi 구현체가 지원할 수도 있는(may be supported) 부가 서비스를 정의하고 있다. 스프링 DM은 추가로 "compendium" 네임스페이스를 지원하여 그런 서비스를 사용할 수 있게 해준다. 보통 해당 네임스페이스 이름으로 osgix를 사용한다.

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/osgi"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
   xmlns:beans="http://www.springframework.org/schema/beans"
   xsi:schemaLocation="http://www.springframework.org/schema/osgi 
        http://www.springframework.org/schema/osgi/spring-osgi.xsd
        http://www.springframework.org/schema/osgi-compendium
        http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd
        http://www.springframework.org/schema/beans  
        http://www.springframework.org/schema/beans/spring-beans.xsd">

   <!-- use the OSGi namespace elements directly -->
   <service id="simpleServiceOsgi" ref="simpleService"
       interface="org.xyz.MyService" />

   <!-- qualify compendium namespace elements -->
   <osgix:property-placeholder persistent-id="com.xyz.myapp"/>

</beans:beans>

현재 이 네임스페이스는 Configuration Admin 서비스만 지원하며 다른 서비스 지원 기능은 추후에 추가될 예정이다.
신고

'Spring DM > Appendix A' 카테고리의 다른 글

A.1. Configuration Admin  (0) 2008.07.07
Compendium Services  (0) 2008.07.07
top


나이스~ 스프링 DM 1.1.0 정식판 배포

Spring DM/etc : 2008.07.04 22:27


http://forum.springframework.org/showthread.php?t=56895

짝짝짝!!
신고
top


Whiteship's 스프링 DM 레퍼런스 1.0 m1 배포

Spring DM/etc : 2008.06.24 11:18



Can u feel the fire~ I get higher~. Nobody nobody nobody no~ can't nobody hold me down~.
Whiteship's 스프링 DM 배포 로드맵

현재 버젼 m1
1. 편집 상태가 상당히 허접합니다.
2. 초장부터 끝장까지 일관적이지가 않습니다. 초반에는 거의 편역과 요약 형태인데, 뒤로 갈 수록 번역 스타일로 변해갑니다.
3. 시간이 넉넉치 않아서, 일단 처리하고 볼려는 심산입니다.

m2 는 다음주 쯔음에...
1. 편집 상태를 좀 더 다듬어서. 링크도 살리고, 기타 등등.
2. 제목을 번역

m3 은 다다음주 쯔음에...
1. 전반적인 문채를 다듬어서 필요한 부분을 추가하고 필요 없는 부분은 삭제. 즉 내용을 수정합니다.
2. 그림과 표를 추가합니다.

v1 정식버젼 배포는 다다다음주 쯔음에..
1. docbook을 이용해서 HTML과 PDF 파일로 배포하기 시도.
2. 잘 되면, maven을 이용해서 빌드

v2 스프링 DM 레퍼런스 구현 기약 없음.
1. 레퍼런스 내용을 다루는 모든 예제 코드 만들기
2. 스프링 DM, OSGi를 익히는데 필요한 로우 레벨의 지식 탐구 정리(Classloading과 Cuncrrency)

v3 더더욱 기약 없음.
1. 스크린 캐스팅 추가

다운로드는 이 곳에서..
신고
top


9.2. Integration Testing

Spring DM/Chapter 9 : 2008.06.22 00:15


OSGi처럼 제한적인 환경에서는 여러분들이 작성한 클래스의 가시성과 버전관리, 번들이 다른 번들과 제대로 동작하는지를 확인하는 것이 중요하다.

통합 테스트를 편하게 하기위해, 스프링 DM 프로젝트는 테스트 클래스 계층구조를 제공한다(org.springframework.osgi.test.AbstractOsgiTests를 기반으로) . 이걸 사용해서 자동으로 OSGi 환경에서 실행되는 일반적인 JUnit 테스트 케이스를 작성할 수 있다.

보통 스프링 DM 프로젝트가 지원하는 시나리오는 다음과 같다:
  • OSGi 프레임워크 시작하기(Equinox, Knopflerfish, Felix)
  • 테스트에 필요하다고 기술된 번들 설치 및 시작
  • 테스트 케이스를 fly 번들 안으로 패키징하고, manifest 작성하고 OSGi 프레임워크에 해당 번들을 설치하기
  • OSGi 프레임워크 안에서 테스트 케이스 실행하기
  • 프레임워크 종료하기
  • 테스트 결과를 OSGi 밖에 있는 원래 테스트 케이스 객체에 전달하기

주의할 것
테스팅 프레임워크의 목적은 OSGi 통합 테스트를 OSGi 환경 밖에서 테스트 하는 것이다(Ant/Maven 같은 곳에서). 테스팅 프레임워크는 OSGi 번들로 사용하기 위해 만들어 둔 것이 아니다.

다음을 쭉 살펴보면 JUnit 기반 통합 테스트를 작성하는 것이 쉬워질 것이다.

본 챕터의 나머지는 스프링 DM 테스팅 스위트가 제공하는 기능들을 설명한다.

9.2.1. 간단한 OSGi 통합 테스트 작성하기

진단 프레임워크에는 특정 기능을 제공하는 여러 클래스들이 있는데, 여러분이 작성한 대부분의 클래스들은 org.springframework.osgi.test.AbstractConfigurablBundleCreatorTests를 상속하면 된다.

이 클래스를 확장하고 BundleContext 필드를 사용하여 OSGi 플랫폼을 사용해보자.

public class SimpleOsgiTest extends AbstractConfigurableBundleCreatorTests {

public void testOsgiPlatformStarts() throws Exception {
    System.out.println(bundleContext.getProperty(Constants.FRAMEWORK_VENDOR));
    System.out.println(bundleContext.getProperty(Constants.FRAMEWORK_VERSION));
    System.out.println(bundleContext.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT));
    }
}

간단하게 JUnit 테스트를 실행하듯이 테스트를 실행하면 된다. Equinox 3.2.x 에서 실행하면 다음과 같은 결과를 얻을 수 있다

Eclipse
1.3.0
OSGi/Minimum-1.0,OSGi/Minimum-1.1,JRE-1.1,J2SE-1.2,J2SE-1.3,J2SE-1.4}

보시다시피, 테스팅 프레임워크는 테스트 실행에 필요한 번들들 필요한 번들들(스프링, 스프링 DM, slf4j ...)을 자동으로 설치해준다.

9.2.2. 테스트에 필요한 것들 설치하기

스프링 DM jar와 테스트 자체를 제외하면 몇몇 라이브러리나 통합 테스트 대상이 되는 코드에 대한 의존도가 높다.

아파치 커먼스 Lang에 의존하고 있는 다음의 테스트 코드를 살펴보자.

import org.apache.commons.lang.time.DateFormatUtils;
    ...
      public void testCommonsLangDateFormat() throws Exception {
        System.out.println(DateFormatUtils.format(new Date(), "HH:mm:ssZZ"));
    }
}

위 코드를 실행하면, 다음과 같은 예외가 발생할 것이다.

java.lang.IllegalStateException: Unable to dynamically start generated unit test bundle
     ...
Caused by: org.osgi.framework.BundleException: The bundle could not be resolved.
Reason: Missing Constraint: Import-Package: org.apache.commons.lang.time; version="0.0.0"
    ...
    ... 15 more

테스트는 org.apache.commons.lang.time 패키지를 필요로 하지만, 이걸 공개한 번들은 존재하지 않는다. 이 문제를 해결하기 위해 commons-lang 번들을 설치해본자.(2.4 이상의 버전을 설치해야 한다. 그래야 OSGi 라이브러리다.)

설치되어야 할 번들을 getTestBundlesNames 또는 getTestBundles를 사용해서 명시할 수 있다.

기본적으로 테스트 스위트는 로컬 maven2 저장소를 사용하여 구성물을 위치시킨다. 구성물 그룹 아이디, 이름, 버전을 콤마로 구분한 문자열로 나열한 것을 기본 locator가 읽어서 해당 구성물을 찾아서 설치한다. 커스텀 locator를 구현하여 설정할 수 있다. org.springframework.osgi.test.provisioning.ArtifactLocator 인터페이스를 구현한 다음 끼워 맞추면 된다.

통합 테스트를 다음과 같이 수정하여 필요한 번들을 설치하자.

protected String[] getTestBundlesNames() {
     return new String[] { "org.springframework.osgi, cglib-nodep.osgi, 2.1.3-SNAPSHOT",
         "org.springframework.osgi, jta.osgi, 1.1-SNAPSHOT",
         "commons-lang, commons-lang, 2.4" };
     };
}

테스트를 다시 실행하면 위의 번들들이 OSGi 플랫폼에 설치된다.

노트

위에서 언급한 구성물들이 여러분의 로컬 메이븐 저장소에 있어야 한다.

9.2.3. Advanced testing framework topics

테스팅 프레임워크는 커스터마이징을 많이 할 수 있다. 이 번 챕터에서 여러분에게 유용한 후킹을 소개하고자 한다. 하지만, 이런 팁들이 테스트 코드의 복잡도를 높일 수도 있다.

9.2.3.1. 테스트 manifest 커스터마이징

자동 생성된 manifest가 테스트에 적당하지 않을 수도 있다. 예를 들어 manifest에 몇몇 새로운 헤더나 필수가 아니라 부가적인 import가 필요할때가 있다.

간단한 경우, 자동 생성된 manifest를 조작할 수 있다. 아래의 예제에서 번들 클래스패스를 명시적으로 설정하고 있다.

protected Manifest getManifest() {
      // let the testing framework create/load the manifest
      Manifest mf = super.getManifest();
      // add Bundle-Classpath:
      mf.getMainAttributes().putValue(Constants.BUNDLE_CLASSPATH, ".,bundleclasspath/simple.jar");
      return mf;
}

또 다른 방법으로 여러분이 직접 작성한 manifest 파일을 getManifestLocation() 메소드에 설정할 수도 있다.

protected String getManifestLocation() {
      return "classpath:com/xyz/abc/test/MyTestTest.MF";
}

둘 모두 manifest에 다음과 같이 설정되어 있어야 한다.

“Bundle-Activator: org.springframework.osgi.test.JUnitTestActivator”

저렇게 설정되어 있지 않으면, 테스팅이 제대로 동작하지 않을 것이다. 또한 JUnit, Spring, Spring DM의 특정 패키지들을 import 해줘야 된다.

Import-Package: junit.framework,
  org.osgi.framework,
  org.apache.commons.logging,
  org.springframework.util,
  org.springframework.osgi.service,
  org.springframework.osgi.util,
  org.springframework.osgi.test,
  org.springframework.context

테스트 클래스가 사용할 패키지 import에 실패하면 테스트는 실패할 것이고 NoDefClassFoundError가 발생할 것이다.

9.2.3.2. 테스트 번들 컨텐츠 커스터마이징

기본적으로, 테스트 대상이 되는 번들을 테스트 할 때 테스팅 인프라는 ./target/test-classes 폴더 밑에 있는 모든 클래스, xml, 프로퍼티 파일들을 사용한다. 이건 메이븐 구조에 맞게 설계된거다. 이런 설정을 두 가지 방법으로 변경할 수 있다.
  • AbstractConfigrableBundleCreatorTests getXXX 메소드를 구현하는 프로그래밍을 하는 방법.
  • 테스트 케이스와 비슷한 이름을 가진 프로퍼티 파일을 작성하는 선언적인 방법. 예를 들어, com.xyz.MyTest 가 사용할 설정 프로퍼티 파일은 com/xyz/MyTest-bundle.properties 파일이어야 한다.
표 9.1. 기본 테스트 jar 컨텐츠 설정

생략

이 옵션은 특정 리소스를 필요로 하는 테스트를 작성할 때 유용하다. AbstractConfigurableBundleCreatorTests와 AbstractOnTheFlyBundleCreatorTests를 살펴보면 보다 많은 후킹 메소드를 찾을 수 있을 것이다

9.2.3.3. MANIFEST.MF 생성 이해하기

테스트 번들 컨텐츠를 기반으로 테스트 manifest를 자동 생성 해주는 테스팅 프레임워크의 유용한 기능 중 하나다. 바이트코드를 분석하여 필요로 하는 페키지들을 import 하는 manifest를 작성해준다. 생성된 번들은 테스트를 실행하기 위한 용도기 때문에, 다음과 같은 가정을 전제로 한다.
  • 아무런 패키지도 export하지 않는다.
  • 페키지를 나누는 기능(서로 다른 번들에서 같은 패키지에 클래스들을 제공하는 기능)을 지원하지 않는다. Split package는 OSGi 스펙 3.13에 따라서 권장하지 않는다.
  • 테스트 번들은 오직 테스트 클래스들만 가지고 있다. 기본 설정을 변경하려면, createManifestOnlyFromTestClass 가 true를 반환하도록 재정의하라.

protected boolean createManifestOnlyFromTestClass() {
    return true;
}

노트

번들에 담겨있는 클래스들의 수와 크기에 Manifest를 작성하는데 필요한 시간이 비례한다.

일반적인 OSGi 번들용 manifest를 작성하는 것이 목적이 아니라, 빠르고 간단하게 테스트를 위한 것을 만들기 위한 용도이다.

9.2.4. OSGi application context 만들기

스프링 DM 테스팅 스위트는 스프링 테스팅 클래스들을 기반으로 하고 있다. application context를 만들려면, getConfigLocation 메소드를 재정의하여 application context 설정파일 위치를 알려주면 된다. 실행시에, OSGi application context가 생성되고 테스트 케이스를 실행할 동안 캐쉬될 것이다.

protected String[] getConfigLocations() {
   return new String[] { "/com/xyz/abc/test/MyTestContext.xml" };
}

9.2.5. 사용할 OSGi 플랫폼 설정하기


테스팅 프레임워크는 3개의 OSGi 4.0 구현체, Equinox, Knopflefish, Felix를 지원한다. 이걸 사용하려면 테스트 클래스패스에 이들이 존재해야 한다. 기본적으로 테스팅 프레임워크는 Equinox를 사용한다. 이 설정을 바꾸는 방법은 두 가지다.
  • getPlatformName() 메소드를 사용하는 프로그래밍적인 방법.
Platforms 인터페이스 구현체의 이름을 설정하여 사용할 플랫폼을 알려준다.

protected String getPlatformName() {
   return Platforms.FELIX;
}
  • org.springframework.osgi.test.framework 시스템 속성을 사용한 선언적인 방법
만약 이 속성이 설정되면, 테스팅 프레임워크는 이 값을 플랫폼 구현체의 풀 네임 값으로 사용할 것이다. 만약 문제가 생기면, Equinox를 다시 사용할 꺼고 경고 메시지를 로깅한다. 이 옵션은 (Ant나 Maven같은) 빌드 툴에게 유용하다. 왜냐면 테스트 코드를 변경하지 않고도 특정 타켓 환경을 알려줄 수 있으니까.

9.2.6. 테스트 의존성 대기하기

테스팅 프레임워크에 내장된 기능 중 하나는 테스트를 실행할 때 필요한 의존성들이 설치 될 때까지 기다리는 것이다. OSGi 플랫폼의 동시성 때문에, 번들이 설치됐다고 해서 해당 번들이 제공하는 서비스가 동작중이라는 것을 보장할 수는 없다. 테스트가 필요로 하는 서비스가 완전히 가용하기 전에 테스트를 실행하는 건 테스트 결과를 더럽히는 일이다. 기본적으로 테스팅 프레임워크는 사용자가 설치한 번들을 모두 조사해서, 스프링을 사용한 번들일 경우 해당 번들이 완전히 시작될 때까지(시작 상태가 되면 서비스 설치된거니까..) 기다린다. 이 기본 행위를 shouldWaitForSpringBundlesContextCreation 메소드에서 변경할 수 있다. AbstractSynchronizedOsgiTests를 참조하라.

9.2.7. 테스팅 프레임워크 성능

테스팅 프레임워크가 제공하는 모든 기능을 고려했을 떄, 성능적인 측면에서 병목현상을 야기하지는 않을지 의심스러울 것이다. 먼저, 테스팅 프레임워크가 자동으로 해주는 모든 일들은 어떻게 해서든 해야만 하는 일들이다. 그 작업들을 손수하기에는 에러가 발생할 여지가 너무 많고 시간 소비도 만만치 않다.

현재의 인프라는 거의 반년간 사용해 왔다. 통합 테스트(120개 정도)를 실행하는데 노트북에서 3분 30초 가량 걸린다. 대부분의 시간은 OSGi 플랫폼을 시작하고 끄는데 소비된다. "테스팅 프레임워크"는 오직 10%가량의 시간만 소비한다.

하지만 우린 필요한 설정을 보다 최소화하고, 보다 더 빠르고 똑똑하게 만들려고 한다. 좋은 아이디어가 있으면 이슈트래커나 포럼을 통해서 언제든지 제안해달라. 
신고

'Spring DM > Chapter 9' 카테고리의 다른 글

9.2. Integration Testing  (0) 2008.06.22
9.1. OSGi Mocks  (0) 2008.06.17
Chapter 9. Testing OSGi based Applications  (0) 2008.06.17
top


9.1. OSGi Mocks

Spring DM/Chapter 9 : 2008.06.17 22:28


대부분의 OSGi API들이 인터페이스고 EasyMock같은 라이브러리를 사용하여 목객체를 만들어 사용하는 것이 간단할 수도 있지만, 실제로는 상당히 많은 코드를 필요로 한다.(특히 JDK 1.4에서..) 테스트를 짧고 간결하게 유지하기위해, 스프링 DM은 org.springframework.osgi.mock 패키지 아래에 OSGi 목들을 제공한다.

이것들이 유용한지 아닌지는 여러분들에게 달려있다. 우린 스프링 DM 테스트 스위트를 만들 때 이들을 상당히 많이 사용했다. 아래의 코드는 그런 테스트 코드에서 흔히 볼 수 있는 코드 조각이다.

private ServiceReference reference;
private BundleContext bundleContext;
private Object service;
   
protected void setUp() throws Exception {
    reference = new MockServiceReference();
    bundleContext = new MockBundleContext() {

        public ServiceReference getServiceReference(String clazz) {
            return reference;
        }

        public ServiceReference[] getServiceReferences(String clazz, String filter)
                throws InvalidSyntaxException {
            return new ServiceReference[] { reference };
        }
       
        public Object getService(ServiceReference ref) {
            if (reference == ref)
               return service;
            super.getService(ref);
        }
    };

    ...
}
   
public void testComponent() throws Exception {
    OsgiComponent comp = new OsgiComponent(bundleContext);
   
    assertSame(reference, comp.getReference());
    assertSame(object, comp.getTarget());
}

마무리 하자면, 스프링 DM이 제공하는 라이브러리들을 사용해보고 여러분들이 가장 편한다고 느끼는 라이브러리를 사용하라. 우리가 작성한 테스트 스위트에서는 EasyMock 라이브러리와 통합 테스트를 많이 사용했다.
신고

'Spring DM > Chapter 9' 카테고리의 다른 글

9.2. Integration Testing  (0) 2008.06.22
9.1. OSGi Mocks  (0) 2008.06.17
Chapter 9. Testing OSGi based Applications  (0) 2008.06.17
top


Chapter 9. Testing OSGi based Applications

Spring DM/Chapter 9 : 2008.06.17 22:10


베스트 프랙티스를 잘 따르고 스프링 DM 지원 기능을 사용한다면, 여러분들이 작성한 bean 클래스들은 단위 테스트가 용이할 것이다. OSGi를 직접 참조하지도 않을 것이고, 최소한의 인터페이스 기반의 OSGi API(BundleContext와 같은..)만을 사용하여 mock 객체를 만드는 것도 쉬워질 것이다. 단위 테스트와 통합 테스트 둘 다 스프링 DM이 지원한다.
신고

'Spring DM > Chapter 9' 카테고리의 다른 글

9.2. Integration Testing  (0) 2008.06.22
9.1. OSGi Mocks  (0) 2008.06.17
Chapter 9. Testing OSGi based Applications  (0) 2008.06.17
top


8.7. Spring-MVC Integration

Spring DM/Chapter 8 : 2008.06.17 22:00


1.1부터 스프링 DM은 스프링 MVC 프레임워크와 밀접하게 통홥되었다. 이번 섹션에서 어떻게 스프링 MVC 애플리케이션을 OSGi 환경에서 실행할 수 있는지 살펴보겠다.

OSGi 플랫폼에서 제대로 사용되려면, 스프링 MVC를 새로운 환경으로 이전해야 한다. 스프링 DM은 OSGi를 인식하는 application context를 제공한다.(OsgiBundleXmlWebApplicationContext) 이것은 스프링 MVC의 XmlApplicationContext와 동일한 역할을 한다. application context는 웹 애플리케이션 BundleContext를 알고 있고 따라서 OSGi 영역에 있는 자원들을 읽고 OSGi 서비스를 공개하고 BundleContextAware를 지원하고 클래스패스에 포함되어있는 번들들을 컴포넌트스캔할 수 있다.

이 애플리케이션 컨텍스트를 사용하려면 스프링의 ContextLoaderListener의 contextClass라는 파라미터와 DispatcherServlet을 사용하면 된다.

<context-param>
  <param-name>contextClass</param-name>                                                                   (1)
  <param-value>
org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext
</param-value>    (2)
</context-param>

<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>                        (3)
</listener>

<servlet>
  <servlet-name>petclinic</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>                              (4)
  <load-on-startup>2</load-on-startup>
  <init-param>
    <param-name>contextClass</param-name>                                                             (5)
    <param-value>
org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext
</param-value>  (2)
  </init-param>
</servlet>

(1) 스프링의 ContextLoaderListner가 최상위 웹 애플리케이션 컨텍스트 타입을 알기 위한
context-param 이름
(2) OSGi를 인식하는 web application context 풀네임
(3) 스프링 설정 읽어들이는 리스너
(4) 스프링 MVC 젤 앞단 컨트롤러
(5) 스프링의 DispatcherServlet이 웹 애플리케이션 컨텍스트 타입을 알기 위한 init-param

위와같이 설정하면,  스프링 DM 번들은 구동중인 BundleContext를 가져다 사용할 수 있으며 OSGi 환경을 인식할 수 있다.

노트

물론 스프링 MVC 애플리케이션에는 적절한 import 문들이 들어가있어야 한다. 즉 WAR도 번들이기 때문에 manifest 파일에 적절하게 설정되어 있지 않으면, 클래스패스가 맞지 않게되고 따라서 제대로 동작하지 않을 것이다.

신고

'Spring DM > Chapter 8' 카테고리의 다른 글

8.7. Spring-MVC Integration  (0) 2008.06.17
8.6. OSGi-ready libraries and web development  (0) 2008.06.17
8.5. Customizing the standard deployers  (0) 2008.06.14
8.4. web extender 설정하기  (0) 2008.06.12
8.3. WAR classpath in OSGi  (0) 2008.06.12
8.2. Web support 사용법  (0) 2008.06.12
8.1. 지원하는 웹 컨테이너  (0) 2008.06.12
Chapter 8. Web Support  (0) 2008.06.12
top


8.6. OSGi-ready libraries and web development

Spring DM/Chapter 8 : 2008.06.17 20:32


불행히도, 현재 대부분의 웹 개발용 라이브러리들은 OSGi 번들이 아니다. 즉 그 라이브러리들을 OSGi 공간에서 사용하려면 다른 번들에 내장된 채로 사용하는 수밖에 없다. 이 문제를 해결하기 위해서, 스프링 DM 프로젝트는 흔히 사용하는 라이브러리들을 OSGi에서 사용할 수 있는 형태로 바꾼 것들을 Maven 리파지토리에 올려서 제공하고 있다.

8.6.1. Deploying web containers as OSGi bundles

스프링 DM은 웹 컨테이너를 OSGi 서비스로 설치하는 것이 가능하게 한다. Tomcat 이나 Jetty 배포판이 그런 일을 하지는 않기 떄문에 스프링 DM은 간단하지만 유용한 두 개의 OSGi Activator를 스프링 DM 리파지토리에서 제공한다. 어떤게 설치되면, 프로그래밍적으로 기본 설정(커스터마이징 할 수 있다. activator는 공용이지만 설정은 쉽게 변경할 수 있다.)에 따라 적절한 웹 컨테이너를 시작시킨다.

8.6.1.1. Tomcat 5.5.x/6.0.x

아파치 톰캣 버전 5.5.x 와 6.0.x는 OSGi 구성물 형태로 catalina.osgi artifactId를 가지고 있다. 이 jar들은 오직 commons-logging, JMX, Servlet/JSP 라이브러리만을 필요로 한다.

게다가 저장소에는 톰캣 Activaor도 있는데 이들의 이름은 catalina.osgi.start로 되어있다. activator는 톰캣 XML 설정을 이해하며 서버를 localhost, 8080 포터에서 실행하기위한 기본 설정을 가지고 있다. 이런 기본 설정은 conf/server.xml 을 톰캣 activator에 Fragment로 붙여서 기본 설정을 재정의할 수 있다.

fragment를 붙이려면, 다음과 같이 manifest에 추가한다.

Fragment-Host: org.springframework.osgi.catalina.start.osgi

8.6.1.2. Jetty 6.1.8+/6.2.0

Jetty는 기본적으로 OSGi에서 사용할 수 있는 형태다. 따라서 어떤 변형을 하지 않아도 OSGi 플랫폼에 설치할 수 있다. 하지만, activator가 없기 때문에 스프링 DM이 톰캣 activator같은 걸 하나 제공해준다. 이 activator는 jetty.start.osgi라는 이름을 가지고 있다. 톰캣 activator와 마찬가지로 이녀석도 localhost에 8080 포트로 기본 설정을 포함하고 있다. 이 기본 설정을 바꾸려면 etc/jetty.xml 에 설정을 한다음 fragment로 붙이면 된다.

Fragment-Host: org.springframework.osgi.jetty.start.osgi

extender처럼, 각각의 activator들은 사용자가 아무것도 제공하지 않으면 기본값을 사용한다.

8.6.2. Common libraries

Servlet, JSP, Standard Taglib, Commons-EL 및 기타 라이브러리들을 스프링 DM 저장소에서 이용할 수 있다.
신고

'Spring DM > Chapter 8' 카테고리의 다른 글

8.7. Spring-MVC Integration  (0) 2008.06.17
8.6. OSGi-ready libraries and web development  (0) 2008.06.17
8.5. Customizing the standard deployers  (0) 2008.06.14
8.4. web extender 설정하기  (0) 2008.06.12
8.3. WAR classpath in OSGi  (0) 2008.06.12
8.2. Web support 사용법  (0) 2008.06.12
8.1. 지원하는 웹 컨테이너  (0) 2008.06.12
Chapter 8. Web Support  (0) 2008.06.12
top


8.5. Customizing the standard deployers

Spring DM/Chapter 8 : 2008.06.14 00:31


디플로이어는 시작시에 필요한 서비스들을 룩업한다. 필수 요소인 경우 디플로이어는 해당 서비스를 참조할 수 있을 때까지 기다리고, 만약 시간이 지나도 참조할 수 없을 때는 예외를 발생시킨다. 만약에 기본 타임아웃 설정이나 서비스 룩업 필터가 정의되어 있지 않으면, 스프링 DM의 reference 엘리먼트를 사용하여 설정할 수 있다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:osgi="http://www.springframework.org/schema/osgi"
   xmlns:p="http://www.springframework.org/schema/p"                                     (4)
   xsi:schemaLocation="http://www.springframework.org/schema/beans  
     http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/osgi
     http://www.springframework.org/schema/osgi/spring-osgi.xsd">

    <osgi:reference id="myTomcatServer"                                                  (1)
        interface="org.apache.catalina.Service"
        filter="(environment=testing)"
        cardinality="0..1"/>
        
    <bean id="warDeployer"                                                               (2)
        class="org.springframework.osgi.web.deployer.tomcat.TomcatWarDeployer"
        p:service-ref="myTomcatServer"/>                                                 (3)

</beans>

1    사용자 정의 OSGi 서비스 룩업
2    디플로이어 정의Deployer definition (이름이 중요하다.)
3    서비스 속성 할당(p namespace 사용)
4    스프링의 p 네임스페이스 선언

위의 설정에 필요한 패키지를 import 해야 한다는 것을 주의 하자. 그리고 위는 웹 Extender에서 사용해야 하기 때문에 Fragment로 설정한다. 우선 import 해야 하는 패키지는 Catalina 패키지고, 그안에 있는 Service  인터페이스는 다른 패키지에 있는 Connector라는 것의 의존하고 있다. 따라서 다음과 같이 설정한다. 그러지 않으면, ClassNotFoundException 이나 NoClassDefFoundException이 발생한다.

# Catalina packages
Import-Package: org.apache.catalina,org.apache.catalina.connector
# Spring-DM Web Extender
Fragment-Host: org.springframework.bundle.osgi.web.extender



신고

'Spring DM > Chapter 8' 카테고리의 다른 글

8.7. Spring-MVC Integration  (0) 2008.06.17
8.6. OSGi-ready libraries and web development  (0) 2008.06.17
8.5. Customizing the standard deployers  (0) 2008.06.14
8.4. web extender 설정하기  (0) 2008.06.12
8.3. WAR classpath in OSGi  (0) 2008.06.12
8.2. Web support 사용법  (0) 2008.06.12
8.1. 지원하는 웹 컨테이너  (0) 2008.06.12
Chapter 8. Web Support  (0) 2008.06.12
top


8.4. web extender 설정하기

Spring DM/Chapter 8 : 2008.06.12 23:57


core extender와 마찬가지로, 웹 Extender도 OSGi fragment로 설정될 수 있다. 같은 패턴을 사용해서, 웹 extender는 자신의 번들 영역에있는 META-INF/spring 폴더 밑에 있는 XML 파일들을 찾고 그것들을 하나의 application context로 조립하여 자신의 설정파일로 내부적으로 사용한다. 이런 기본 설정을 재정의 하려면, 아래 표에서 적당한 빈 이름을 찾아서, 그것들을 원하는 대로 정의한 다음 그걸 다음의 코드를 사용하여 fragment로 spring-osgi-web.jar에 붙이면 된다.

Fragment-Host: org.springframework.bundle.osgi.web.extender

다음의 빈들이 현재 Web extender에 의해 인식가능하다.

표생략

8.4.1. 웹 배포자 변경하기

톰캣 배포자에서 제티로 바꾸는 예제는 다음과 같다. META0INF/spring/jetty-deployer.xml에 다음과 같이 설정한다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/beans  
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="warDeployer"                                                               (1)
        class="org.springframework.osgi.web.deployer.jetty.JettyWarDeployer" />          (2)
</beans>

1    web extender에 의해 사용되고 있는 미리 정의한 빈 이름
2    org.springframework.osgi.web.deployer.WarDeployer 인터페이스를 구현하고 있는 Bean 구현체

파일을 만들었으면, 스프링 DM 웹 Extender 번들d에 OSGi fragment로 붙어있는 번들이 되어야 한다. 따라서 Fragment-Host 헤더를 사용한다.

Fragment-Host: org.springframework.bundle.osgi.web.extender

자 이제 위의 조각(Fragment)이 spring-osgi-web.jar 번들에 끼워졌기 때문에 웹 애플리케이션을 제티에 배포한다.

미리 만들어둔 제티 Fragment를 스프링 DM 메이븐 저장소에서 jetty.extender.fragment.osgi 아티팩트id로 사용할 수 있다.
신고

'Spring DM > Chapter 8' 카테고리의 다른 글

8.7. Spring-MVC Integration  (0) 2008.06.17
8.6. OSGi-ready libraries and web development  (0) 2008.06.17
8.5. Customizing the standard deployers  (0) 2008.06.14
8.4. web extender 설정하기  (0) 2008.06.12
8.3. WAR classpath in OSGi  (0) 2008.06.12
8.2. Web support 사용법  (0) 2008.06.12
8.1. 지원하는 웹 컨테이너  (0) 2008.06.12
Chapter 8. Web Support  (0) 2008.06.12
top


8.3. WAR classpath in OSGi

Spring DM/Chapter 8 : 2008.06.12 23:35


서블릿 스펙에는 WAR 내부에 특별한 의미를 지니는 위치와 몇가지 규칙들을 정의하고 있다. 이번 섹션에서는 이것들이 OSGi 환경에서 어떻게 처리되는지 살펴볼 것이다.

8.3.1. Static Recsources

WAR 번들을 설치할 때, static resource들의 경우, 스프링 DM은 번들 영역에서 가용한 것이 무엇인지만 신경쓴다. 이게 무슨 뜻이냐면 번들 jar 내부에 있는 것들과 거기에 붙어있는 fragment만을 사용할 수 있다는 것이다. 서블릿 스펙에 보면, 웹 애플리케이션에 접속한 클라이언트가 아니라 WEB-INF 폴더 이하에 있는 자원들만ServletContext API를 통해 사용 가능하다고 되어있다. 게다가 클래스패스(imported pachages, required bundles 또는 dynamic imports)에 있는 모든 자원은 애플리케이션 코드에서 읽어들여 사용할 수 있지만 그 밖에서는 참조할 수 없다.

8.3.2. 서블릿

기존의 WAR 배포와의 주요 차이점은 서블릿 패키지들을 WAR 번들에서 사용할 수 있도록 명시적으로 import되어야 한다는 것이다. 해당 패지키들을 Import -Package 속성에 추가한다.

Import-Package: javax.servlet,javax.servlet.http,javax.servlet.resources

추가적으로, 서블릿 스펙은 WAR의 클래스패스를 몇몇 미리 정의된 위치에 근거하고 있다. 빠르게 살펴보면 다음과 같다:
  • WEB-INF/classes: 모든 리소드들은 WEB-INF/Classes 밑에 있다
  • WEB-INF/lib/*.jar: 모든 jar 파일들은 WEB-INF/lib 밑에 있다.
여기에 추가로, 각각의 컨테이너 구현체들은 WAR 클래스패스에 추가되는 common 라이브러리들을 제공할 수 있다. OSGi 이기 때문에, WAR 클래스패스는 다시 구성한다. 스프링 DM은 미리 정의된 위치는 무시하고 항상 OSGi 클래스패스를 사용한다. 즉 WEB-INF/classes에 포함되어 있거나 WEB-INF/lib에 포함되어 있다 하더라도 WAR 번들이 import한 패키지들만 사용할 수 있다는 것이다. 다시 말하자면, WEB-INF/classes 밑에 있는 모든 클래스들중에 WAR OSGi 클래스패스에서 가용하지 않은 것들은 없는거나 마찬가지다.

미리 정의된 WAR 위치들을 설정하는 가장 쉬운 방법은, 그것들을 번들 클래스패스에 추가하는 것이다.

Bundle-Classpath: .,WEB-INF/classes,WEB-INF/lib/some.jar,WEB-INF/lib/lib.jar

번들 클래스패스에 추가하기 전에 그들을 OSGi 번들로 설치할 수 있는지 없는지 생각해야한다. 그렇게 함으로써 귿르을 다른 WAR에서도 사용할 수 있고 OSGi 버전잉을 할 수 있다. 동일한 VM에 같은 라이브러리의 상이한 버전이 여럿 존재하는 것이 가능해 진다.

8.3.3. JSP

JSP를 처리하려고, 스프링 DM은 Tomcat Jasper2 엔진을 통합했다. 즉 JSP 1.2, 2.0, 2.1을 지원한다는 것이다. OSGi화된 버전들은 스프링 DM 리파지토리에서 가용하다. OSGi 번들이 Jasper 클래스들을 import할 필요가 없다.

8.3.3.1. 태그 라이브러리들

JSP 스펙은 태그 라이브러리 생성하여 "JSP 페이지에서 재사용할 수 있는 기들을을 모듈화 하여 선언할 수 있도록"했다. 또한 재사용 가능한 taglib들은 자바 클래스들(Tag 구현체)와 어떤 태그들을 사용할 수 있는 기술한 파일을 컴포넌트로 가지고 있다. 스프링 DM은 taglib들을 jar 형태로 WEB-INF/lib 밑에 두거나 풀어져있는 상태로 WEB-INF/classes 밑에 두는 JSP 컨벤션을 확장하여, 번들 클래스패스(imported pachages, required bundles)에 있는 모든 taglib들을 찾아낸다.

스프링 DM은 번들 클래스패스 내에서 자동으로 taglib 파일(*.tld)들을 찾아서 그들을 Jasper 엔진에서 사용할 수 있게 해준다. 하지만, tag 정의가 자동으로 찾아지는 반면 tag 클래스들은 그렇지 않다. 여기서도 OSGi 클래스패스가 우선한다. 즉, 태그를 사용하려면, war 번들이 tag에 해당하는 클래스를 import 해야한다. 안그러면 태그를 사용할 수 없다.

많은 태그를 방출하는 라이브리들을 다룰 때, Impoert-Pachage 대신 Required-Bundle 헤더를 사용할 수 있다.

Require-Bundle: org.springframework.osgi.jstl.osgi

위의 헤더를 사용하면, JSP Standard Tag Library(JSTL)이 내보내는 모든 클래스들을 war 번들이 참조할 수 있고 따라서 JSP 내에서 사용할 수 있다.

주의할 것

Require-Bundle을 사용하기 전에 그 용법에 대해 OSGi 스펙 3.13 참조하라.

war 클래스패스에 어떤 매카니즘을 사용하든 상관없이, 여러 WAR들이 그것들을 공유하게 할 수 있다. 각각의 번들들은 오직 패키지만 import 할 수 있고 라이브러리 jar를 통째로 가져오진 못한다. 사실, 다른 번들들이나 Jar에 들어있는 패지키들을 선택적으로 사용하여 원하는 행위를 도출해 낼 수 있다. 매우 막강한 기능으로 웹 애플리케이션 배포를 용이하게 한다.


신고

'Spring DM > Chapter 8' 카테고리의 다른 글

8.7. Spring-MVC Integration  (0) 2008.06.17
8.6. OSGi-ready libraries and web development  (0) 2008.06.17
8.5. Customizing the standard deployers  (0) 2008.06.14
8.4. web extender 설정하기  (0) 2008.06.12
8.3. WAR classpath in OSGi  (0) 2008.06.12
8.2. Web support 사용법  (0) 2008.06.12
8.1. 지원하는 웹 컨테이너  (0) 2008.06.12
Chapter 8. Web Support  (0) 2008.06.12
top


8.1. 지원하는 웹 컨테이너

Spring DM/Chapter 8 : 2008.06.12 22:41


현재까지는, Apache Tomcat 5.5.X/6.0.X 그리고 Jetty 6.1.8+/6.2.X를 사용할 수 있다.(다른 컨테이너들도 쉽게 끼워넣을 수 있다.). 웹 지원은 JDK 1.4 호환가능하다. 선택한 컨테이너가 필요로 하는 JVM을 확인하라. 일반적으로, Servlet 2.4/JSP 2.0은 JDK 1.4를 사용하고 Servlet 2.5/JSP2.1은 JDK 1.5를 필요로 한다.
신고

'Spring DM > Chapter 8' 카테고리의 다른 글

8.7. Spring-MVC Integration  (0) 2008.06.17
8.6. OSGi-ready libraries and web development  (0) 2008.06.17
8.5. Customizing the standard deployers  (0) 2008.06.14
8.4. web extender 설정하기  (0) 2008.06.12
8.3. WAR classpath in OSGi  (0) 2008.06.12
8.2. Web support 사용법  (0) 2008.06.12
8.1. 지원하는 웹 컨테이너  (0) 2008.06.12
Chapter 8. Web Support  (0) 2008.06.12
top


Chapter 8. Web Support

Spring DM/Chapter 8 : 2008.06.12 22:30


1.1.0 배포판 부터 도입된 주요 기능은 웹 애플리케이션 지원이고 이로인해 웹 애플리케이션을 OSGi에 배포하기 쉬워졌다.

웹 애플리케이션을 OSGi 위에서 돌리는 가장 큰 문제는 클로스로딩이다. 웹 애플리케이션에는 번들 영역(Bundle Space)라던지 가져온 패키지(Imported pachages)라는 개념이 없다. 각각의 웹 컨테이너들은 자신만의 클래스 로딩 계층구조를 가지고 있는 클래스패스를 사용하여 OSGi 공간과 출돌을 발생시킬 수 있다. 스프링 DM은 이런 문제들을 웹 컨테이너와 OSGi 공간 사이에 다리 역할을 하여 로딩이 더이상 문제가 되지 않도록 하고 있다. 그 기능과는 별개로, 스프링DM에서 웹 지원은 웹 컨테이너와 직접 통합하여 WAR 처리가 말그대로 서버에서 처리된다. 모든 설정과 기능(non-blocking vs blocking IO, thread pool, specification support(Servlet 2.3, 2.4, 2.5) 등등등)이 가용하다. 모든 타겟 컨테이너의 커스텀 설정 파일과 web.xml 문법이 모두 사용 가능하다.(스프링 DM은 전혀 이걸 파싱하지 않는다.) 요약하자면, 타겟 컨테이너가 지원하는 모든 것들이 스프링 DM을 사용한 OSGi WAR로 가용하다는 것이다.


신고

'Spring DM > Chapter 8' 카테고리의 다른 글

8.7. Spring-MVC Integration  (0) 2008.06.17
8.6. OSGi-ready libraries and web development  (0) 2008.06.17
8.5. Customizing the standard deployers  (0) 2008.06.14
8.4. web extender 설정하기  (0) 2008.06.12
8.3. WAR classpath in OSGi  (0) 2008.06.12
8.2. Web support 사용법  (0) 2008.06.12
8.1. 지원하는 웹 컨테이너  (0) 2008.06.12
Chapter 8. Web Support  (0) 2008.06.12
top


6.5. 서비스 Exporter와 서비스 Importer의 관계

Spring DM/Chapter 6 : 2008.06.11 22:51


공개한 서비스가 기능을 수행하기 위해 다른 서비스에 의존할 수 있다. 이때 만약 이들 서비스가 필수 레퍼런스라고 가정하고 해당 서비스들이 없어지고 대체제를 찾지 못해서 unsatisfied 상태가 되면 공개한 서비스는 자동으로 서비스 레지스트리에서 해지가된다. 즉 더이상 클라이언트에서 해당 서비스를 사용할 수 없게 된다. 그러나, 해당 필수 레퍼런스가 다시 가용해지면, 공개한 서비스도 다시 서비스 레지스트리에 등록된다.

이런 공개한 서비스의 자동 해지 및 자동 재등록은 오직 명시적인 선언에 의해서만 사용할 수 있다. 만약 서비스 A 빈을 공개한 서비스 S가 서비스 M을 사용하고 있을 때 아래 처럼 명시적으로 선언을 해 둬야. M이 없어지면 S가 해지되고, M이 사용가능 해지면 S도 다시 서비스 레지스트리에 등록된다.

<osgi:service id="S" ref="A" interface="SomeInterface"/>

<bean id="A" class="SomeImplementation">
   <property name="helperService" ref="M"/>
</bean>

<!-- the reference element is used to refer to a service
     in the service registry -->
<osgi:reference id="M" interface="HelperService"
     cardinality="1..1"/>

하지만 만약 A에서 M으로 의존성이 명시되어 있지 않고, 런타임 시에 M에 대한 레퍼런스를 만들어서 A로 넘긴다면 스프링 컨테이너는 아무일도 해주지 않는다. 스프링 DM은 의존성을 추적하지 않을 것이다.
신고
top


6.4. Service importer global defaults

Spring DM/Chapter 6 : 2008.06.11 22:29


osgi 네임스페이스는 모든 가져올 레퍼런스에 설정한 전역 설정을 선언할 수 있는 두 개의 속성을 제공한다.

따라서, osgi 네임스페이스를 사용할 때 내부에 있는 set, list, reference 엘리먼트는 다음 속성을 사용할 수 있다.
  • default-timeout: 타임아웃을 명시하지 않은 모든 importer에 기본 타임아웃을 설정할 수 있다.
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:osgi="http://www.springframework.org/schema/osgi"                            (1)
          osgi:default-timeout="5000">                                                   (2)

  <reference id="someService" interface="com.xyz.AService"/>                             (3)

  <reference id="someOtherService" interface="com.xyz.BService"
       timeout="1000"/>                                                                  (4)

</beans:beans>

(1) osgi 네임스페이스 프리픽스 선언
(2) default-timeout을 루트 엘리먼트에 선언. 만약 기본값이 설정되어 있지 않으면 5분이다. 여기서는 5초로 설정했다. 즉 밀리세컨이라는거..
(3) 이 reference는 기본값을 상속 받아서 타임아웃이 5초다.
(4) 이 reference는 기본값을 재정의해서 1초가 된다.

  • default-cardinality: 연관유형을 설정하지 않은 것들의 기본 연관유형을 설정할 수 있다. 가용한 값은 0..X와  1..X다. X는 런타입시에 reference일 경우에는 1로 list나 set일 경우에는 N으로 바뀐다.
<beans:beans
      xmlns="http://www.springframework.org/schema/osgi"                                 (1)
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:beans="http://www.springframework.org/schema/beans"                          (2)
      xmlns:osgi="http://www.springframework.org/schema/osgi"                            (3)
         osgi:default-cardinality="0..X"                                                 (4)
         default-lazy-init="false">                                                      (5)

  <reference id="someService" interface="com.xyz.AService"/>                             (6)

  <set id="someSetOfService" interface="com.xyz.BService"/>                              (7)

  <list id="anotherListOfServices" interface="com.xyz.CService" cardinality="1..N"/>     (8)

</beans:beans>

(1) 스프링 DM 스키마를 기본 네임스페이스로 선언
(2) 스프링 프레임워크 beans 스키마를 가져오고 해당 네임스페이스 프리픽스를 정한다.(위 예제에선 beans로 했음)
(3) 스프링 DM 스키마를 가져오고 osgi 네임스페이스 프리픽스를 설정한다.
(4) default-cardinality를 루트 엘리먼트에 설정한다. 만약에 기본값을 설정하지 않으면 1..X으로 설정한다. 위의 경우 기본 값을 0..X으로 했고. 이 때 osgi 프리픽스를 붙인것에 주목하라.
(5) beans 엘리먼트 속성(default-lazy-init)은 프리픽스를 사용하지 않았다. since they are declared as being local and unqualified (see the beans schema for more information).
(6) reference 선언은 연관유형을 설정하지 않았기 때문에 기본값을 상속받는다. 즉 0..1이 된다.
(7) set 선언도 연관유형을 설정하지 않았기 때문에 기본값을 상속받는다. 즉 0..N이 된다. 0..1이 아니다
(8) list 선언은 연관유형이 기본값을 재정의하여 설정한대로 1..N 이 된다.

default-* 들을 사용하면 선언을 보다 쉽게 할 수 있고 기본 행위 변경을 간단하게 할 수 있다.(타임아웃 시간 줄이기나 늘리기와 같은..)
신고
top


6.3. Exporter/Importer listener 베스트 프랙티스

Spring DM/Chapter 6 : 2008.06.10 22:26


위에서 언급했듯이, 스프링 DM 리스너들은 서비스가 묶이고, 풀리고, 등록되고, 해지될 때를 알기 위한 용도다. 이런 리스너들을 다룰 때 다음의 가이드라인이 도움이 될 수 있을 것이다.
  • 오래 걸리는 작업을 리스너 안에서 실행하지 말아라. 만약 그래야만 한다면, 별도의 쓰레드에서 작업하도록 하라. 리스너들이 동기적으로 처리되기 때문에 가능한 빨리 처리되도록 해야 한다. 해당 리스너 안에서 작업을 하는 동안에는 다른 이벤드들과 서비스의 활동이 대기상태가 된다.
  • 왠만하면 커스텀 리스너 콜백을 사용하라. 그래야 스프링 DM API에 묶이지 않으며, 특정 이름을 가용하지도 않는다.
  • bind/unbind 설정을 반복하고 있다면, 빈 설정 상속 기능을 사용하는 것을 한번 고려해 보아라. 공통적인 설정을 재사용할 수 있다.
  • java.util.Dictionary보다는 java.util.Map을 사용하라. 전자는 폐기처분 상태다. 그래도 호환성을 위해서 스프링 DM은 리스너에 필요시 Dictionary로 캐스팅할 수 있는 Map을 제공한다.
  • 과도한 메소드 사용에 주의하라. 원치 않게도 모든 메소드들이 특정 서비스 타입에 모두 호출 될 수 있다.
public class MyListener {
    void register((1)Object service, Map properties);
    void register((2)Collection dataService, Map properties);
    void register((3)SortedSet orderedDataService , Map properties);
}

1    Object type - 이 메소드는 항상 실행된다.
2    Collection type - 이 메소드가 실행되면, 바로 위에 있는 메소드도 실행된다.
3    SortedSet type - 이 메소드가 실행되면, 위에 있는 거 모두 실행된다.

6.3.1. 리스너와 cyclic depencdency

리스너가 자신을 사용하는 서비스를 사용하려는 빈을 참조하려는 경우가 있을 수 있다.

<bean id="listener" class="cycle.Listener">                                              (1)
    <property name="target" ref="importer" />                                            (2)
</bean>
   
<osgi:reference id="importer" interface="SomeService">                                   (3)
    <osgi:listener bind-method="bind" ref="listener" />                                  (4)
</osgi:reference>

1    Listener bean
2    Dependency listener -> importer
3    Importer declaration
4    Dependency importer -> listener

위 선언은 유효하다. 그러나 리스너를 만들려고 하면 레퍼런스 빈을 만들어야 하고 레퍼런스 빈을 만들려면 리스너를 만들어야 한다. 이 원이 깨져서 어느 한쪽이라고 먼저 생성을 하고 설정되어야 한다. 이런 시나리오는 스프링 DM에서 지원한다. 즉 알아서 만들어 준다. 하지만 다음과 같이 내부 빈을 사용한 경우에는 그렇치 않다.

<osgi:reference id="importer" interface="SomeService">                                   (1)
    <osgi:listener bind-method="bind">                                                   (2)
        <bean class="cycle.Listener">                                                    (3)
            <property name="target" ref="importer" />                                    (4)
        </bean>
    </osgi:listener>
</osgi:reference>

1    OSGi service importer
2    Dependency between importer -> listener
3    Nested listener declaration
4    Dependency nested listener -> importer

내부 빈은 자신의 이름이나 라이프사이클도 없이 외부 빈에 종속적인 삶을 살 뿐이기 때문에, 내부 리스너를 캐시 할 수 없다. 따라서 cyclic 참조 원을 깨트리지못하고 동작하지 않게 되는것이다.

정리하자면, 만약 리스너가 정말로 자신을 사용하는 서비스에 대한 참조가 필요하다면 리스너를 탑 레벨 빈으로 등록하거나 dependency lookup을 사용하라. 대신 후자는 좀 더 많으 설정과 빈 이름을 사용할 것이기 때문에 dependency injection 보다 깨지기 쉽다.


신고
top


6.2. Defining references to OSGi services

Spring DM/Chapter 6 : 2008.06.10 22:00


스프링 DM은 OSGi 서비스 레지스트리를 통해 사용할 수 있는 서비스를 나타내는 빈을 선언하는 기능을 제공한다. 이런 방법으로 통해 OSGi 서비스는 애플리케이션 컴포넌트로 주입될 수 있다. 서비스를 룩업할때는 해당 서비스가 지원하는 서비스 인터페이스 타입과 레지스트리에 등록된 서비스 속성에 부합하는 부가적인 필터 표현식을 사용한다.

몇몇 경우에, 간단하게 애플리케이션에서 하나의 서비스만을 필요로 할 때가 있다. 이 때는 reference 엘리먼트를 정의해서 단일 서비스를 참조하도록 정의할 수 있다. 다른 경우, 특히 OSGi 화이트보드 패턴을 사용할 때, 모든 가용한 서비들을 필요로 할 때가 있는데, 스프링 DM은 이거슬 List나 Set 콜렉션으로 이들 집합을 관리할 수 있는 기능을 제공한다.

6.2.1. 단일 서비스 참조하기


reference 엘리먼트는 서비스 레지스트리에 등록된 서비스를 참조할 때 사용한다.

선언한 것에 부합하는 서비스가 여러 개일 수 있기 때문에, BundleContext.getServiceReference에 의해 반환되는 서비스를 참조하게 된다. 이게 무슨 뜻이냐면 가장 높은 랭킹의 서비스가 반환된다는 것이다. 또는 만약 랭킹이 같을 때는 서비스 id가 가장 낮은 순서(프레임워크에 먼저 등록될 수록 id가 낮다.)로 반환된다.(OSGi 스펙에 보면 보다 자세하게 서비스 선택 알고리즘이 설명되어 있다.)

6.2.1.1. 가져온 서비스의 인터페이스 제어하기

interface 속성은 해당 서비스가 반드시 구현한 인터페이스를 나타낸다. 예를 들어, 다음의 선언은 messageService 빈 하나를 등록한건데, 이것은 MessageService 인터페이스를 제공하는 서비스를 서비스 레지스트리로부터 질의하여 반환받은 서비스가 된다.

<reference id="messageService" interface="com.xyz.MessageService"/>

service 선언과 마찬가지로, 여러개의 인터페이스를 기술할 떄는 interface 속성 대신에 내부 엘리먼트로 interfaces를 사용하면 된다.

<osgi:reference id="importedOsgiService">
  <osgi:interfaces>
     <value>com.xyz.MessageService</value>
     <value>com.xyz.MarkerInterface</value>
  </osgi:interfaces>
</osgi:reference>

interface 속성과 interfaces 엘리먼트를 둘 다 사용하는 것은 문법에 어긋나며, 항상 둘 중 하나만 사용하도록 한다.

reference 엘리먼트로 정의한 빈은 번들이 참조할 수 있는 서비스의 인터페이스들을 구현하고 있다.(greedy proxing 이라고 한다.) 만약 등록된 서비스 인터페이스가 자바 클래스 타입을 포함하고 있다면(인터페이스가 아니라), 해당 타입들은 스프링 AOP를 따르게 되ㅇㄴ다. 간략하게 말하자면, 명시된 인터페이스들이 인터페이스가 아니라 클래스라면, cglib이 반드시 가용한 상태여야 하며, final 메소드가 없어야 한다.

6.2.1.2. filter 속성

부가적인 속성 filter는 OSGi 필터 표현식을 명시하고 서비스 레지스트리 룩업을 할 때 오직 주어진 필터에 해당하는 것들에서만 찾도록 제약을 가할 수 있다.

<reference id="asyncMessageService" interface="com.xyz.MessageService"
  filter="(asynchronous-delivery=true)"/>

이것은 asynchronous-delivery 속성이 true이고 MessageService 인터페이스로 등록해둔 OSGi 서비스만 참조할 것이다.

6.2.1.3. bean-name 속성

bean-name 속성은 service 엘리먼트를 사용하여 공개한 빈의 이름에 해당하는 서비스를 찾아주는 필터 표현식의 단축키 정도에 해당한다.

<bean id="(1)messageServiceBean" scope="bundle" class="com.xyz.MessageServiceImpl"/>
<!-- service exporter -->
<osgi:service id="messageServiceExporter" ref="(1)beanToBeExported" interface="com.xyz.MessageService"/>

<osgi:reference id="messageService" interface="com.xyz.MessageService"
   bean-name="(1)messageServiceBean"/>

1    the name used with bean-name attribute

위에 선언한 reference 빈은 MessageService 인터페이스로 등록된 서비스 중에서 org.springframework.osgi.bean.name 속성에 이름이 messageServiceBean 인 OSGi 서비스를 찾는다. 다시 간략하게 말하자면, 모든 공개된 빈 중에서 MessageService 인터페이스를 구현했고, 빈의 이름이 messageService인 빈을 참조하게 된다.

6.2.1.4. cardinality 속성

cardinality 속성은 항상 해당하는 서비스가 존재해야 하는지 아닌지를 기술할 때 사용한다. cardinality 값이 1..1(이게 기본값) 이면 해당하는 서비스가 반드시 가용해야 한다는 것을 뜻한다. cardinality 값이 0..1이면, 해당하는 서비스가 항상 필요한 것은 아니라는 것을 뜻한다.(4.2.1.6에 자세히 나와있다.) reference에 cardinality 1..1로 설정되어 있는 것은 필수mandatory 서비스 레퍼런스라고도 하며, 기본적으로 해당 레퍼런스가 참조 가능할 때까지 애플리케이션 컨텍스트 생성이 지연된다.

노트

해당 번들 자신이 공개한 서비스를 필수 서비스 레퍼런스로 참조하는 것은 에러다. 이런 행위로 인해 애플리케이션 컨텍스트 생성이 데드락이나 타임아웃으로 실패하게 될 것이다.

6.2.1.5. depends-on 속성

dependes-on 속성은 서비스 레지스트리에서 해당 서비스 레퍼런스를 룩업하기 전에 이 속성에 명시한 빈을 먼저 생성하라는 것이다.

6.2.1.6. context-class-loader 속성

OSGi 서비스 플랫폼 코어 스펙(현재 4.1 작성중)에는 서비스 레지스트리에서 얻어온 서비스를 통하여 컨텍스트 클래스 로더에서 가용한 타입이나 리소스들을 명시하고 있지 않다. 따라서 어떤 서비스들은 컨텍스트 클래스 로더로부터 특정 라이브러리가 가용하리라고 예상하고 작성하기도 한다. 스프링 DM은 서비스 호출 시점에 컨텍스트 클래스 로더 제어대해 명시적으로 제어한다. reference 엘리먼트의 context-class-loader 속성으로 이를 달성할 수 있다.

context-class-loader에 가용한 값은 다음과 같다.
  • client - 서비스 호출 기간중에, 컨텍스트 클래스 로더는 서비스를 호출하고 있는 번들의 클래스패스에 있는 타입들을 볼 수 있다. 기본값이다.
  • service-provider - 서비스 호출 기간중에, 컨텍스트 클래스 로더는 서비스를 공개한 쪽 번들의 클래스패스에 있는 타입들을 볼 수 있다.
  • unmanaged - 서비스 호출 기간중에 컨텍스트 클래스 로더 관리를 하지 않음
6.2.1.7. reference 엘리먼트 속성

지금까지 살펴본 속성들 표 생략.

6.2.1.8. reference와 OSGi 서비스 동적특성Dynamics

reference 엘리먼트로 정의한 빈은 애플리케이션 컨텍스트의 생명주기 동안 바뀌지 않는다. 하지만, 해당 빈이 참조하는 OSGi 서비스는 언제든지 서비스 레지스트리에서 나가고 등록될 수 있다. 필수 서비스 레퍼런스(cardinality 1..1)인 경우에는, 해당 서비스가 가용할 떄 까지 애플리케이션 컨텍스트 생성을 일정 시간 지연시킨다. 부가 서비스 레퍼런스(cardinality 0..1)인 경우에는 현재 해당 서비스가 가용한지 여부와 관계없이 해당 빈이 바로 생성된다.

만약 참조해야 하는 서비스가 없어지면, 스프링 DM은 해당 reference에 정의한 것에 해당하는 다른 서비스로 기존 서비스를 교체 시도를 한다. 애플리케이션은 리스너를 등록하여 자신이 참조하는 서비스의 변경을 알아차려야 한다. 만약 해당하는 서비스가 없다면, reference는 unsatisfied가 되고, 이 reference에 의존하는 다른 공개된 서비스들을 해당 reference의 의존성이 해결될때까지 서비스 레지스트리에서 해지한다. 자세한건 6.5에서..

만약 unsatistied 상태인 reference 빈에 어떤 요청이 발생했다면, 해당 요청은 레퍼런스가 다시 satisfied 상태가 될때까지 잠시 대기시킨다. timeout 속성에 이 때 대기할 시간(millisesecond)을 설정할 수 있다. 몇시한 타임아웃 값이 지나고 나서도 해당 빈이 가용하지 않다면 ServiceUnavailableException을 던진다.

6.2.1.9. 관리하고 있는 서비스 레퍼런스 참조하기

스프링 DM은 자신이 관리하고 있는 서비스 레퍼런스를 ServiceReference 타입으로 자동변환해준다. 따라서, ServiceReference 타입의 속성을 가지고 있는 빈에 해당 서비스를 (명시된 인터페이스 타입이 아니라 ServiceReference 타입으로)injection 할 수 있다.

public class BeanWithServiceReference {
    private ServiceReference serviceReference;
    private SomeService service;
           
    // getters/setters ommitted
}

<reference id="service" interface="com.xyz.SomeService"/>
       
<bean id="someBean" class="BeanWithServiceReference">
  <property name="serviceReference" ref="service"/>                                      (1)
  <property name="service" ref="service"/>                                               (2)
</bean>

1    Automatic managed service to ServiceReference conversion.
2    Managed service is injected without any conversion

노트

주입된 ServiceReference 타입의 빈은 참조하고 있는 OSGi 서비스 객체가 바뀔 때마다 같이 바뀐다.

6.2.2. 서비스 콜렉션 참조하기


때때로 애플리케이션은 간단하게 특정 범위 중에서 하나의 서비스를 참조할 뿐만 아니라, 범위 해당하는 모든 서비스를 참조해야 할 때도 있다. 스프링 DM은 이를 List 또는 Set(정렬은 부가적으로) 엘리먼트로 지원한다.

List와 Set의 차이는 오직 동일성뿐이다. 레지스트리에 등록되어 있는 두 개 이상의 서비스들(각자 다른 서비스 id를 가지고 있을 것이다.)이 해당 서비스의 equals 메소드 구현에 따라 같을 수도 있는데. Set에는 그들 중에 하나만 가지고 있을 것이고, List는 전부다 반환해 준다.

set과 list 스키마 엘리먼트는 서비스 집합체를 나타낼 때 사용한다.

이 엘리먼트들도 interface, filter, bean-name, cardinality 그리고 context-class-loader를 지원한다. 단 cardinality의 값으로는 0..n 과 1..n 만 사용할 수 있다.

0..n은 해당 콜렉션에 대응하는 서비스가 하나도 없어도 상관없다는 것이고 1..n은 필수 레퍼런스를 나타낸다.

list는 java.util.List 타입으로 정의되고, set 엘리먼트는 java.util.Set 타입의 빈으로 정의된다.

다음의 예제는 EventListener 인터페이스를 구현한 모든 등록된 서비스들을 List 타입으로 반환할 것이다.

<list id="myEventListeners" interface="com.xyz.EventListener"/>

리스트의 요소들은 스프링에의해 동적으로 관리될 것이다. 대응하는 서비스가 레지스트리에 등록되고 해지됨에 따라 콜렉션의 구성요소도 갱신될 것이다.

스프링 DM은 정렬된 콜렉션도 지원한다. set과 list 둘다.

정렬하는 방법은 두 가지인데, 하나는 Comparator를 사용하는 방법(custom ordering)이고 다른 하나는 Comparable 인터페이스를 구현한 것 끼리 비교하는 것(natural ordering)이다.

6.2.2.1. Greedy Proxing

스프링 DM 서비스 콜렉션으로 가져온 모든 OSGi 서비스는 interface 속성에 설정한 클래스에 타입 호환가능하다. 하지만, 때때로 서비스가 부가적으로 설정한 클래스들을 사용하고 시을 수 있다.

그런 경우, 스프링 DM 콜렉션은 greedy-groxing 속성을 지원하는데, 이 속성을 사용하여 참조하는 서비스에 부가적으로 설정한 모든 클래스들을 사용할 수 있도록 프록시들을 생성하게 할 수 있다. 따라서, 가져온 프록시를 interface에 설정한 클래스가 아닌 다른 타입으로 캐스팅을 할 수 있다. 다음의 예제를 보자.

<list id="services" interface="com.xyz.SomeService" greedy-proxying="true"/>

다음과 같이 할 수 있다.

for (Iterator iterator = services.iterator(); iterator.hasNext();) {
    SomeService service = (SomeService) iterator.next();
    service.executeOperation();
    // if the service implements an additional type
    // do something extra
    if (service instanceof MessageDispatcher) {
        ((MessageDispatcher)service).sendAckMessage();
    }
}

노트

greedy proxy와 instanceof를 사용하기 전에 다른 인터페이스나 클래스 사용을 고려해 보아라. 보다 나은 다형성과 객체 지향 스러운 서비스를 구성할 수 있을 것이다.

6.2.2.2. 콜렉션(list와 set) 엘리먼트 속성

timeout 이 없는거만 뺴면 reference 랑 똑같다.

6.2.2.3. list/set 그리고 OSGi 서비스 동적특성

OSGi 서비스들의 집합은 OSGi 공간의 상태를 반영해야 하기 때문에 애플리케이션 컨텍스트의 라이프사이클 동안 계속해서 변한다. 서비스가 등록되고 해지되는 동안 콜렉션에 해당 서비스들이 추가 또는 삭제 된다.

reference 선언은 자신이 참조하는 서비스가 해지 되면 대체제를 찾는 반면, 콜렉션은 그냥 서비스를 콜렉션에서 제거한다. reference와 마찬가지로, 1..n 인 cardinality는 필수 레퍼런스라고 하며, 0..n은 부가적인 레퍼런스라고 한다. 만약에 대응하는 서비스가 없다면 필수 콜렉션만 unsatisfied 상태가 되고 ServiceUnavailableException을 던진다.

6.2.2.4. Iterator 제약사항과 서비스 콜렉션

콜렉션을 순회하는 방법중에 권장하는 방법은 Iterator를 사용하는 것이다. 하지만, OSGi 서비스는 언제든지 등록되고 해지될 수 있으므로, 콜렉션 또한 그에 따라 변경되어야 한다. 스프링 DM은 깔끔하게Transparenlty 사용자가 참조하는 모든 Iterator들을 수정해 준다. 따라서 사용자는 콜렉션이 변경되는 와중에도 안전하게 순회할 수 있다. 게다가, 그 Iterator들은 콜렉션의 모든 변경 사항을 반영한다. 변경이 Iterator 객체를 만든 후에 발생했더라도 반영된다. 만약 순회를 시작하자 마자 서비스들이 왕창 내려갔다고 했을때, 이 상태에서 순회를 계속하면 "죽은" 서비스들을 호출하게 될 것이다. 스프링 DM은 그래서 이 Iterator들이 스냅샷이 아니라 가장 최신 콜렉션 상태를 반영한 것이 된다. 순회가 얼마나 빠르고 느리냐는 상관없다.

서비스 수정은 Iteraor에서 순회하기 전에 있는 것들에만 반영이 된다는 것에 주의하자. 이미 순회를 마친 서비스에는 어쩔 도리가 없다. 만약 이미 해지된 서비스에 어떤 동작을 요구한다면 ServiceUnavailableException이 발생한다.

정리하자면, reference 선언은 자신이 참조하는 서비스가 해지되면 대체제를 찾지만 콜렉션은 대체제를 찾지 않는다. 그냥 자신의 콜렉션에서 해당 서비스를 제거할 뿐이다. 다음 순회할 때 그들을 사용하지 않도록.

Iterator 제약사항은 next() 메소드가 항상 hasNext() 호출 결과를 따른다는 것을 알아두자.

hasNext()가 true일 때 next()를 하면 항상 null이 아닌 값을 반환한다.
hasNext()가 false일 때 next()를 하면 NoSuchElementException을 던진다.

간단하게 Iterator를 리프레쉬하려면 hasNext()를 다시 호출하면 된다. 그럼 Iterator가 현재 콜렉션 에서 다음 순회 엔트리를 확인할 것이다.

6.2.3. 가져온import OSGi 서비스의 동적특성 다루기

reference나 set, list를 사용할 때 스프링 DM이 뒷단의 서비스를 관리할 것이다. 하지만, 하지만 때론 애플리케이션이 뒷단의 서비스 변경을 알고 싶을 수도 있다.

언제 reference 빈이 묶이고 풀리는지 알고 싶은 그런 애플리케이션들은 내부 엘리먼트로 하나 이상의 listener 엘리먼트를 등록할 수 있다. 이 엘리먼트는 reference, set, list에서 사용할 수 있다. 서비스 공개 리스너 설정과 비슷하다. listener 엘리먼트에 org.springframework.osgi.service.importer.OsgiServiceLifecycleListener 인터페이스를 구현한 빈을 참조하도록 설정하면, 해당 인터페이스의 bind와 unbind 메소드를 호출하게 된다. 커스텀 바인드 언바인드 메소드를 사용하려면 메소드 이름을 사용하면 된다.

<reference id="someService" interface="com.xyz.MessageService">
  <listener ref="aListenerBean"/>
</reference>

<reference id="someService" interface="com.xyz.MessageService">
  <listener bind-method="onBind" unbind-method="onUnbind">
     <beans:bean class="MyCustomListener"/>
  </listener>
</reference>

만약 OsgiServiceLifecycleListener와 커스텀 메소드 둘다 등록되어 있다면 인터페이스 구현체 먼저 호출하고 그 다음 커스텀 메소드를 호출한다.

커스텀 메소드의 시그너쳐는 다음과 같다.

public void anyMethodName(ServiceType service, Dictionary properties);

public void anyMethodName(ServiceType service, Map properties);

public void anyMethodName(ServiceReference ref);

ServiceType 자리에는 어떤 타입이든 선언할 수 있다. 해당 타입에 해당하는 서비스가 묶이거나 풀릴때 호출된다. 만약 모든 타입에 대해 콜백을 호출하고 싶으면 java.lang.Object 타입으로 선언하면 된다.

properties 파라미터는 등록된 서비스가 가지고 있는 속성들의 집합을 나타낸다.

리스너가 reference에 등록되어 있다면:
  • 레퍼런스가 초기에 서비스와 묶일 때와 서비스가 새로운 서비스로 교체될 때마다 bind 메소드가 실행된다.
  • 현재 서비스가 해지되거나, 그 즉시 교체가능한 대체 서비스가 없을 때 unbind 콜백이 호출된다.(물론 해당 reference는 unsatisfied 상태가 된다.)
리스너가 콜렉션에 등록되어 있다면:
  • 새로운 서비스가 콜렉션에 추가되면 bind 메소드를 호출한다.
  • 서비스가 해지되고 콜렉션에서 제거될 때 unbind 메소드를 호출한다.
콜렉션에는 서비스 교체가 없다는 것을 주목하라. 콜렉션은 그냥 서비스를 추가하고 제거할 뿐이다.

뒷단의 OSGi 서비스에 대한 OSGi serviceChanged 이벤트 처리의 일부로 바인드와 언바인드 콜백은 동기적으로 처리된다.

아래의 테이블은 reference listener 서브 엘리먼트로 가용한 속성들이다.

생략

6.2.4. 리스너와 서비스 프록시들


임폴트 리스너들은 특정 시점에 묶이는 OSGi 서비스에 접근할 수 있는 방법을 제공하지만, 여기서 중요한 것은 해당 메소드로 넘어온 아규먼트가 실제 서비스 객체가 아닌 프록시라는 것이다. 프록시를 사용하는 이유는 언제 어떻게 바뀔지 모른느 객체에 대하여 강력한 레퍼런스를 가지는 것을 방지하기 위함이다. 서비스들을 추적하는 것이 주목적인 리스너들은 instance equality나 object equlity에 연연해서는 안된다. 이 들 메소드가 해당 인터페이스나 클래스의 public 메소드로 구현한 것이 아니라면, 프록시의 메소드가 호출될 것이다.

따라서 추적은 그냥 서비스 인터페이스나, 서비스 속성(org.osgi.framework.Constants#SERVICE_ID 참조) 또는 서비스 노티(바인드/언바인드)로만 하는 것을 추천한다.

6.2.5. 호출하는 BundleContext에 접근하기


가져온 서비스가 특정 시점에 어떤 번들을 사용하고 있는지 알고 싶을 수 있다. 이런 시나리오를 돕기 위해, 스플이 DM이 가져온 서비스는 가져온 번들 BundleContext를 LocalBundleContext 클래스로 공개한다. 가져온 것에 대한 메소드가 호출될 때마다, ThreadLocal을 사용하여 호출하는 BundleContext를 사용할 수 있다. getInvokerBundleContext()를 통해서..

단 이걸 사용할 때 해당 클래스가 스프링 DM 코드에 의존하게 된다는 것을 주의해야 한다.
신고
top


6.1. Exporting a Spring bean as an OSGi service

Spring DM/Chapter 6 : 2008.06.04 23:50


service 엘리먼트를 사용해서 OSGi 서비스로 공개할 빈을 설정할 수 있다. 최소한 공개시킬 빈과 서비스 인터페이스를 설정해야 한다.

<service ref="beanToPublish" interface="com.xyz.MessageService"/>

위의 설정은 beanToPublish라는 빈을 com.xyz.MessageService 인터페이스를 통해서 사용할 수 있도록 서비스로 공개하겠다는 것이다. 그렇게 공개한 서비스는 org.springframework.osgi.bean.name 이라는 속성을 타겟 빈의 이름(여기서는 beanToPublish)을 설정한다.

서비스 엘리먼트로 정의한 빈은 org.osgi.framework.ServiceRegistration 타입의 빈이고 즉 서비스 레지스트리에 ServiceRegistration 객체가 등록된다. 이 빈에 id를 설정하고 다른 빈에서 해당 ServiceRegistration 객체를 참조 하도록 설정할 수 도 있다.

<service id="myServiceRegistration" ref="beanToPublish"
    interface="com.xyz.MessageService"/>

서비스로 공개할 빈 이름을 참조하는 대신에 서비스 빈 내부에 익명 내부 빈으로 등록할 수도 있다. 최상위 네임스페이스가 bean일 경우에 아래와 같을 것이다.

<osgi:service interface="com.xyz.MessageService">
  <bean class="SomeClass">
     ...
  </bean>
</osgi:service>

org.osgi.framework.ServiceFactory 인터페이스
를 구현한 빈을 공개하면 OSGi Service Platform Core Specification 5.6에 있는 ServiceFactory 제약대로 동작한다.(해당 서비스 객체를 요구할 때마다 서비스팩토리에서 만들어서 줌) OSGi API를 구현하는 대신, 스프링 DM이 도입한 새로운 bean 스콥을 사용할 수도 있다. bundle 스콥으로 해당 빈을 이 스콥으로 OSGi 서비스로 공개하면 각각의 클라이언트(OSGi 서비스 레지스트리에서 서비스를 import하는 번들들)마다 독립적인 객체를 만들어서 제공해 줄 것이다. 해당 빈을 서비스로 임포트한 번들이 동작을 멈추면, 해당 빈 객체는 사라질 것이다. bundle 스콥을 사용하려면 다음과 같이 설정하면 된다.

<osgi:service ref="beanToBeExported" interface="com.xyz.MessageService"/>

<bean id="beanToBeExported" scope="bundle" class="com.xyz.MessageServiceImpl"/>

6.1.1. Controlling the set of advertised service interfaces for an exported service

OSGi 서비스 플랫폼 코어 스팩에는 "서비스 인터페이스"라는 용어를 정의하고 있는데, 이는 서비스의 public 메소드들 규약을 표현하는 용어다. 일반적으로 자바 인터페이스가 되지만, 스펙에서는 클래스 이름으로 서비스 객체를 등록 할 수도 있도록 지원한다. 따라서, "서비스 인터페이스"라는 말은 클래스와 인터페이스 둘 모두를 가리킬 수 있다.

공개할 서비스의 서비스 인터페이들을 기술하는데 몇가지 옵션들이 있다. 가장 간단하게는 interface 속성에 전체 페키지 경로가 붙은 인터페이스 이름을 설정할 수 있다. 해당 서비스를 여러 인터페이스에 등록하려면 interfaces라는 내부 엘리먼트를 사용한다.

<osgi:service ref="beanToBeExported">
  <osgi:interfaces>
     <value>com.xyz.MessageService</value>
     <value>com.xyz.MarkerInterface</value>
  </osgi:interfaces>
</osgi:service>

동시에 둘 다 사용하는 것은 문법에 어긋난다. 둘 중 하나만 사용하라.

6.1.1.1. Detecting the advertised interfaces at runtime

auto-export  속성을 사용하면 명시적으로 서비스 인터페이스들을 등록할 필요가 없다. 스프링 DM이 클래스 상속구조와 인터페이스를 분석하여 설정할 것이다.

auto-export 속성은 네 개중 하나의 값을 가질 수 있다.
  • disabled: 기본값으로, 자동으로 찾지 않으므로, interface 또는 interfaces 설정을 해야 한다.
  • interfaces: 해당 빈이 구현한 모든 인터페이스를 등록한다.
  • class-hierarchy: 빈이 구현한 모든 타입과 슈퍼 타입을 등록한다.
  • all-classes: 위에 두개 합친거

auto-export와 interfaces 옵션은 상호배타적이지 않다. 두 설정을 동시에 사용할 수 있다. 하지만, 대부분의 경우 다음의 설정이 유용할 것이다.

<service ref="beanToBeExported" auto-export="interfaces"/>

이렇게 설정하여 인터페이스 상속구조에서 모든 인터페이스 타입으로 서비스를 참조할 수 있다.

public interface SuperInterface {}

public interface SubInterface extends SuperInterface {}

이런 코드에서 SupoerInterface로 등록한 서비스는 SubInterface로 참조할 수가 없는데, 이런 이유로 인해 해당 서비스에 auto-export="interfaces"로 설정하여 모든 인터페이스를 지원하도록하는 것이 베스트 프랙티스다.

6.1.2. 공개할 서비스에 프로퍼티 설정하기

앞서 언급했듯이, 공개한 서비스는 항상 org.springframework.osgi.bean.name 서비스 속성을 공개할 빈의 이름으로 설정되어 있다. service-properties 내부 엘리먼트를 사용하여 부가적인 속성을 설정할 수 있다. service-properties 엘리먼트는 키-값 쌍을 가지고 있는데 이는 서비스에서 속성을 사용할 수 있다. 키는 반드시 문자열이어야 하고 값은 OSGi 필터가 인식할 수 있는 타입이어야 한다. OSGi 서비스 플랫폼 코어 스팩 5.5를 보면 필터 표현식과 프로퍼티 값이 어떻게 대응하는지 참조할 수 있다.

service-properties 엘리먼트는 반드시 최소한 하나의 entry 엘리먼트를 가지고 있어야 한다.

<service ref="beanToBeExported" interface="com.xyz.MyServiceInterface">
  <service-properties>
    <beans:entry key="myOtherKey" value="aStringValue"/>
    <beans:entry key="aThirdKey" value-ref="beanToExposeAsProperty"/>
  </service-properties>
</service>

스프링 DM 로드맵에는 OSGi Configuration Administration 서비스에 안에 등록되어 있는 속성들을 등록된 서비스의 속성으로 공개하는 기능을 포함하고 있다. Appendix F. 로드맵에 자세한 내용이 있다.

6.1.3 depends-on 설정

스프링은 명시적으로 서비스 요소들간의 의존성을 관리한다. 예를 들어 서비스로 공개한 빈이 공개하기 전에 완전히 설정을 마치고 만든 다음에 공개한다. 만약에 서비스가 다른 컴포넌트(다른 서비스를 포함한)에 의존성을 가지고 있다면 단드시 해당 서비스를 공개하기 전에 그것들을 초기화 해야 하는데, 그럴 때 depends-on 속성을 사용여 그들의 의존성을 표현할 수 있다.

<service ref="beanToBeExported" interface="com.xyz.MyServiceInterface"
     depends-on="myOtherComponent"/>

6.1.4 context-class-loader 속성

OSGi 서비스 플랫폼 코어 스펙(현제 4.1이 작성 중이다.)에는 서비스 레지스트리에서 받아온 서비스에 어떤 요청을 했을 때 context class loader를 통해서 가용한 리소스나 타입을 명시하고 있지 않다. 따라서, 몇몇 서비스들은 context class loader에 특정 가정을 한 상태에서 라이브러리를 사용하고 있다. 스프링 DM은 서비스 실행 중에 context class loader를 명시적으로 제어할 수 있는 방법을 제공한다. context-class-loader 속성을 통해 제어할 수 있다.

context-class-loader 속성에는 unmanaged(기본값)와 service-provider를 사용할 수 있다. service-provider 값을 사용하여 스프링 DM으로 하여금 context class loader가 번들이 공개한 서비스의 클래스패스에 있는 모든 리소스를 참조할 수 있다는 것을 보장해준다.

context-class-loader를 service-provider로 설정하면, 클래스로더를 다루기 위해 서비스 객체가 프록시로 된다. 이 때 만약 서비스가 구현 클래스 일 경우 CGLIB을 필요로 한다.

6.1.5. ranking 속성

서비스 레지스틀에 여러 개의 같은 종류의 서비스가 존재할 경우, 우선 순위가 높은 서비스를 사용하게 된다.(OSGi 서비스 플랫폼 스펙 5.2.5) 이 값을 ranking 속성으로 설정할 수 있다. 기본값은 0

<service ref="beanToBeExported" interface="com.xyz.MyServiceInterface"
  ranking="9"/>

6.1.6. service 엘리먼트 속성

요약할 겸, 위에서 살펴본 모든 속성들과 그 값들을 표로 나타내면 다음과 같다.

[표 생략]

6.1.7. 서비스 등록과 해지 라이프사이클

service 엘리먼트로 등록된 서비스느는 애플리케이션 컨텍스트가 처음 만들어 질때 OSGI 서비스 레지스크리에 등록된다. 번들이 멈추면 서비스가 자동적으로 해지되고 애플리케이션 컨텍스트가 소멸한다.

만약 의존성이 충족되지 않아서 등록시 또는 해지시에 어떤 행위를 해야하는 상황이 필요할 수 있다. 그럴 때는 registration-listener 엘리먼트를 사용해서 리스너 빈을 정의할 수 있다.

<service ref="beanToBeExported" interface="SomeInterface">
  <registration-listener ref="myListener"                                                (1)
    registration-method="serviceRegistered"                                              (2)
    unregistration-method="serviceUnregistered"/>                                        (2)
  <registration-listener
     registration-method="register">                                                     (3)
     <bean class="SomeListenerClass"/>                                                   (4)
  </registration-listener>
</service>

(1) 최상위 빈 정의를 참조하는 리스너 선언
(2) 등록과 해지 메소드 설정
(3) 해당 리스너의 등록 메소드만 설정
(4) 내부 리스너 빈 등록

registration-method와 unregistration-method 속성은 리스너 빈에 정의한 메소드 이름을 나타내고 이들은 등록 및 해지시에 자동으로 호출된다. 등록과 해지는 콜백 메소드로 반드시 다음의 시그너처 중 하나를 따라야 한다.

public void anyMethodName(ServiceType serviceInstance, Map serviceProperties);

public void anyMethodName(ServiceType serviceInstance, Dictionary serviceProperties);

serviceType은 공개할 서비스의 인터페이스에 상응하는 어떤 타입이든지 될 수 있다.

등록 콜백은 서비스가 초기에 시작시 등록될 때 호출되고, 계속해서 다시 등록될 때마다 호출된다. 해지 콜백은 이유에 상관없이 서비스 해지 과정 중에 호출된다.

스프링 DM은 ServiceType 인자 타입을 보고 그에 상응하는 서비스가 등록/해지 될 때에만 등록/해지 메소드를 호출한다.

serviceProperties는 등록/해지 서비스의 모든 속성을 담고 있는 맵을 나타낸다. OSGi 스펙에 호환하기 위해 이 인자는 필요시에 java.util.Dictionary로 캐스팅될 수도 있다.

6.1.7.1. OsgiServiceRegistrationListener 인터페이스

위에서 설명한 방법말고 OsgiServiceRegistrationListener 인터페이스를 직접 구현하는 방법도 있는데, 이렇게 하면 XML 설정은 줄어드는 대신 스프링 DM에 종속적인 코드가 생긴다.

둘 다 사용할 수 있는데, 그럴 때는 먼저 OsgiServiceRegistrationListener 인터페이스의 메소드가 먼저 호출되고, 그 다음 커스텀 메소드가 호출된다.

ps: 왜이리 길어...
신고
top


Chapter 6. The Service Registry

Spring DM/Chapter 6 : 2008.06.02 00:01


OSGi 서비스 레지스트리는 번들이 객체를 공유 레지스트리로 공개할 수 있고 이를 인터페이스를 통해 접근하도록 하는 기반 시설이다. 그렇게 공개된 서비스들은 레지스트리 내부에서 그들과 관련된 서비스 속성들을 가지고 있다.

스프링 DM은 osgi 네임스페이스를 제공하여 스프링이 빈을 OSGi 서비스로 공개할 수 있도록 한다. osgi 네임스페이스는 다른 최상위 네임스페이스 내부에 선언해도 되고, 최상위 네임스페이스로 사용해도 된다.

OSGi 관련 설정을 한 곳에 모아둔 osgi 네임스페이스를 최상위 네임스페이스로 사용하는 것이 편하다.(5.1 참조)
신고
top


5.7. Diagnosing problems

Spring DM/Chapter 5 : 2008.05.25 22:40


여러분이 사용하기로 선택한 OSGi 플랫폼 구현체는 현제 OSGi 환경 상태에 대한 정보를 잘 제공해 주어야 한다. 예를 들어, -console 아규먼트를 Equinox 시작시 추가하면 커맨드 라인 콘솔을 제공한다. 이것을 통해 어떤 번들들이 설치되어 있고 그들의 상태와, 해당 번들에 의해 공개된 패키지와 서비스, 번들 Resolve 실패 원인, 번들 라이프사이클 다루기 등을 할 수 있다.

게다가, 스프링 자체와 스프링 DM 번들은 문제의 원인을 조사할때 사용할 수 있는 확장 가능한 로깅 체계가 마련되어 있다. Simple Logging Facade for Java(slf4j) slf4j.jar 와 slf4j-log4j13.jar 번들을 설치하길 권장한다. 그렇게만 하면, 번들 클래스패스 루트에 log4j.properties 파일을 생성하여 사용할 수 있다.

스프링 DM 모듈은 commons-logging API를 내부적으로 사용하고 있는데, 이것은 로깅 구현체가 완전히 끼워맞출 수 있는pluggble 형태로 개발되었다는 것을 의미한다.
신고
top


5.6. Considerations when using external libraries

Spring DM/Chapter 5 : 2008.05.24 23:08


대부분의 엔터프라이즈 애플리케이션 라이브러리들은 context class loader를 통해서 타입과 리소스를 로딩할 수 있다고 가정한다. 보통 개발자가 이 것을 직접 다루지는 않지만, 애플리케이션 서버, 컨테이너 또는 멀티 쓰레드로 동작하는 애플리케이션들은 context class loader를 사용하고 있다.

OSGi R4에서는 context class loader를 통해 가용한 타입이나 리소스 집합에 대해 정의되어 있지 않다. 이것은 OSGi 플랫폼이 쓰레드 context class loader 값을 보장하지 못한다는 것이고 다시 말하자면, ccl을 관리하지 않는다는 것이다.

따라서 클래스 로딩을 하거나 동적으로 새로운 클래스를 생성하는 코드가 OSGi 환경에서는 제대로 동작하지 않을 수 있다.

스프링 DM은 해당 번들의 application context를 생성하는 도중에 번들의 클래스패스에서 가용한 모든 타입과 리소스들을 ccl을 통해 접근할 수 있도록 보장한다. 또한 스프링 DM은 외부 서비스를 호출할 때와 공개한 서비스에 대한 요청에 서비스를 할 때 CCL을 통해서 접근 가능한 클래스와 리소스를 설정할 수 있다. 방법은 5.5에서 설명했다.

OSGi R5에서는 제 3의 라이브러리에 의해 추가된 암묵적인 클래스 패스와 생성된 클래스를 지원하기 위한 스펙을 정하고 있다. 그전까지는 DynamicImport-Package manifest 헤더를 사용하거나,  Equinox의 버디buddy 매커니즘을 사용할 수 있을 것이다.
신고
top


5.4. Spring XML authoring support

Spring DM/Chapter 5 : 2008.05.19 22:44


스프링 2.0은 보다 쉬운 XML 설정과 확장 가능한 XML을 도입했다. 이 중 후자는 커스텀 스키마를 만들어 스프링 XML 인프라가 자동으로 해당 설정을 읽을 수 있는 것이 가능해졌다. 그냥 그것들을 클래스패스에 두기만 하면 된다.(이 부분은 토비 사부님이 1회 KSUG에서 발표하셨던 내용) 스프링 DM은 이 기본 지식을 활용해서 OSGi 환경에서 부가적인 코드나 menifest 선언 필요 없이 커스텀 스키마를 사용할 수 있도록 했다.

Spring DM은 OSGi 공간에 배포되는 모든 번들(스프링 DM 번들이든 아니든 상관없이)들을 조사하여 커스텀 스프링 네임스페이스 선언을 가지고 있는지 스캔한다.(META-INF/spring.handlers 와 META-INF/spring.schemas 번들 영역을 확인한다.) 만약에 해당하는 선언을 찾으면, 스프링 DM은 해당 스키마를 만들고 해당 네임스페이스는 OSGi 서비스를 통해서 자동으로 스프링 번들에 의해 사용이 가능해진다

=> 즉, 커스텀 스키마를 사용하는 번들을 배포할 때 필요한 건, 네임스페이스 파서와 스키마를 제공하는 라이브러리를 OSGi 플랫폼에 배포하기만 하면 된다는 것이다.

번들의 클래스 패스 내부에 있는 커스컴 스키마는 OSGi 공간에서 다른 번들들에 의해 사용될 수 있다. 하지만, 번들 내부 라이브리의 네임스페이스는 다른 번들들에의해 공유되지 않는다. 다른 번들들이 볼 수 없다.

=> 번들로 배포된 네임스페이스만 공개 되고, 내장된 라이브러리의 네임스페이스는 공개하지 않음.

스프링 DM을 사용하면, 커스컴 네임스페이스 기능을 어떠한 부가작없도 필요없이 투명하게 지원한다. 내장된 네임스페이스 제공자(Embedded namespace provider)들은 우선권을 가지지만 공유하지는 않는다. 이와 반대로 번들로 배포된 제공자(providers deployed as bundle)들은 다른 번들들에서 참조할 수 있다.
신고
top


Spring DM에 Spring MVC 연동 기능 추가됨.

Spring DM/etc : 2008.04.29 21:31


참조 : http://static.springframework.org/osgi/docs/1.1.0-m2/reference/html/web.html#web:spring-mvc

1.1.0 M2가 나왔습니다. 눈에 띄는 변화는 단연 Web쪽 기능 추가. 자세한 내용은 레퍼런스를 보라고하지만, 레퍼런스보다 예제코드가 더 배고픈데 말이죠.

오늘 밤은 스프링 DM과 함께~


스프링은 역시 멋져부러~
신고
top







티스토리 툴바