posted by 아겔-_- 2009.11.28 19:26

세줄요약:
  • clojure.jar, clojure-contrib.jar 절대 (직접) 설치하지마라!!!
  • 개발하려면 emacs + (elpa) + swank-clojure 써라!!!
  • lein을 활용해라!!!


1. emacs에 elpa을 설치한다 : http://tromey.com/elpa/

  방문해서 install elisp코드 이맥스 scratch 버퍼에 붙여넣고 C-j




2. swank-clojure 설치하여 slime + clojure 설치를 한방에

  이맥스에서 "M-x package-list-packages"한 다음 "swank-clojure"에서 "I"로 체크하고 "X"로 설치... 


3. ~/.emacs에 다음을 추가하여 유니코드 사용가능하게
(setq slime-net-coding-system 'utf-8-unix)

4. 이맥스에서 "M-x slime"하여 테스트!


5. leiningen을 설치 : http://github.com/technomancy/leiningen/

"lein" 쉘스크립트를 다운 받아 적당히 PATH에 걸고 실행가능으로.
그리고 다음을 쉘에서 실행하여 clojure, clojure-contrib등을 설치...
lein self-install

이렇게 하면 간략한 clojure 개발환경 세팅 끝.

project.clj을 만들고 lein compile, jar, uberjar, test등을 바로 적용이 가능해졌고, clojars에서 제공하는 외부 라이브러리를 다운 받아 적용이 가능해졌고 pom을 만들어 clojars에 배포하거나 apache-maven에 적용도 가능해지는 멋진 환경에 되었심...

이맥스에서는 "M-x swank-clojure-project"로 해당 project.clj의 경로를 지정하면 프로젝트를 바로 인식해서 열어준다능... (클래스패스등...)

하악하악... 


신고
posted by 아겔-_- 2009.06.28 23:40

자바가 뭐길래...

 

 

주의: 전방에 간만에 DogSound

 

 

2009/06/28 22:51:52

 

몇년간 잠잠하던 이슈였던 "자바를 도대체 왜 쓰나?"라는 플레임이 KLDP에 번졌었다.

 

개인적으로 회사일도 바쁘고, 플레임에 진지하게 끼어드는것도 별로 좋아하지 않는 나로서는 그저 불구경일뿐이었다. 이제는 어느덧 개념있는 몇몇 유져들이 소화한 상태로 보인다.

 

그럼에도 별로 특출난 자바 개발자도 아닌 내가 생각하는 자바의 즐거움, 혹은 강력함에 대해서 많이들 공감하지 못하는 모습에 조금 섭섭하고 안타까운 마음에 졸문을 적는다.

 

 

 

"Guy L. Steele, Jr."란 사람을 아시나요? (http://en.wikipedia.org/wiki/Guy_L._Steele,_Jr.)

Scheme이란 언어의 초기설계에 많은 공헌을 한 분이라고 합니다. 그리고 또 재미있는것은 다음의 경력입니다.:

Steele has served on accredited standards committees ECMA TC39 (ECMAScript, for which he was editor of the first edition), X3J11 (the C language), and X3J3 (Fortran) and is currently chairman of X3J13 (Common Lisp). He was also a member of the IEEE working group that produced the IEEE Standard for the Scheme Programming Language, IEEE Std 1178-1990. He represents Sun Microsystems in the High Performance Fortran Forum, which produced the High Performance Fortran specification in May, 1993.

한 마디로

  • ECMAScript (JavaScript, ActionScript...)
  • C language
  • CommonLisp
  • Scheme

이런 언어들의 표준에 공헌을 하고 계시는군요. 그리고 또 어떤 언어에 공헌을 하고 계실까요? 딩동댕~ 예, 자바입니다.

아주 오래전에 자바의 시작과 함께했던 분이군요. 자바도 어떻게 생각해본다면, Scheme와 유사하죠. (Crystalized) C/C++에서 많은 불필요하고 복잡한 부분을 제거하고, 순수한 객체지향언어로서, 그러면서도 단순함을 읽지 않도록 중용을 지킨 언어라고 생각합니다. (예, primitives가 있지만요. 순수하다고 그렇게 얘기할래요. 스몰톡이 더 순수한 객체지향이지만, 메타클래스와 같은 도를 넘어선 부분이 있지 않을까요? 너무 give-and-take인가요? ^^;)

 

많은 사람들이 이런 발언에 반감을 가질것을 알면서도 제가 이렇게 적는 이유는, 자바가 "성공적"이기 때문입니다. 시장의 대부분을 잠식했다는 성공은 둘째치더라도, 비-개발자를 내면의 포스를 이끌어내는 해커적인 수련이 아니라, 교육과 훈련으로 개발자로 만드는것이 가능한 언어이기 때문입니다.

 

자바를 정말 제대로 이해하고 계신가요? 저는 솔직히 별로 그렇지 못해 부끄럽습니다만, 적어도 '루비스트의 생각'이나 '팩터수련자의 마음'으로 자바를 대하고 있다고 생각하진 않습니다. 무슨말인가하면 자신이 익숙한 세상의 시각으로 자바를 재단하지 않는거 말입니다. 자바는 루비, 리습, 팩터, 스몰톡, 펄이 아닙니다. 자바의 세계에는 그 규칙이 있습니다.

 

예를 들어,

  • 모든것은 객체
  • 그런데 객체의 최소단위는 선언의 단위 : 패키지, 클래스, 인터페이스, 필드, 메서드...

    • 여기서 삐끗하는거죠. 코드블럭은 객체의 최소단위가 아니니까요. 다른 대부분의 다이나믹 언어들과 다르게.
    • 그래서 재사용의 단위는 객체까지니까 좀 더 블럭이 커지죠.
  • 그리고 정적인 타입검사

    • 이것도 불편하다고 생각하면 불편하죠
    • 하지만 반대로 좋은거라고 생각하면 좋은거죠. 컴파일러가 에러를 잡아주고, 좋은 개발환경이 있으니까요.

 

인정할것을 인정하면 나쁘지 않다고 생각합니다.

물론, 루비나 펄, 파이썬, 리습 같은 언어보다 더 간결하고 명확한 코드를 작성하기 쉽지않고, 알고리즘을 기술하는데도 더 복잡합니다. 하지만, 선원에 들어가 참선을 하며 작성하는 코드가 아니라 정말 그때 그때 필요한 코드를 나열하고 그걸 컴파일러와 개발환경에 잡아주는것으로 인한 개발성능은 나름 매력적이고 즐거운 경험입니다. (실용적인)

 

또한 다른 언어에서는 예를 찾아보기 힘든 방대한 라이브러리, 도구가 있습니다.

대부분의것들이 꽤 mature하고 동일한 방법으로 접근이 가능합니다. 오픈소스로. Maven이나 Ivy에 대해서 생각해보세요.

 

개발작업이 단순히 말도 안되는 복잡한 디테일에 사로잡힌것이 아니라 라이브러리들을 모아서 적당한 블럭을 조합해 내는 그런 작업이 되어갑니다. (스몰톡의 아이디어가 무엇이었는지 기억해보세요.)

 

반대로 펄이나 파이썬으로, 혹은 루비, 팩터로 하는 작업들을 생각해보면 재밌습니다.

대부분의 경우에는 그 언어라는 system을 벗어나는일이 적지만, 그래도 자바에 비하면 대부분의 경우 시스템과 언어, 그리고 적어도 c에 대해서 해커적인 지식을 필요로하는 작업이 있습니다. (extension build나 설치...)

 

하지만 자바를 이용하면서 jvm, jar버젼, 그리고 .class파일의 몇가지 규칙을 제외하고는 그 범위를 넘어서는 생각이 많이 필요하진 않습니다.

 

저는 대표적으로 커먼리습에서 ASDF을 이용해서 외부 패키지를 설치하는것과 Maven을 이용해서 외부 JAR을 추가하는것을 비교해보라고 권해드리고 싶습니다.

 

물론, 리습과 같은 언어가 쓸모없다는말이 아닙니다. 저라면 그걸로 충족이 된다면 얼마든지 그런 언어들을 이용할 생각이 있고 그런 언어들을 좋아합니다. 저는 회사에서는 다이나믹언어빠로, #langdev와 같은 곳에서는 자바빠로의 오명을 듣기도 했습니다. 그런데 단순히 그런것들을 무턱대고 자신의 생각의 한계에 가두는것이 안타깝습니다.

 

결국 저희 회사의 주 사용언어는 자바지만, 저의 의견이 반영되어 개발자 면접시 가장 주요한 질문은 "팩터, 리습, 스몰톡, 루비, 파이썬, 펄등을 아는가? 안다면 사용할수있는가"라는 질문입니다. ("평균을 넘어서기", "해커와 화가"에서 잘 알려진 아이디어죠.)

자바개발자보다 파이썬 개발자가 더 낫지만, 반대로 파이썬을 능숙히 할줄아는 자바개발자가 더 좋습니다. 반대도 마찬가지구요. :-) 저희 회사의 기업가치는 그런 개발자들의 합이라고 생각합니다.

 

저는 자바가 좋고, 루비가 좋고, 팩터가 좋습니다.

 

어떤분은 도대체 그따위 개소리를 하는 저의가 뭐냐고 하실지도 모르겠다는 먼 걱정이 듭니다.

펄을 이용해 web crawler을 만들때 회사에서는 투덜거렸었고, 팩터에 관심을 가질때 어떤분께서는 21세기들어 보기드문 큰웃음을 주셨었고, 자바를 옹호할때 나름 개방된 마음이라고 생각했던 사람들은 얼마나 자신들의 생각이 고루한가를 고백하셨던것 같습니다. 그냥 저의 생각은 좋다고 생각하는게 있는데 그걸 당신네들이 느끼지 못하는게 슬픈거지, 그걸 굳이 선포하실 필요는 없다고 생각합니다. 그리고 제가 그동안 공부해온 언어들과 환경들을 생각할때(팩터, 리습, IoLanguage...) 단순히 제가 자바를 좋아한다고 백안시하는건 그게 더 웃기다고 생각합니다. (나름 "신자유주의 좌파"나 "주주총회에 참석하는 노조위원장"같은거죠.;;;)

 

장미는 피처럼 붉고, 코스모스는 어린아이의 뺨처럼 핑크인게 좋습니다.

 

자바는 지금까지 발전해왔고, 앞으로도 발전할것이라고 생각합니다.

Groovy, Scala, JRuby로 그랬고, 다시 한번 새롭게 태어날 Java7, 그리고 JavaFX에서 가능성을 봅니다. :-)

 

 

