년도별 글 목록: 2008

OSGi 시작하기 6 – 동적으로 서비스 추적하기 : [번역] Dynamic Service Tracking

이 글은 Neil Bartlett 의 연재 글 “Getting started with OSGi”의 번역본입니다.
* 파트 1 – 첫번째 번들 : Your First Bundle
* 파트 2 – 프레임워크와 연동하기 : Interacting with the Framework
* 파트 3 – 번들간의 의존관계 : Dependencies between bundles
* 파트 4 – 서비스 등록하기 : Registering a Service
* 파트 5 – 서비스 사용하기 : Consuming a Service
에 이어 6번째 글입니다. 오탈자 및 이상한 번역은 댓글로 남겨주세요

Getting started with OSGi : OSGi 시작하기 파트 6 – 동적으로 서비스 추적하기

저자 : Neil Bartlett < njbartlett at gmail dot com >
역자 : 권 정혁 < guruguru at gmail dot com >

글원본 : http://www.eclipsezone.com/eclipse/forums/t91059.html – Getting started with OSGi : Dynamic Service Tracking

EclipseZone OSGi 미니 시리즈에 돌아오신걸 환영합니다.

지난번에는 Martin Fowler 의 시나리오(특정감독에 의해 제작된 영화를 찾는 MovieFinder 에 의존하는 MovieLister)를 이용해서 어떻게 서비스를 사용하는지를 알아봤습니다. 또한, MovieLister MovieFinder 의 인스턴스를 찾지 못할때 무엇을 해야하는지를 통해 동적인 OSGi 서비스의 본질에 대해 살펴보았습니다.

우리가 지난번에 고려하지 않았던 다른 것이 있습니다. 만약 한개 이상의 MovieFinder가 있다면? 즉, 어떤 번들이라도 MovieFinder 인터페이스를 구현하는 서비스를 등록할수 있고, 레지스트리 입장에선 모든 번들은 같습니다.

우린 문제를 간단히 무시할 수도 있고, 실제로 지난번엔 그렇게 했습니다. ServiceTracker 에게 getService()를 호출함으로써, 우린 서비스 레지스트리에 의해 선택된 임의의 MovieFinder 인스턴스를 받게 됩니다. 이 선택에 영향을 줄수있는 여러가지 방법이 있지만(예를 들어, SERVICE_RANKING 속성을 서비스 등록시에 지정함으로써), 사용자로서의 우리는 이 선택에 대한 완벽한 조정능력을 가지지는 못합니다. 그리고 실제로 더 많은 조정능력을 가지게 되는것은 좋은게 아닙니다. 즉 우리는 MovieFinder 의 어떤 인스턴스라도 사용할수 있어야 한다는것이죠. 우리가 처음부터 인터페이스를 사용하는 이유이기도 합니다.

대신에 여러개의 서비스 인스턴스들에 대해 인지하고 사용하는 것은 때때로 유용할수도 있습니다. 예를 들어, 여러개의 MovieFinder 인터페이스가 가용하다면 MovieLister 가 이용할수 있는 영화 데이타에 대한 여러개의 소스가 있다는것을 의미합니다. 검색시에 이들을 모두 이용함으로써, 더 넓고 유용한 검색결과를 사용자에게 제공할 수 있게됩니다.

마지막에 논의했던 문제로 다시 돌아가서, 만약 MovieFinder 서비스가 사용 불가하다면 어떤일을 하는것이 맞을까요 ? 우린 MovieFinder 가 가용하지 않을때 listByDirector 메소드가 호출될때마다 null 을 리턴하는 간단한 방법을 사용했습니다. 하지만 MovieFinder 가 존재하지 않는다면 MovieLister 의 메소드 호출도 볼가능하게 하면 어떨까요 ?

MovieListerMovieFinder 와 마찬가지로 서비스입니다. 만약 MovieFinder 서비스가 사라진다면, MovieLister 도 같이 사라지게 하는건 ? 다시 말해, 우린 MovieLister 서비스가 MovieFinder 에 대해 “1 대 다” 관계를 가지기를 원했습니다. 마지막 튜토리얼에서 우린 “0 대 1” 관계였습니다.

MovieListerImpl 를 변경해봅시다. 아래 코드와 교체하세요.

package osgitut.movies.impl;
import java.util.*;
import osgitut.movies.*;
public class MovieListerImpl implements MovieLister {
  private Collection finders =
   Collections.synchronizedCollection(new ArrayList());
  protected void bindFinder(MovieFinder finder) {
   finders.add(finder);
    System.out.println("MovieLister: added a finder");
 }
  protected void unbindFinder(MovieFinder finder) {
   finders.remove(finder);
   System.out.println("MovieLister: removed a finder");
 }
  public List listByDirector(String director) {
    MovieFinder[] finderArray = (MovieFinder[])
     finders.toArray(new MovieFinder[finders.size()]);
    List result = new LinkedList();
    for(int j=0; j < finderArray.length; j++) {
      Movie[] all = finderArray[j].findAll();
      for(int i=0; i < all.length; i++) {
        if(director.equals(all[i].getDirector())) {
          result.add(all[i]);
       }
     }
   }
   return result;
 }
}

이제 우린 MovieListerImpl 에서 OSGi 에 대한 의존성을 없앴습니다. 이젠 순수 POJO 입니다. 어쨋든, 이 클래스는 누군가 또는 어떤것이 MovieFinder 서비스를 찾아서 bindFinder 메소드를 통해 제공되어야 합니다. 이렇게 하기위해서 osgitut/movies/impl/MovieFinderTracker.java 라는 새로운 파일을 아래와 같이 작성합니다.

package osgitut.movies.impl;
import org.osgi.framework.*;
import org.osgi.util.tracker.*;
import osgitut.movies.*;
public class MovieFinderTracker extends ServiceTracker {
  private final MovieListerImpl lister = new MovieListerImpl();
  private int finderCount = 0;
  private ServiceRegistration registration = null;
  public MovieFinderTracker(BundleContext context) {
   super(context, MovieFinder.class.getName(), null);
  }
  private boolean registering = false;
  public Object addingService(ServiceReference reference) {
   MovieFinder finder = (MovieFinder) context.getService(reference);
    lister.bindFinder(finder);
    synchronized(this) {
     finderCount ++;
      if (registering)
        return finder;
      registering = (finderCount == 1);
      if (!registering)
       return finder;
    }
   ServiceRegistration reg = context.registerService(
   MovieLister.class.getName(), lister, null);
    synchronized(this) {
     registering = false;
      registration = reg;
    }
   return finder;
  }
 public void removedService(ServiceReference reference, Object service) {
   MovieFinder finder = (MovieFinder) service;
    lister.unbindFinder(finder);
   context.ungetService(reference);
    ServiceRegistration needsUnregistration = null;
   synchronized(this) {
     finderCount --;
      if (finderCount == 0) {
       needsUnregistration = registration;
        registration = null;
      }
    }
   if(needsUnregistration != null) {
      needsUnregistration.unregister();
    }
  }
}

이 클래스는 지난번에 얘기했던 ServiceTracker 클래스를 오버라이드 해서, ServiceTracker 가 서비스 등록/삭제시 동작하는 방식을 커스터마이즈 합니다. 특징적으로, MovieFinder 서비스가 추가될때 addingService 메소드가 호출되고 , MovieFinder 가 제거될때 removedService 가 호출됩니다. 우리가 오버라이드 할수 있는 메소드중에 modifiedService 도 잇습니다만 여기선 필요하지 않습니다.

이 두개의 메소드에 대해선 살펴볼만한 가치가 있습니다. 첫째로 addingService 에선 전달받은 인자가 실제 서비스 구현 개체가 아니라 ServiceReference 입니다. ServiceReference는 인자로 전달될수 있는 가벼운 핸들이며, 서비스에 대한 속성(서비스 등록시에 전달했던)를 읽는데 사용이 가능합니다. 결정적으로, ServiceReference 를 얻는것은 OSGi 프레임워크가 해당 서비스의 레퍼런스 카운트를 증가시키지 않습니다. Java Reflection API 에 있는 WeakReference 클래스와 비슷하게 생각하시면 됩니다.

예제에서 우리가 ServiceReference 로 할 첫번째 작업은 MovieFinder 서비스 개체를 얻는것입니다. 이를 위해서 우린 다시 BundleContext 를 필요로 합니다. (OSGi 프레임워크와 관련된 모든 작업은 BundleContext 인터페이스를 통해 이뤄진다는걸 명심하세요. ) 편리하게도 슈퍼클래스인 ServiceTracker BundleContext 에 대한 레퍼런스를 context 라고 이름붙인 protected 멤버로 가지고 있으므로 바로 사용할 수 있습니다.