뭔가 돌을 던지려면 던지고, 말려면 말아라는 식의 글이라 좀 부끄럽군요. 오랬만에 DogSound을 적어봅니다.

이 글은 스프링노트에서 작성되었습니다.

신고

'5.1ch DogSound' 카테고리의 다른 글

어떻게 앞서갈것인가  (1) 2010.06.04
be a Big Fish  (0) 2010.03.26
자바가 뭐길래  (4) 2009.06.28
거짓말과 함정들  (2) 2009.04.16
모든 상황속에서  (0) 2009.02.21
[모자이크] 핵심, 본질, ...  (0) 2008.09.11
posted by 아겔-_- 2009.06.21 21:14

IoC, DI, and Google Guice

 

 


"...해 아래에는 새 것이 없나니" (개역개정 전도서 1:9)
"...and no new under the sun." (KJV Ecclesiaste 1:9)

 

  • 어느샌가 작성하다보니 2.0을 기준으로 하고 있었음 2009/06/21 20:47:15

 

 

IoC? DI?

 

 

IoC: Inversion of Control
  • 일반적인 procedural로부터 절차가 거꾸로 된것처럼 보이는 is an abstract principle describing an aspect of some software architecture designs.

    • 전통적인 프로그래밍에서는 flow은 중앙화된 어떤 코드로 관리함.
    • IoC에서는 이러한 흐름을 직접 제어할 필요가 없어지며, caller측에서 얻어야할 응답은 어느순간 이미 얻어져 있도록 되며 이를 신경쓸 필요가 없게된다.

      • 피호출자측에서 이러한 사항을 조절한다.
      • 그리고 언제, 어떻게라는 사항을 호출자측에서 지정하는것보다 피호출자에 따라서 기술함이 더 바람직하다.
    • 이런 "IoC principle"을 "Holloywood principle"이라고 하기도.

      • "don't call us, we'll call you."
      • 우리가 흔히 아는 callback, event-listener와 같은 디자인의 코드들이 이런 범주에 속함.
  • 디자인 가이드라인으로서...

    • 어떤 작업의 수행을 구현으로부터 분리가능
    • 모든 시스템은 "설계의도"에 대해 집중됨.
    • 모든 시스템은 연동한 다른 시스템이 "어떻게 할것이다"라거나 "어떻게 하지않을것이다"라는식의 추측을 하지않게된다.
    • 특정 시스템의 교체가 있더라도 다른 시스템에 부수효과(side-effect)가 없다.
  • 구현 방식들은...

    1. 팩토리(factory) 패턴
    2. service locator이용
    3. constructor injection
    4. setter injection
    5. interface injection
    6. contextualized lookup (service locator로 구현하는 경우도)

 

 

DI: Dependency Injection
  • 소프트웨어 컴포넌트에 외부의존(external dependency)을 제공하는.
  • 필요한 의존성을 얻는데 있어 invert하는, IoC의 한 구현형태
  • 어떤 소프트웨어 객체가 어떤 작업을 완수하기 위해서는 다른 객체와의 연동이 필요한데 이런 이용할 객체들을 '서비스(service)'라고.

    • 어떤 객체가 다른 서비스 객체들을 이용하기 위해서는 기본적으로 이들의 생성(instantiate)-초기화(initiate)-해제(dispose)의 생명주기(lifecycle)을 관리해야 하는데 이는 나름 번잡한 작업
    • 이상적으로는 어떤 객체가 서비스 객체를 이용하기 위해서는 이들의 참조만을 이용해서 접근하면 될것을.
  • "dependency injection"은 이런 서비스 객체들을 제공해주고, 생명주기를 관리해주는일에 적용하는 디자인패턴.

    • 적어도 다음의 3가지 요소들로 구성됨

      1. dependent : 서비스객체를 이용하여 작업을 수행하는 객체
      2. dependencies : 서비스 구현객체, 작업을 수행하기위한 서비스를 제공
      3. provider : dependent와 dependencies 사이에서 dependencies의 생명주기를 관리하거나 dependent에게 dependencies을 제공하는 객체
    • provider은 간단히 serivce locator, factory pattern등으로 구현하거나 프레임웍으로 구현하기도.
  • 장단점

    • 장점: 서비스객체와 이용객체간의 커플링이 완전히 사라짐

      • 서비스객체를 교체하거나 유연성이 대폭적으로 확대
      • 단위테스팅이 용이 : 쉽게 mock service을 주입하거나 하면 되니까.
    • 단점: 설정이 분산된 경우 더 큰 혼란이 생김.

      • 실제 주입객체와 연관을 찾기 위해서 일반적인 흐름분석으로 따라잡기가 어려우며
      • 대부분의 ide에서 제공하는 정적인 컴파일시간의 검사들이 무효화됨
      • guice에서는 완전히 자바언어안에서 자바 어노테이션을 이용하여 정적검사가 이루어지며, ide가 다루는 클래스, 인터페이스와 똑같은 추상화레벨에서 접근가능하므로 이러한 문제들이 해소
  • 마틴파울러 아저씨는 객체가 외부 의존성의 참조를 얻는 다음과 같은 3가지 '타입'이 있다고...

    1. "interface injection" : 노출 모듈측이 제공하는 인터페이스를 사용자측에서 구현하여 의존성을 실행시간에 얻는 방식
    2. "setter injection" : 의존하는측에서 setter method을 노출하여 프레임웍이 이를 이용하여 의존성을 주입하는 방식
    3. "constructor injection" : 클래스 생성자를 통해서 의존성을 넘겨주는 방식

 

 

 

 