다음으로 우리가 위에서 정의한 MovieListImpl bindFinder 메소드를 가지고 파인더를 바인딩 합니다. 그리고 MovieListerImpl 자체를 MovieLister 인터페이스로 서비스에 등록합니다. 이미 서비스가 등록되지 않았을때만 서비스를 등록하고 있다는 걸 주의하세요. 이번 시나리오 에선 한개의 MovieLister 가 여러개의 MovieFinder 서비스를 추적하기를 원합니다.

마지막으로 메소드에서 리턴합니다. 여기에 흥미있는 부분이 있습니다. addingService 의 리턴타입은 그냥 Object 입니다. 우린 무엇을 리턴해야 할까요 ? 사실은 ServiceTracker 는 상관하지 않습니다. 우리가 원하는 어떤것을 리턴해도 됩니다. 어쨋거나, 우리가 addingService 에서 리턴하는 객체는 modifiedService removedService 가 호출되었을때 우리에게 다시 주어집니다. 그러므로 removeService 메소드의 첫번째 줄을 보시면, 우리가 객체를 MovieFinder 로 캐스팅하는것을 볼수있습니다. 이렇게 해서 리스터로 부터 unbound 될수 있는것이죠. 그리고는 만약 추적하는 finder 들이 0개가 되었을때 MovieLister 서비스를 등록해제 합니다.

일반적으로, 우리가 addingService 에서 한 일들은 removedService 메소드에서 되돌려 놔야 합니다. 그러므로, addingService 메소드에서 리턴할것은 우리가 무슨일을 했는지를 알수있도록 도와주는 것이야 합니다. HashMap 에서의 Key가 될 수도 있고, ServiceRegistration 객체일수도, 이번 경우처럼 실제 서비스 객체일수도 있습니다.

removedService 의 마지막 단계로, 우리가 “가져왔던(Got)” 서비스를 “돌려줘야(Unget)” 합니다. 이는 서비스 레지스트리가 서비스 사용 카운터를 줄이게 해서, 카운터가 0 이 되었을때 서비스가 해제될수 있도록 하기위한 것이므로, 매우 중요합니다.

자 이제 우린 Activator 가 필요합니다. osgitut/movies/impl/TrackingMovieListerActivator.java 입니다.

package osgitut.movies.impl;
import org.osgi.framework.*;
public class TrackingMovieListerActivator implements BundleActivator {
 private MovieFinderTracker tracker;
 public void start(BundleContext context) {
    tracker = new MovieFinderTracker(context);
   tracker.open();
 }
  public void stop(BundleContext context) {
   tracker.close();
  }
}

Manifest 파일 TrackingMovieLister.mf 입니다.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Tracking Movie Lister
Bundle-SymbolicName: TrackingMovieLister
Bundle-Version: 1.0.0
Bundle-Activator: osgitut.movies.impl.TrackingMovieListerActivator
Import-Package: org.osgi.framework,
 org.osgi.util.tracker,
 osgitut.movies;version="[1.0.0,2.0.0)"

이 번들을 빌드해서 Equinox 에 설치하는것은 여러분께 연습으로 남겨둡니다. 그후에는 아래 단계들을 따라해서 모든것이 동작하는지를 살펴보세요.

  1. BasicMovieFinder 를 실행하고 TrackingMovieLister 를 실행합니다. “MovieLister: added a finder” 메시지가 나오는지 확인.
  2. services 명령을 입력해서 MovieLister 가 등록되어 있는지 확인합니다.
  3. BasicMovieFinder 를 중단하고 “MovieLister: removed a finder” 메시지가 나오는지 확인.
  4. services 명령을 다시 입력해서 MovieLister 서비스 등록이 해제 되었는지 확인.

우리가 여기서 한 작업은, 매우 강력한 기술의 토대를 다진거라고 볼수 있습니다. 우리는 한개의 서비스의 라이프사이클을 다른 서비스(실제로는 여러개의 다른 서비스)의 라이프사이클에 연결하였습니다. 이 기술을 더 발전시키면, MovieLister 에 연결된 다른 서비스를 가질수도 있고, 또 거기에 의존하는 다른 서비스 등등.. 우리는 서로 의존하는 서비스들의 그래프를 만들었습니다. 하지만 다른 정적인 IOC 컨테이너에 의해 만들어진 bean 들의 그래프와는 달리 우리의 그래프는 튼튼하며, 자가 치유능력이 있고, 변화하는 환경에 적응할 수 있습니다.