참고문서

 

 

 

 

guice 기초

http://code.google.com/docreader/#p=google-guice&s=google-guice&t=UsersGuide

 

어떤 객체가 단순히 다른 서비스 객체를 원하더라도, 그 서비스 객체가 다시 필요로하는 또 다른 서비스 객체를 그 서비스 객체에 넘겨줘야 하므로 결국에는 object graph을 생성하는 번거로움이 있음. 이를 guice가 해결하는것을 보임.

 

다음은 제일 기본적인 guice사용법:

  1. 서비스 인터페이스와 서비스 구현객체 (둘이 하나여도 상관은 없겠지만)

    • 서비스 객체에서도 @Inject을 이용하여 의존성을 표기해줄수있음.
    • 그리고 그 서비스 객체의 참조 서비스 객체도 다시 외부 의존성을 표기할수있음.
    • 이렇게 재귀적 종속관계를 표현하면 guice가 알아서 object-graph을 생성함!
  2. 서비스 객체들을 만들었다면 이들을 '모듈'로 묶는다.

    • 모듈을 각 서비스 객체의 인터페이스와 구현객체를 '바인딩'한다.
    • 또는 모듈에서 서비스 객체의 '스코프'를 지정할수도 있음.
  3. 마지막으로 하나 이상의 모듈을 기반한 'Injector'을 생성하고, injector을 통하여 대상 객체에 의존성을 '주입'한다.

    • Injector.getInstance을 통해서 직접 원하는 서비스 객체를 얻거나.
    • 다른 객체에 대해서 Injector.injectMembers등을 통해서 의존성을 주입해주거나.

 

정리해보면

  • 서비스 객체나, 주입을 원하는 대상 객체측에서는 의존성을 필드나 setter, constructor에 @Inject 어노테이션을 이용하여 표기한다.
  • 구현한 서비스 객체들을 모듈을 통해서 묶는데, 모듈에서 이들이 어떤 타입이나 변수이름 등의 형태에 대해 바인딩 되는지, 어떤 생명주기범위를 갖는지등을 설정해준다.
  • Injector을 모듈을 통해 생성하여, 이를 통하여 원하는 바인딩을 얻거나 다른 객체에 의존성을 채워준다.

 

 

Guice 바인딩

Injector의 책임은 객체그래프를 생성하는일.

어떤 타입의 인스턴스를 요청하면 injector은 무엇을 생성하고, 어떻게 의존성을 채우고 이들을 조합할지에 따라 인스턴스를 되돌려줌.

이러한 의존성을 어떻게 풀지 결정은 바인딩(binding)을 통한 injector의 설정(configure)을 따른다.

 

바인딩을 만들려면 AbstractModule을 상속하여 configure메서드를 오버라이드하여 그안에서 bind()을 호출하여 바인딩한다. 메서드들을 이용하여 직접 기술하기 때문에 컴파일러가 타입을 체크하여 정적검사를 수행하여 오류를 잡아준다.

 