한편으로 우리가 작성한 코드에는 약간의 문제가 있습니다. MovieFinderTracker TrackingMovieListerActivator 클래스는 반복사용 되는 문장들이 가득해서, 우리가 시스템을 확장하기 시작한다면 우리는 같은 코드를 매번 조금씩만 바꿔서 작성하게 되어 매우 피곤해 질것입니다. 그러므로 다음회에서는 이 모든 코드를 몇줄의 XML 로 변경하는 방법을 알아볼 것 입니다.

다음회부터는 이제 한 디렉토리에서 커맨드 라인 툴로 모든것을 작성하는것을 그만둘 것입니다. 이 튜토리얼을 시작할때 저의 목표는 OSGi 는 간단하면서도 강력한 프레임워크 이며, OSGi 번들을 개발하기 위해서 Eclipse 같은 무겁고 강력한 IDE 가 필요하지는 않다는것을 보여주는 것 이었습니다. 어떤 것이 매우 쉽다고 보여질때 , 우리는 한편으론 IDE 가 어떤 흑마법을 사용한 것이 아닐까 하는 의구심을 가지게 됩니다. 전 이번 경우 엔 그런것과 달리, OSGi 가 그런 흑마법은 필요하지 않다는 것 을 보여주었기를 희망합니다. 한편으로, 만약 이 코드를 넣는 디렉토리가 제것과 비슷하다면, 여러분께서도 이제 적절한 개발환경을 원하고 계실겁니다. 저 역시 그렇습니다. 이것은 물론 OSGi 의 문제가 아닙니다. 어떤 Java 프로젝트라도 표준 툴만을 이용한다면 금방 관리하기 힘들어 집니다.

하여튼, 죄송하지만 다음회까지 여러분께선 EclipseCon 이 끝나는것을 기다리셔야 할듯합니다. 전 24시간안에 Santa Clara 로 가는 비행기를 탑니다. 거기서 뵙기를!
(역주: 작년글이라 위 내용은 필요없겠지만 원문과의 일치를 위해 그냥 번역합니다 ^_^ )

Concurrent Code 를 위해 더 나은 방법을 제공해준 BJ Hargrave 에게 고맙다는 말을 전합니다.

OSGi 시작하기 5 – 서비스 사용하기 : [번역] Consuming a Service

이 글은 Neil Bartlett 의 연재 글 “Getting started with OSGi”의 번역본입니다.
* 파트 1 – 첫번째 번들 : Your First Bundle
* 파트 2 – 프레임워크와 연동하기 : Interacting with the Framework
* 파트 3 – 번들간의 의존관계 : Dependencies between bundles
* 파트 4 – 서비스 등록하기 : Registering a Service
에 이어 5번째 글입니다. 오탈자 및 이상한 번역은 댓글로 남겨주세요

Getting started with OSGi : OSGi 시작하기 파트 5 – 서비스 사용하기

저자 : Neil Bartlett < njbartlett at gmail dot com >
역자 : 권 정혁 < guruguru at gmail dot com >

글원본 : http://www.eclipsezone.com/eclipse/forums/t90796.html – Getting started with OSGi : Consuming a Service

마지막 글에서 우린 어떻게 서비스를 등록하는지에 대해 알아봤습니다. 이제 그 서비스를 찾고 다른 번들에서 그 서비스를 이용하도록 작업해 봅시다.

Martin Folwer의 Dependency Injection에 대한 글에서 영감을 얻었던 지난번처럼, 우린 문제를 우리 요구사항에 포함할 것입니니다. 우린 MovieFinder 를 서비스로 만들어서 서비스 레지스트리에 등록했습니다. 이젠 특정 감독에 의해 제작된 영화를 찾기위해 MovieFinder 를 사용하는 MovieLister를 만들어볼 것입니다. 그리고 이 MovieLister 자체도 GUI Application 같은 다른 특정번들에 사용되는 서비스가 될것이라고 가정합니다. 여기서 문제점은, OSGi 서비스는 동적이라 등록되고 사라지고 한다는것입니다. 즉, 우리가 MovieFinder 서비스를 호출하고자 할때, 서비스가 불가능할수도 있습니다.

그러면, 만약 MovieFinder 서비스가 존재하지 않는다면 MovieLister 는 무엇을 해야할까요 ? MovieLister 가 하는 일중에 MovieFinder 에 대한 호출이 매우 중요한 것이라는것은 확실하므로, 우리가 선택할수 있는 옵션은 몇가지 밖에 없습니다.

  1. 에러를 낸다. (Null 을 리턴하거나 Exception 을 내거나)
  2. 기다린다.
  3. 처음부터 아예 설치가 안되도록 한다. ( Don’t be there in the first place )

이 글에선 쉬운 앞에 2가지 방법만을 살펴보도록 합니다. 세번째 방법은 아직 여러분께 어떤 의미가 있게 보이진 않겠지만, 앞에 2가지를 보고나면 알수 있게 되실겁니다.

첫번째로 할일은 MovieLister 서비스에 대한 인터페이스를 작성하는것입니다. 아래 소스를 osgitut/movies/MovieLister.java 에 복사하세요.

package osgitut.movies;
import java.util.List;
public interface MovieLister {
    List listByDirector(String name);
}

이제 osgitut/movies/impl/MovieListerImpl.java 파일을 생성합니다.

package osgitut.movies.impl;
import java.util.*;
import osgitut.movies.*;
import org.osgi.framework.*;
import org.osgi.util.tracker.ServiceTracker;
public class MovieListerImpl implements MovieLister {
    private final ServiceTracker finderTrack;
    public MovieListerImpl(ServiceTracker finderTrack) {
        this.finderTrack = finderTrack;
    }
    public List listByDirector(String name) {
        MovieFinder finder = (MovieFinder) finderTrack.getService();
        if(finder == null) {
            return null;
        } else {
            return doSearch(name, finder);
        }
    }
    private List doSearch(String name, MovieFinder finder) {
        Movie[] movies = finder.findAll();
        List result = new LinkedList();
        for (int i = 0; i < movies.length; i++) {
            if(movies[i].getDirector().indexOf(name) > -1) {
                result.add(movies[i]);
            }
        }
        return result;
    }
}

이것이 아마 지금까지 샘플중 가장 긴 코드일겁니다! 그럼, 여기선 무슨일이 일어나고 있을까요 ? 첫번째로 실제 영화를 찾는 로직이 doSearch(String,MovieFinder) 메소드로 분리되어, OSGi 에 관련된 코드를 독립시키도록 도와주고 있습니다. 불가피 하게도, 우리가 검색을 하는 방법이 멍청하고 비효율적이지만, 그건 이 튜토리얼에는 크게 종요하지 않습니다. 어차피 우리 데이터베이스에는 딱! 2개의 영화만 있으니까요.

흥미로운건 서비스 레지스트리로부터 MovieFinder 를 찾기위해 ServiceTracker를 사용하는 listByDirector(String name) 메소드 입니다. ServiceTracker 는 OSGi API 의 재미없는 하위레벨 코드를 추상화시켜주는 매우 유용한 클래스입니다. 어쨋거나, 우린 정말 서비스가 존재하는지 체크할 필요가 있습니다. ServiceTracker 는 생성자로 전달되었다고 가정합니다.

여러분께선 아마도 ServiceTracker 를 사용하지 않고 레지스트리에서 서비스를 가져오는 코드를 보셨을수도 있습니다. 예를 들어 BundleContextgetServiceReferecegetService 를 호출하는것이 가능합니다. 하지만 이런 코드는 꽤 복잡하고 사용후 잘 지우도록 조심해야 합니다. 제 의견으론, 로우레벨 API를 사용하는 것의 이점은 매우 작고 많은 문제가 있습니다. ServiceTracker 를 항상 사용하는것이 좋습니다.

ServiceTracker 를 생성하기에 좋은곳은 bundle activator 입니다. 아래 코드를 osgitut/movies/impl/MovieListerActivator.java 에 복사하세요.