모듈을 만들었으면 이를 Guice.createInjector()에 넘겨줘서 injector을 생성하면된다.

 

 

typed bindings & linked bindings

타입을 기반으로 해당 인스턴스를 찾아내는 바인딩. 예를 들어서

  1. bind(TransactionLog.class).to(DatabaseTransactionLog.class);

...와 같은 코드는 TransactionLog에 대한 요청을 DatabaseTransactionLog의 인스턴스로 매핑할것.

또한 재미있는것은 이를 연쇄 할수있다는것.

예를 들어, DatabaseTransactionLog을 또 다른 MySqlDatabaseTransactionLog로 바인딩하면, TransactionLog에 대한 요청의 응답은 MySqlDatabaseTransactionLog로.

 

 

named bindings & instance binding

typed bindings은 어떤 타입 하나에 대해 하나의 구현만을 지정가능함. 그런데 하나의 타입인데 여러가지 상황/문맥에 따라 다른 인스턴스를 필요로한다면? (예를 들어, 문자열 상수라던지...)

  1. bind(String.class)
        .annotatedWith(Names.named("JDBC URL"))
        .toInstance("jdbc:mysql://localhost/pizza");
    bind(Integer.class)
        .annotatedWith(Names.named("login timeout seconds"))
        .toInstance(10);

.toInstance()을 이용하지 않으면 타입을 지정하게되고, 그러면 매번 요청시마다 새로운 객체를 만들어야하므로 오버헤드. (또는 @Provides을 이용하기.)

 

 

@Provides 메서드

어떤 바인딩에 대한 인스턴스가 단순히 생성자만을 통해서 guice가 직접 생성하는것으로 부족할때, 생성 절차를 기술할 필요가 있을때 이 방법을 이용한다.

 

방법은 모듈 안에서 @Provides 어노테이션을 객체 생성 메서드에 붙이고, 해당 메서드의 되돌림값은 바인딩 타입이라면, 그 타입을 요청할때 해당 메서드를 호출하여 인스턴스를 얻는다.

  1. public class BillingModule extends AbstractModule {
      @Override
      protected void configure() {
        ...
      }

      @Provides
      TransactionLog provideTransactionLog() {
        DatabaseTransactionLog transactionLog = new DatabaseTransactionLog();
        transactionLog.setJdbcUrl("jdbc:mysql://localhost/pizza");
        transactionLog.setThreadPoolSize(30);
        return transactionLog;
      }
    }

 

또한 타입 바인딩뿐만 아니라 named binding등에 대해서도 다음처럼하여 적용이 가능

  1. @Provides @PayPal
    CreditCardProcessor providePayPalCreditCardProcessor(
      @Named("PayPal API key") String apiKey) {
        PayPalCreditCardProcessor processor = new PayPalCreditCardProcessor();
        processor.setApiKey(apiKey);
        return processor;
    }
  • @PayPal은 가상의 어노테이션. named binding이라면 @Named("PayPal")등일수도 있겠죠.
  • 또한 apiKey인자에 대해서도 자동으로 inject하여 처리하므로, @Provides 메서드가 항상 아무 인자도 안받는 메서드일 필요는 없음. (대신 주입이 가능한.)

 

provider bindings

@Provides 메서드들이 많아진다면, 이들을 개별 클래스로 분리를 생각해볼수있음. 이런 @Provides 메서드를 개별적인 클래스로 분리하는데 이용하는것이 Provider 인터페이스를 구현하는것.

 

이 인터페이스는 다음과 같음.

  1. public interface Provider<T> {
      T get();
    }

 

즉, 이를 이용하는 방법은 Provider<T>을 특정 대상 타입에 대해서 특화(specialize)한 다음, get() 메서드를 구현하는것.

  1. public class DatabaseTransactionLogProvider implements Provider<TransactionLog> {
      private final Connection connection;

      @Inject
      public DatabaseTransactionLogProvider(Connection connection) {
        this.connection = connection;
      }

      public TransactionLog get() {
        DatabaseTransactionLog transactionLog = new DatabaseTransactionLog();
        transactionLog.setConnection(connection);
        return transactionLog;
      }
    }

 