package osgitut.movies.impl;
import java.util.*;
import org.osgi.framework.*;
import org.osgi.util.tracker.ServiceTracker;
import osgitut.movies.*;
public class MovieListerActivator implements BundleActivator {
    private ServiceTracker finderTracker;
    private ServiceRegistration listerReg;
    public void start(BundleContext context) throws Exception {
        // Create and open the MovieFinder ServiceTracker
        finderTracker = new ServiceTracker(context, MovieFinder.class.getName(), null);
        finderTracker.open();
        // Create the MovieLister and register as a service
        MovieLister lister = new MovieListerImpl(finderTracker);
        listerReg = context.registerService(MovieLister.class.getName(), lister, null);
        // Execute the sample search
        doSampleSearch(lister);
    }
    public void stop(BundleContext context) throws Exception {
        // Unregister the MovieLister service
        listerReg.unregister();
        // Close the MovieFinder ServiceTracker
        finderTracker.close();
    }
    private void doSampleSearch(MovieLister lister) {
        List movies = lister.listByDirector("Miyazaki");
        if(movies == null) {
            System.err.println("Could not retrieve movie list");
        } else {
            for (Iterator it = movies.iterator(); it.hasNext();) {
                Movie movie = (Movie) it.next();
                System.out.println("Title: " + movie.getTitle());
            }
        }
    }
}

이제 Activator 가 재미있어 보이기 시작합니다. 처음에 start 메소드에서 MovieLister 가 사용할 ServiceTracker 개체를 생성합니다. 그리고는 ServiceTracker 를 “엽니다”. 이건 MovieFinder 서비스의 Instance를 레지스트리에서 추적하는걸 시작하라는 것이죠. 그리고는 MovieLister 인터페이스 이름으로 서비스 레지스트리에 MovieListerImpl 개체를 생성하고 등록합니다. 마지막으로, 우리가 번들을 시작했을때 뭔가 재미있는것이 보일수 있도록, MovieLister 를 이용하여 간단한 검색을 실행하고 결과를 출력합니다.

이제 이 번들을 만들고 설치해야 합니다. 자세한 설명은 하지 않도록 하겠습니다. 이전 회를 참고하면 충분히 하실수 있을겁니다. Manifest 파일을 만들고, Bundle-Activatorosgitut.movies.impl.MovieListerActivator 를 지정해야 하는걸 기억해 두세요. 또한 Import-Package 에는 우리가 다른 번들에서 임포팅하는 3개의 패키지 ( org.osgi.framework , org.osgi.util.tracker 그리고 osgitut.movies ) 를 적어주어야 합니다.

MovieLister.jar 를 Equinox 런타임안에 설치했다면, 시작할 수 있습니다. 지난번에 만든 BasicMovieFinder 번들이 동작하고 있는지에 따라 다음 2개의 메시지중 하나를 볼수 있습니다. 만약 동작중이 아니라면,

osgi> start 2
Could not retrieve movie list

아직 동작중이라면

osgi> start 2
Title: Spirited Away

각 번들을 중지시키고 시작시켜보면, 두개의 메시지를 원하는 대로 보실수 있습니다. 이것이 이번 연재의 거의 다입니다만, 제가 서비스가 사용 불가능할때(not available) 할수 있는 일중에 기다리는 방법이 있다고 한거 기억하시나요 ? 우리가 가지고 있는 코드만 있으면 이건 간단합니다. MovieListerImpl 의 16번째 라인을 getService() 메소드 대신 ServiceTrackerwaitForService(5000)으로 변경하시고, InterruptedException 에 대한 try/catch 블록을 추가하세요.

이것은 listByDirector() 메소드가 5000 밀리세컨드동안 MovieFinder 서비스가 나타날때까지 기다리도록 할것입니다. 만약 MovieFinder 서비스가 그 시간내에 설치된다면 (물론 이미 있을때에도) 우린 바로 서비스를 가져와서 사용이 가능할 것입니다.

일반적인 경우에 저는 이런식으로 중지하고 있는 쓰레드를 사용하라고 권고하지만, 이 경우엔 listByDirecor() 메소드가 프레임워크 쓰레드로 부터 호출되는 Bundle activator 의 start 메소드 에서 호출이 되었기 때문에 위험할수 있습니다. 번들이 활성화 될때 여러 일들이 일어나야할 필요가 있기때문에 Activator 들은 빨리 리턴해야 합니다. 최악의 경우에는 우리가 다른것에 의해 이미 lock 되었을지도 모르는 프레임워크 소유개체의 synchronized 블록에 들어갔으므로 deadlock 이 발생할 수도 있습니다. 기본 가이드라인은, 프레임워크에 의해 호출되는 모든코드 또는 번들의 activator 에 있는 start 메소드에서는 시간이 오래 걸리는 작업이나 블록킹 오퍼레이션을 하지 말라는 것입니다.

다음 회에선 의존개체가 없을 경우의 신비한 3번째 옵션 “Don’t exist in the first place” 에 대해 알아보겠습니다. 기대해 주세요!