그리고 마지막으로 모듈에서 .toProvider을 이용하여 바인드.

  1. public class BillingModule extends AbstractModule {
      @Override
      protected void configure() {
        bind(TransactionLog.class)
            .toProvider(DatabaseTransactionLogProvider.class);
      }
  2.   ...

 

more bindings...
  • injector은 기본적으로 built-in bindings을 갖는다.
  • 요청한 타입에 대한 바인딩이 없다면, 기본적으로 just-in-time binding을 이용한다.
  • 그리고 모든 타입에 대해서 providers에 대한 바인딩을 기본값을 통해 자동적으로 제공한다. (이후 injections / injecting providers을 참고)

 

built-in bindings

injector은 몇가지 바인딩을 기본적으로 제공하며, 이들을 직접 바인딩하려고 하면 에러-_-;

Logger : "java.util.logging.Logger"을 기본적으로 바인딩함. logger 이름은 inject 대상 클래스의 이름으로 주입해줌.

  • the Injector
  • TypeLiterals : TypeLiteral<T>을 주입하여 injector가 주입해주는 타입에 대한 정보를 주입가능.
  • the Stage : 이 enum을 통해서 현재 실행환경이 production/development등을 구분할수있게해줌.

 

 

just-in-time bindings
  • injector가 특정 타입의 인스턴스를 얻으려면

    1. 모듈에 바인딩한 explicit binding을 뒤져본다
    2. 없으면 just-in-time binding(혹은 implicit binding)을 생성하여 이를 처리한다

 

  1. constructor bindings : 바인딩 대상 타입의 injectable생성자를 이용한다. 여기서의 'injectable'생성자는 다음 조건을 만족함

    1. public임
    2. 생성자에 인자가 필요없음
    3. 혹은 @Inject어노테이션이 붙어 인자를 주입할수있음
  2. @ImplementedBy : 이 어노테이션을 인터페이스측에 붙여서 해당 인터페이스를 구현하는 기본 서비스 객체가 무엇인지 지정할수있음
  3. @ProvidedBy : 이 어노테이션을 인터페이스측에 붙여서 provider 클래스를 지정할수있음

 

 

Guice 스코프

기본적으로 Injector은 요청에 대해서 매번 새로운 인스턴스를 되돌림. 이를 수정하는게 'scope'설정. 이를 통하여 하나의 인스턴스를 공유하는게 가능해지는데, 애플리케이션 단위 (@Singleton), 세션단위 (@Session), 요청단위 (@Request)등이 있으며, 이를 추가적으로 구현할수도 있음. servlet extension을 통해 웹애플리케이션을 위한 scope을 제공.

 

스코프 적용하기

구현 클래스에 다음처럼 어노테이션을 붙여서 적용하거나

  1. @Singleton
    public class InMemoryTransactionLog implements TransactionLog {
      /* everything here should be threadsafe! */
    }
  2.  

bind문장에 in()을 적용하여 지정함.

  1. bind(TransactionLog.class).to(InMemoryTransactionLog.class).in(Singleton.class);

또한 @Provides 메서드에 지정하여도 가능함

  1. @Provides @Singleton
    TransactionLog provideTransactionLog() {
    ...
    }

서블릿과 관련하여 ReqeustScoped라던지 Scopes.REQUEST 인스턴스등도 이를 이용하여 가능. (HTTP요청이나 RPC요청에 대해 스코프, 세션도 마찬가지로.)

 

eager singletons

singleton을 위한 특별한 처리를 지원함. eager하게 생성되는가에 대한 여부를 지정.

  1. bind(TransactionLog.class).to(InMemoryTransactionLog.class).asEagerSingleton();

Eager singletons reveal initialization problems sooner, and ensure end-users get a consistent, snappy experience. Lazy singletons enable a faster edit-compile-run development cycle. Use the Stage enum to specify which strategy should be used.

  PRODUCTION DEVELOPMENT
.asEagerSingleton() eager eager
.in(Singleton.class) eager lazy
.in(Scopes.SINGLETON) eager lazy
@Singleton eager* lazy

* Guice will only eagerly build singletons for the types it knows about. These are the types mentioned in your modules, plus the transitivedependencies of those types.

 

스코프의 선택
  • stateful한 객체라면 이를 고려해야함

    • 애플리케이션단위 공유라면 singleton
    • 요청과 같은것에 따른것이라면 이에 따른 스코프
  • stateless하며, 생성하는데 비용이 적게 드는 객체라면 스코프에 대한 고려는 무의미

또한 싱글턴을 위한 '변호'는 다음과 같다.

  • stateful한 객체에 유용. (설정, 카운터...)
  • 생성하거나 lookup하여 얻는데 비용이 큰 객체
  • 디비접속과 같은 리소스와 묶인 객체

 

스코프와 concurrency

@Singleton, @SessionScoped와 같이 넓은 범위에 공유되는 객체는 threadsafe해야하며, 가능하면 mutability을 최소화하는것이 바람직.

 

Guice Injections

 

Constructor Injection

생성자에 @Inject 어노테이션을 붙이고, 그 인자들은 주입이 가능한것들이라면 guice가 이를 생성할때에 자동적으로 주입해준다. 어노테이션이 없더라도 똘똘하게 guice가 잘 생성자에 객체들을 넘겨줌.

 

Method Injection

메서드에 @Inject 어노테이션이 붙어있다면, 자동적으로 해당 메서드를 호출하여 인자들을 넘겨줌. (setter등... 하지만 꼭 메서드 이름이 setter일 필요는 없음.)

 

Field Injection

필드에 값을 자동적으로 세팅. final인 필드에는 주의를 (의미가 모호해짐?)

 

Optional Injections

만약 주입을 할때에 원하는 타겟에 대한 인스턴스를 얻지 못할때 조용히 넘어가고 싶을때 이를 이용.

@Inject(optional=true)로 어노테이션.

 

"requestInjection"

그냥 손으로 객체를 생성한 다음에 나머지들을 주입하여면 Injector.injectMembers()을 이용하여 직접 주입이 가능

 

Static Injections

static factory을 적용하려면, 이를 이용.

모듈에서는 requestStaticInjection()을 이용하고, 이용측에서는 Provider<T>을 이용하여 구현.

  1. @Override public void configure() {
    requestStaticInjection(ProcessorFactory.class);
        ...
    }

  2. class ProcessorFactory {
      @Inject static Provider<Processor> processorProvider;

      /**
       * @deprecated prefer to inject your processor instead.
       */
      @Deprecated
      public static Processor getInstance() {
        return processorProvider.get();
      }
    }

Static members will not be injected at instance-injection time. This API is not recommended for general use because it suffers many of the same problems as static factories: it's clumsy to test, it makes dependencies opaque, and it relies on global state.

 

Automatic Injection

Guice은 다음과 같은것들을 자동으로 주입함.

  • bind문에서 toInstance()을 통해 전달한 모든 인스턴스들
  • bind문에서 toProvider()을 통해 전달한 모든 provider 인스턴스들

The objects will be injected while the injector itself is being created. If they're needed to satisfy other startup injections, Guice will inject them before they're used.

 

 

 

응용

 

guice-servlet

 

wideplay

 

결론

  • 이런것도 세상에 있구나. 일본쪽 자바커뮤니티스러운것들

    • http://code.google.com/p/t-2/ : T-2 Web Framework

      • 뭔가 죠낸 어노테이션으로 웹프레임웍 ㄷㄷㄷ
    • http://www.seasar.org/

      • 기본적으로 AOP/IoC 프레임웍인데
      • AMF, BDS등과의 연동이 많고 은근히 일본쪽에서는 활성화된듯?
  • 스프링이 좀 더 범위가 넓고(IoC만 하는게 아니니까), 웹과의 연동에 대해서 더 고민을 한듯.
  • 하지만 guice의 경우 정말 외부 설정파일이없이, 코드 그자체로 (그것도 서비스 구현측만으로) 그의 범위와 적용방법에 대해서 기술할수있으므로, 정말 self-contained한 컴포넌트를 위한 방법이고, 무엇보다 light-weight.
  • http://en.wikipedia.org/wiki/Dependency_Injection#Existing_frameworks : 정말 많은 DI 프레임웍/컨테이너가;;;

 

 

이 글은 스프링노트에서 작성되었습니다.

신고
posted by 아겔-_- 2009.05.23 18:47
회사에서 작업하는 자바플젝들은 apache-maven으로 의존성관리 및 빌드, 그리고 개별 라이브러리들을 저장소를 만들어 올리고 다시 다른 프로젝트에서 사용하도록 이용하고 있습니다.

일단 메이븐을 사용한 기간도 만만치않게 길었는데 친숙해지는것과 별개로 이해하기 힘든 무언가라는 느낌을 지울수없었습니다.

  1. 친숙하지않은 용어: artifact, archetype...
  2. 너무 광범위한 범위를 포괄: 정말 메타적인 무언가로서 빌드, 의존성관리뿐만이 아니라 플러그인을 통해서 무한한 확장이 가능한 선언적이고, 메타적인 프로젝트 관리도구...
대충 생각을 정리해보면 저런정도가 아닐까 싶어요.

개인적인 자바프로젝트의 의존성관리를 하려고 찾아본 도구는 [apache-ivy]입니다. 의존성 관리를 위해서 해줄일은 다음과 같았습니다.

  1. 프로젝트 디렉토리에 ivy.xml 작성: 프로젝트 기본정보와 외부 의존성을 나열
  2. 프로젝트 빌드파일에 <ivy:retrieve/>등으로 dependency-resolve.

간단하죠? (사실 apache-maven의 경우도 mvn으로 프로젝트 만들고 pom.xml만 끄적거리면 되는건 똑같겠죠.)

사실 메이븐으로 같은일을 하는데 비슷한 정도의 번잡함인데 왜 제가 ivy에 더 끌리는지 생각해봤는데요. apache-ivy의 경우는 단순하고, unobtrusive한 도구이고, 메이븐의 경우는 좀 아니지 않았나 생각해요. 그러면서도 단계별 저장소의 구분, module configuration을 통해서 다른 개발자와의 모듈 공유와 같은 의존성의 '입력'이외에 '출력'에 대해서도 충분한 지원을 하고 단순한 규칙을 통한 유연함이 마음에 들었나봐요.

maven의 경우, 사실 간단한 몇가지 '요소'들(아티팩트, 아키타입, 플러그인...)을 조합하여 뭔가를 하는 도구이지만, 그 조합에 대해서는 너무 '될데로 되라. 난 별로 관심없다'라는식의 관점이었던건 아닌가 싶어요. (예전에 뻘로깅 시즌1에서 말했던 '리습 신드롬'이랑 비슷한걸까요. 어차피 확장이 무한히 가능하다면, 확장으로 뭘하든 별로 관심이 없어지는.)

그리고 그에 반해서 ivy은 그 목적과 범위가 명확한 덕분에 단순하면서도 강력한 도구가 되지 않았나 싶어요.
신고
posted by 아겔-_- 2009.04.27 12:08
자바개발을 하다보면 좋은 프로파일러 냅두고 귀찮아서; 구간에 따른 시간 경과를 재는 경우가 많음. 매번하면서 그냥 "이러다가말 코드니까"하고 자기합리화.

예를 들어 다음과 같은 코드가 있을때

long start = System.currentTimeMillis();
DO_SOMETHING();
log.info("ms for block n was: " + (System.currentTimeMillis() - start));


하악... 이것만 몇번씩 중복이 일어나는지...


이를 위한 Perf4J





신고
posted by 아겔-_- 2008.09.05 16:57
솔까말 좀 지겨웠다.

이클립스... Flex빌더에 m2eclipse... 속도도 끔찍하게 느렸고 이것저것 겨우겨우 굴러가는듯한 느낌과 속도-,.-;;;
물론 딱 JDT에 서브버젼 플러그인이랑 m2eclipse정도만 되도 쓸만은 하고 정말 JDT는 자바 코딩하는데 있어서 절대적인 도구라고 생각했삼.

그래도 뻑하면 뻗어주고, Refresh, Clean을 오락가락하게 만들어주시는 버그들이랑 그런거 경험하다보니 좀 그랬다-,.-;;; 그래, 그냥 하기 싫었는지도 -,.-...

무엇보다 작은 프로젝트(짐 하고 있는 프로젝트는 내부 프레임웍에 통합할 부분을 구성하기 위한 테스트케이스들이 주가 되는)이기 때문에 개인 저장소에 올릴때도 그냥 간략히 바로 올리고 maven만 갖고서 빌드해보고 테스트 굴려보고 JUnit 리포트 보고 그러면서 주욱 코딩하면 되는 작업이라 이정도는 되겠지 하고 거의 1년여만에 넷빈즈를 설치했삼.

Tools > Plugins에서 업데이트 좀 받아서 설치하고, Maven 통합이나 그런것만 받아서 시작했는데 꽤 빠르다는 느낌. 그리고 잡스러운 배경지식도 별 필요가 없었던거 같고...

그냥 File > New Project에서 Maven 이하에서 원하는 archetype 선택해서(Quickstart!!!!) 프로젝트 와꾸 만들고 끄적거렸는데 정말 통합도 잘되어있고 만족스러웠당.

이클립스 키바인딩에 워낙에 쩔어있어서 키바인딩을 첨에는 이클립스 스타일로 맞춰놓고 했는데 아예 넷빈즈로 재설정하고 Open Type, Open Resource, Outline그리고 Ctrl-0, Ctrl-1, Ctrl-4등으로 주로 오가는 View들 왔다리 갔다리 하면서 코딩하니까 마우스에 거의 손 갈일도 없고 좋았삼.

편집부분에서는 Next Error에 Alt-/을 바인딩해서 warnings/errors을 오가고, Alt-Enter로 이클립스에서 Quick-Fix처럼 되는걸보고 매우 흡족.  Alt-Insert로 코드 생성하는것도 마음에 들구.

무엇보다 별도로 Run Dialog 없이 그냥 Alt-F6으로 메이븐 테스트 돌리고 JUnit Test Results로 통합된 부분도 정말 마음에 들었심.

사용자 삽입 이미지


그다지 따지고 보면 이클립스보다 예쁘다거나 한것도 아닌데 화면전환이나 그런게 훨씬 빠르다는 느낌-,.-;;;(괴상하죵?;;;)

결국에는 이클립스로 진행하는 프로젝트로 다시 통합할 부분이지만 이렇게 넷빈즈로 작업하는게 꽤 즐겁고 나중에 다시 생각해봤을때도 좋은 툴이라는 생각이 남을것 같심.

그리고 편집기에서 변경사항들 표현해주는 방법도 맘에 들구용(local history등으로 연관이 있는 부분에서). 서브버젼등의 버젼관리랑 통합된 diff나 그런것도 꽤 맘에 들어용.

신고

티스토리 툴바