Whiteship's Note

'2008/11'에 해당되는 글 52건

  1. 2008.11.30 지금은 공항이에요 (8)
  2. 2008.11.29 드디어 Spring One America에 갑니다. (2)
  3. 2008.11.29 스프링 프레임워크 3.0 m1 임박.
  4. 2008.11.28 Whiteship's 피아노 쉬운 러브 스토리 (4)
  5. 2008.11.28 Whiteship's 피아노 쉬운 캐논 (2)
  6. 2008.11.28 i구글의 날씨 위젯 좀 짱인듯..
  7. 2008.11.28 LA, 마이애미, 아틀란타 날씨
  8. 2008.11.28 기술 보다는 팀이 개발 정책을 세울 때 우선이 되어야 한다. (2)
  9. 2008.11.27 오호.. 스프링소스 manifest 헤더가 OSGi에 추가되는군요
  10. 2008.11.27 PropertyEditor 활용 예제 (8)
  11. 2008.11.26 스프링 MVC form 태그 써 보셨어요? (2)
  12. 2008.11.26 스프링소스 웨비나: 프로들의 아파치 톰캣 팁과 트릭 (2)
  13. 2008.11.25 스프링 DM 1.2.0 m2 배포
  14. 2008.11.23 OSGi uses 충돌 감지하기
  15. 2008.11.23 초보자를 위한 책(기술 서적)이 뭔가요? (4)
  16. 2008.11.23 OSGi "uses" 지시어 이해하기
  17. 2008.11.23 미국 가기 전 몸무게 73.05 (4)
  18. 2008.11.21 Toby's J2EE Development without EJB 정리 (4)
  19. 2008.11.21 회사 이사 중 (2)
  20. 2008.11.19 하이버네이트 사용시 Association Fake Object라는 기술을 사용해 보세요. (2)
  21. 2008.11.18 스프링을 사용하는 애플리케이션의 성능 최적화 방안
  22. 2008.11.17 하이버네이트, 스프링, 트랜잭션, OSIV(Open Session In View) 패턴
  23. 2008.11.17 최근에 맛들린 피아노~ (10)
  24. 2008.11.16 새로운 스프링소스 웨비나 일정 (2)
  25. 2008.11.15 Validator에도 여러 가지가 있네 (2)
  26. 2008.11.14 하이버네이트 Criteria 검색 쿼리 골치
  27. 2008.11.14 음헤헷 봄싹 게시판 검색 MVC 완성
  28. 2008.11.13 게시판에서 글 검색 기능은 어떻게 만들까? (2)
  29. 2008.11.12 @Repository를 쓴다면 하이버네이트 예외 변환기 직접 만들 필요 없습니다. (4)
  30. 2008.11.11 SpringSource DM Server 실습할 것 1

지금은 공항이에요



ㅎㅎ;;
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지

신고
top


드디어 Spring One America에 갑니다.

Spring/S1A : 2008.11.29 22:34


작년부터 꿈꿔왔던 컨퍼런스입니다. 정말 정말 가고 싶었습니다. 작년에는 Spring 2.5. Spring Security 2.0 그리고 Spring OSGi(지금은 DM이지만) 소개에 관련된 세션에 많은 관심이 있었지만 갈 수 없었습니다. 하지만 이번에는 드디어 갈 수 있게 됐습니다. 이번에는 Spring 3.0과 Spring DM 그리고 DM Server에 관심이 많습니다. 그토록 가고 싶었던 컨퍼런스를 가게 되었는데 아직도 잘 실감이 나질 않습니다. 가서 무슨 말을 할지 생각도 안나고.. 어버버버 하다가 오는거 아닌지 걱정입니다. @.@

사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지
사용자 삽입 이미지

사용자 삽입 이미지

유겐 휄러한테 배정된 세션 하나가 뭔지 모르겠는데 비어있네요. 일단 유겐 휄러가 보고 싶어서 유겐이 뭔가를 하게 되면 그걸 보고 아니면 쉬던가 차선책으로 선택한 퍼시스턴스 튜닝을 보러갈 듯 합니다.

8시부터 밥먹고 발표 시작해서 대충 5시쯤 끝나는 군요. 첫 날에도 파티하고 세 번째 날에도 파티하네요. 해변 파뤼~ 파뤼~ 맛난거 많이 있으려나~ +_+
신고
top


스프링 프레임워크 3.0 m1 임박.

Spring/etc : 2008.11.29 13:36


참조: http://jira.springframework.org/browse/SPR?report=com.atlassian.jira.plugin.system.project%3Aroadmap-panel

아마도 S1A 컨퍼런스에 맞춰서 하나 공개하고 싶었는지 이슈를 뒤로(m2)좀 미룬거 같습니다. 캬오..

눈에 띄는 이슈 몇 가지는 흠..
- 내부 코드를 자바 5 기반으로 업그레이드
- @RequestMapping에서 URI 템플릿 기능 제공
- RSS/ATOM 뷰 지원
- @RequestParam에 defaultValue 속성 추가
- Expression Language Support(모르겠음)

흠.. REST는 m2에 추가되지만 이번에 추가되는 기능 중에 URI 템플릿 기능과 RSS 지원 기능 그리고 @RequeestParam에 defaultValue 속성 추가는 당장 개발에 써먹을 수 있어 보입니다. 하나 더 EL 기능에 대한 건 잘 파악이 안 됐는데 저게 JSF를 지원하는 기능인건지.. 아님 빈 XML 설정 파일에서 EL을 쓸 수 있게 해주겠다는 건지 좀 햇갈리네요. 자세히 봐야겠습니다.
신고
top


Whiteship's 피아노 쉬운 러브 스토리




이것도 역시 쉬운 악보를 보고 쳤습니다. 전에도 한 번 올린 적은 있지만 그건 좀 틀린 부분도 있어서 다시 쳐봤습니다. ㅋㅋ 하지만 이번에도 틀린 부분 많다는거~
신고
top


Whiteship's 피아노 쉬운 캐논




캬캬캬 캐논이 은근히 어렵습니다. 쉬운 악보를 보고 친건데 힘 조절이랑 박자 조절하기가 여간 어려운게 아닙니다. 어렸을 때 부터 꾸준히 쳤으면 몸에 베어있겠지만 느즈막히 다시 시작 한거라 쉽지 않네요.
신고
top


i구글의 날씨 위젯 좀 짱인듯..

Good Tools : 2008.11.28 20:30


구글에서 마이애미 날씨를 검색했더니 아래처럼 첫 화면에 바로 날씨 요약 정보를 보여줍니다.


저기 보이는 iGoole에 추가 버튼을 눌렀더니...


이렇게 기존에 추가되어있던 서울 날씨에 계속해서 추가해줍니다. 우왕;; 귿인데.. S1A 컨퍼런스 할 때 비오겠네;;
신고
top


LA, 마이애미, 아틀란타 날씨



이번 주 일요일에 가는 S1A와 회사일 때문에 미국 날씨를 미리 봐둡니다.

LA 날씨


LA에서는 갈때 하루 올때 하루 머물기 때문에 그리 중요하지 않고...

마이애미 날씨


S1A 컨퍼런스로 5일정도 머무를 마이애미는... 좀 더워보이는군요. 반팔을 챙겨야겠습니다. 수영복도.. 더우니까 땀 날테고 그럼 옷도 자주 갈아 입어야겠네.

아틀란타 날씨


흠.. 일주일 정도 머무를 곳. 저 정도면 초 가을인가.. 긴팔 입으면 더울까? 얇은 긴팔이면 괜찮겠지..좀 선선하면 좋겠네.

신고

'모하니? > 그냥 놀아' 카테고리의 다른 글

Alabama에 돼지갈비 립  (3) 2008.12.09
미국 Alabama에 있는 햄버거 가게와 서점  (4) 2008.12.07
저는 이제 Alabama에 왔습니다.  (0) 2008.12.07
LA에서 보낸 하루(?)  (6) 2008.12.01
지금은 공항이에요  (8) 2008.11.30
LA, 마이애미, 아틀란타 날씨  (0) 2008.11.28
회사 이사 중  (2) 2008.11.21
개발자들의 수다 후기  (0) 2008.11.09
꺄오~~ 살꺼야. 키보드. 카시오 PX-320  (8) 2008.10.30
보고 싶은 피아노 공연  (0) 2008.10.22
방송탔네~  (0) 2008.10.01
top


기술 보다는 팀이 개발 정책을 세울 때 우선이 되어야 한다.

모하니?/Thinking : 2008.11.28 11:24


당연한 말이죠. 그런데 정말 이렇게 하고 계신가요?

오늘 "사람을 위한 자동화" 시리즈를 번역하다가 멋진 문장 하나를 발견했습니다. (번역을 하면 이게 좋습니다. 정독을 하게 되고, 정독을 하다보면 좋은 문장도 놓치지 않을 수 있죠.)

There are probably version-control systems that support parallel development better than Subversion, but in my experience the policies that teams adhere to when developing are much more important than how a tool technically solves the problem.

병렬로 개발할 때 서브버전보다 더 좋은 툴도 있겠지만, 본인 경험상 개발을 할 때 기술 보다는 팀원에게 익숙한 정책을 세우는게 더 중요했다는 내용입니다.(아마도 GIT 같은 분산 SCM을 두고 말한거 같네요.)

저 한 문장이 저한테 참 많은 생각을 하게 합니다.

SI에 대한 (경험없고 몽매한 저의) 생각

실제 제품 코드 작성하는 개발자들이 자꾸 바뀌는 환경에서 저런게 가능한가? SI가 어쩌다 그런 구조가 됐을까? 팀 단위로 다니는 SI 업체에서는 가능할까? 그 사람들은 프로젝트에 가서 코딩만 하고 기술 선택에 대한 의사결정에 어떤 영향을 주고는 있는 건가? 그런 의사결정 권한이 있는 사람들은 코딩하는 개발자들을 팀으로 생각할까 아니면 종으로 생각하고 있을까? 일단 다 정해놓고 와서 코딩만 시키는거 아닌가? 어떻게 그렇게 개발을 하지? 고객과 개발자가 직접 만나서 일을 하면 안 되고 꼭 중간다리 역할을 하는 사람이 있어야 하나? 그 사람들이 실제로 코딩을 할 개발자들과 같이 개발을 할꺼면 상관없겠지만 그런 경우가 아니라 아예 업체도 다르고 개발할 사람들이랑 전혀 공감대도 없다면. 뭔가 잘못 된 거 아닌가? 개발자와 고객 사이를 막고서서 자기들의 입지를 만들고 개발자 의사소통 능력을 점점 쇠퇴시키는거 아닐까? 개발자는 왜 의사소통을 못한다고 생각하지? 못 하는게 아니라 안 하니까 퇴화 되는거 아닌가? 고객과 개발자가 직접 만나서 대화를 하면 오히려 중간 다리가 고객 - 인코딩 디코딩 - 개발자 - 디코딩 인코딩 - 고객 사이의 네 번의 인/디코딩 과정이 사라지니까 훨씬 좋은거 아닌가? 그래야 위와 같이 팀을 고려한 정책을 만들지 않을까?

나에 대한 내 생각

내가 공부하는 것들을 다른 사람들도 공부하고 있을까? 난 누구랑 일할 수 있는거지? 내가 좋아하는 기술을 포기하고 다른 사람들에 맞춰서 혹은 누군가 이미 다 정해놓은 틀 속에서 개발을 해야 하는건가? 어떻게 해야 되는거지.. 나도 팀 생활을 하고는 싶은데, 내가 사용하고 싶은 기술로는 팀 생활을 할 수가 없고.. 난 선택의 기로에 서있는 건가? 팀이냐 기술이냐 라는 선택인가?? 흠..아니야. 내가 쓰고 싶은 기술(스프링, 하이버, 스프링 DM, 메이븐, ...)이 그렇게도 유별 난건 아니자나. 저 기술을 쓰면서 개발하는 곳이 정말 그렇게도 없을까? 지금도 어디선가는 저 기술로 개발하고 있을 텐데. 글치.. 한국에서도 조금 큰 회사에서 이미 저렇게 하고 있자나. 그래도 역시 혼자는 너무 외로워. 하지만 사실 나 혼자는 아니지. 사부님도 있고 고객도 있으니까. 고객이랑 놀지 뭐. 그러고 보면 다음 프로젝트 기술은 사부님이 기술 결정을 하니까 내가 좋아하는 기술도 써먹어 볼 수 있단 말이지. 딱 저 문구에 맞는 상태로 개발하는.. 즐거움. 팀이 좋아하고 팀에게 익숙한 기술을 사용하는 이 즐거움을 다른 많은 개발자들도 알고 있겠지?? 그래야 할텐데..
신고
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


PropertyEditor 활용 예제

Spring/Chapter 5 : 2008.11.27 15:46


어제 올린 글에 이어지는 내용으로 스프링이 제공하는 form 태그와 PropertyEditor를 조합하는 방법입니다. PropertyEditor로 할 수 있는 일 중 하나를 스프링 form 태그가 해줍니다. 그게 뭐냐면.. getAsText죠.

<form:checkboxes items="${allRoles}" path="roles" delimiter="<br/>" itemLabel="note"  itemValue="id" /><br/>

여기서 보시면, itemValue에 설정한 id 값을 보고 자바빈 스펙에 따라 getId를 호출하여 해당 값을 각각의 체크박스 아이템의 value로 사용합니다. 편하죠, 대신 다른 반쪽이 없기 때문에 바인딩에러가 발생할 겁니다.

form 태그를 사용하여 값을 바인딩할 속성 roles는 Set<Role> 타입이거든요. id가 실제로는 int 값이지만, 화면에서는 String 값 형태로 전달되겠죠. 그 String 값을 Role 타입으로 캐스팅하려니까 에러가 발생하는 겁니다. 이 에러는 <form:errors path="roles" /> 이런 코드를 화면에 붙여두면 확인할 수 있습니다.

자.. 그럼 어떻게 해야되나요? HttpServletRequest 타입 객체를 메소드 매개변수로 추가해주고 거기서 roles라는 파라미터의 값 빼와서 파싱하고 어쩌구 저쩌구.. @.@ 그렇게 하실건가요? 스프링 2.5 이전 이라면 뭐.. 그럴수도 있겠다 싶지만, 서블릿 API에 의존하지 않은 아주 깔끔한 스프링 2.5 애노테이션 기반 컨트롤러에 저 것 때문에 서블릿 API를 사용할 건가요?? 아니죠. 그러고 싶지 않습니다.

네 그러지 않아도 됩니다. setAsText를 구현한 PropertyEditor를 등록해주면 깔끔하게 해결할 수 있습니다.

public class RolePropertyEditor extends PropertyEditorSupport {

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        if(!text.isEmpty())
            setValue(new Role(Integer.parseInt(text)));
    }

}

하이버를 사용하고 있으니 불 필요한 쿼리를 날리지 않도록 Fake Association Object를 활용하여 PropertyEditor를 구현합니다. 꼭 실제 객체가 필요하다면 DAO를 이용해서 가져올 수도 있겠죠. OSAF에는 두 종류의 GenericPropertyEditor로 그 두 가지 경우를 모두 지원합니다.

자 그리고 이 프로퍼티에디터를 바인더에 등록해주면 끝납니다.,

   @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(Role.class, new RolePropertyEditor());
    }

끝~.. 이제 스프링이 Role이라는 도메인 객체를 알아보고 잘 파싱해서 Member의 Set<Role> 타입의 roles라는 속성에다가 잘 설정해 줄 겁니다.


신고

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

PropertyEditor 활용 예제  (8) 2008.11.27
5. Validation, Data-binding, the BeanWrapper, and PropertyEditors  (0) 2007.03.21
top


스프링 MVC form 태그 써 보셨어요?

Spring/Chapter 13 : 2008.11.26 15:14


귿이에요.

<form:checkboxes items="${allAuthorities}" path="authorities" delimiter="<br/>" itemLabel="name"  itemValue="id" />

단 한 줄로..


저렇게 출력해줍니다. 괜찮죠? EL로 넘겨준 allAuthorities 이 녀석은 List 타입으로 도메인 객체 타입의 객체들을 담고 있죠. 흠... 화면에 보이는 값이 어째 좀 '사용자 비친화적(and 개발자 친화적)'입니다. name 말고 note를 출력하도록 할까요? 아~~주 간단합니다.

<form:checkboxes items="${allAuthorities}" path="authorities" delimiter="<br/>" itemLabel="note"  itemValue="id" />

JSP에서 단어 하나만 바꿔주면 되죠.


짜잔... OSAF의 커스텀 태그는 스프링 form 태그를 기반으로 만들었으며, 정형적인 화면 개발 속도를 극대화 할 수 있도록 만들어 두었습니다.

다음에는 PropertyEditor 활용법을 살펴보겠습니다.
신고
top


스프링소스 웨비나: 프로들의 아파치 톰캣 팁과 트릭

Spring/Webinar : 2008.11.26 00:08


마크 토마스 랑 ...
- 톰캣 커비터로 5년 넘게 일해왔다.
- 아파치 멤버
- 시니어 소프트웨어 엔지니어 이자 컨선턴트
- 스프링소스 Covalent 부서
- 성능, 트러블슈팅, 보안 전문가

톰캣 버전 얘기
- 6.0.x가 최신 버전
- 7.x가 슬슬 수면위로 들어나고 있다.(서블릿 3.0 스펙, ..)

주요 안건
- 대규모 개발에서 톰캣
- 톰캣 & JVM 업그레이드
- ...

setenv.sh - 여기서 커스텀 옵션
- JAVA_HOME
- JAVA_OPTS
- CATALINA_OPTS
- ...
- 이 파일은 톰캣이 기본으로 제공하는게 아니니깐 복사해서 가지고 다니면서 수정하라.
- 여기서 자바 버전 설정하면 톰캣 스트립트 수정하지 않아도 된다.
- 인스턴스 데이터를 분리해낼 수 있다.(별도의 톰캣 서버 인스턴스)
- 톰캣이나 JVM을 변경할 때 이 파일을 이용하면 편하다.
- RPM을 사용하면 롤백 과정이 복잡하다.

Production 세팅

server.xml
- <Server port="8005" shutdown="SHUTDOWN" > : will allow unauthorized shut-down of Tomcat instance
- <Server port="-1" shutdown="SHUTDOWN" > : 셧다운 포트 disable.
- 톰캣 멈추기: kill <pid>

애플리케이션 제거하기
- ROOT - 제공할 애플리케이션으로 대체하기
- 다음 폴더는 제거하는게 보안 최선책(security best practice)이다.
- /examples
- /docs
- /manager(원격 배포를 할 수 없게 된다.)
- /host-manager(원격 호스트 관리를 할 수 없게 된다.)

로깅
- conf/loggin.properties: 핸들러 등록
.handlers = \1catalina.org.apache.juli.FileHandler
- 파일에만 로깅한다.
- 개발할 때 가끔은 stdou/stderr가 더 쉬울때도 있다.

Rotating catalina.out(모르는 거)
- http://www.cronolog.org - 예제 도구
>> "$CATALINA_BASE" /logs/catalina.out 2>&1 &
-  하루 주기로 로테이트
2>&1 | /bin/cronlog/ ...

접근 로깅(이것도 모르는거..)
- valve를 사용해서 접근 로깅을 할 수 있다.

글로벌 기본값
- ex) 커넥션 풀
- 모든 기본 값은 conf/context.xml 또는 conf/web.xml 에 설정할 수 있다.
- 기본값은 애프리케이션에서 설정한 값이 재정의할 수 있다.

Templating
- catalina.properties의 값을 server.xml에서 사용할 수 있다.

배포 방법
- server.xm에서 <Context> 엘리먼트 사용하기
- WAR 파일 자동 배포
- 디렉토리 자동 배포
- XML 파일 자동 배포
- 원격 배포
- Best Practice는 한 가지 선호하는 방법을 사용하는 것이다. 여러 방법을 혼용하면 얘상치 못한 상황을 보게 될지도 모른다.

Building Tomcat Native(이것도 모르는 거)
- OpenSSL 소스 distro 압축 풀기
- APR 소스 distro 압출 풀기
- APR Util 소스 disto 압축 풀기
- tomcat-nartive.tar.gz distro 압축 풀기
- setenv.sh (64비트로 컴파일 했으면 64 비트 JVM 사용하도록 설정해야 한다.)

커넥터 선택하기(아파치 커넥터 얘기하는건가?)
- BIO(Blocking IO)
- NIO(None-blocking IO)
- 왜 NIO 커넥터를 사용하려는가?
- 네이티브(APR) 커넥터는 솔라시스에서 안정적이지 않다.
- NIO는 순수 자바 솔루션이다.
- SSL로 NIO와 BIO를 교환하는 건 간단하다.


버추얼 호스팅은 무엇인가?
- 단일 톰캣 인스턴스에 여러 호스트 이름 주는거
- http://a.foo.com
- http://b.foo.com

호스트 정의
- server.xml에 호스트 설정
- 자신만의 appBase 필요함
- ...

버추어 호스팅 컨텍스트 정의
- 표준 방법 적용 http://apache.org/tomcat-6.0-doc/config/context.html

버추어 호스팅 사용이 적당한 경우
- DNS 가 설정되어 있지 않을 때
- docBase == appBase
- ROOT.war 사용하지 않을 때
- ...

문서화되어 있지 않은 옵션
- W3C Extended 로그 파일 포맷
- 캐싱 - private chaching을 권장한다.

스프링소스에서 아파치 톰캣 지원

질문 답변

Q: mod_jk vs mod_proxy_ajp ? Which is preferred for Apache2.2 to Tomcat6.0.x?
A: We recommend them in the following order
 mod_proxy_http, mod_jk, mod_proxy_ajp
 we prefer the HTTP protocol, if you want AJP, mod_jk is more stable than mod_proxy_ajp (which is the newest addition)

Q: mysql-connector: why not shared/lib?
A: since connection pool library doesn't have access to shared/lib
 if you want mysql jars in the webapp, you can add a connection pool library in your webapp and configure it there. Tomcat has to follow the class loader rules

Q: Currently we see that with 3 apache servers having each 100 clients (prefork + mod_jk) each tomcat server (10) has also 100 threads. Which doesn't look logical. Is there a mod_jk config option which could change this behaviour?
A: in httpd.conf -
 JkOptions +DisableReuse
 this will turn of AJP keep alive, and you no longer have to balance threads

Q: Is Log Valves a tomcat6 feature?
A: AccessLogValves have been around in Tomcat since Tomcat 5 (possible 4) Can be found under the Valves section of the Tomcat Configuration Reference

Q: does the connector preference also apply to AJP connections (using mod_jk)?
A: Yes, with the exception of SSL. No SSL support on AJP, but you can keep more connections than threads using APR/AJP, so you no longer have to carefully balance maxThreads(Tomcat) with MaxClients(httpd)

Q: Is there a way to solve the problem of "PermGen memory error" that usually arises after many reloads of the contexts?
A: PermGen error, are very hard to resolve, as they are very subtle bugs in the web applications
 If the bug can't be fixed, increase -XX:MaxPermSize large enough to be able to reload applications during the day and then do a restart of tomcat at night

Q: If you are passing .jsp pages to Tomcat from Apache , do the Tomcat docBase and the Apache Document root need to be the same for the given Virtual Server ?
A: For security reasons, you don't want httpd to have access to the Tomcat file system (webapps), as one can exploit your configuration to download your code

ps: 큰일이네;; PPT에 집중하니까 귀는 하나도 안 들리네;;
신고
top


스프링 DM 1.2.0 m2 배포

Spring DM/etc : 2008.11.25 00:52


참조 : http://www.springsource.org/node/837

눈에 띄는 변경 사항은
- 일단 얼마전에 배포된 스프링 2.5.6을 사용하도록 변경 했다는 겁니다.
- compendium 네임스페이스를 추가했다는데..;; 뭔지 모르겠습니다. 알아봐야겠네요.
- shutdown 알고리즘을 개선했다는 군요.

나머진 잘 눈에 안 들어오고 모르겠네요~

ps: 이사 할 땐 손톱을 약간 길게 깍으세요. 평소처럼 깍았는데 이사하면서 손 끝이 부어서 그런가 굉장히 따갑습니다. ㅠ,ㅠ
신고
top


OSGi uses 충돌 감지하기

Spring DM/etc : 2008.11.23 18:39


참조 및 번역: Diagnosing OSGi uses conflicts

Glyn은 최근에 "OSGi "uses" 지시어 이해하기"를 제공했다. 나(Rob Harrop)는 uses 제약 위반 원인을 좀 더 자세히 살펴보고 여러분 애플리케이션에서 발생하는 uses 문제 해결에 유용한 몇 가지 팁을 제공하고자 한다.

나는 대부분의 예제에서 dm Server 보다는 이퀴녹스를 사용하려고 한다. 그 이유는 uses 제약사항이 dm Server에 한정적인 것이 아니고 모든 OSGi 사용자와 관련된 것이기 때문이다. 이 블로그 마지막에는, dm Server에 구축된 매우 똑똑한 제약 사항 실패 진단 몇 가지를 보여줄 것이다.

의존적인 제약 불일치(Dependent Constraint Mismatch)


가장 흔한 uses 위반은 한 개 이상의 의존적인 제약 사항끼리의 불일치 때문이다. 예제로 다음 세 개의 manifest를 살펴보자.

Manifest-Version: 1.0
Bundle-Name: Spring Bundle
Bundle-ManifestVersion: 2
Bundle-SymbolicName: spring
Bundle-Version: 2.5.5
Export-Package: spring.orm.hibernate;version="2.5.5";uses:="eclipselink"
Import-Package: eclipselink;version="[1.0, 2.0)"

Manifest-Version: 1.0
Bundle-Name: EclipseLink 1 Bundle
Bundle-ManifestVersion: 2
Bundle-SymbolicName: eclipselink
Bundle-Version: 1
Export-Package: eclipselink;version="1.0.0"

Manifest-Version: 1.0
Bundle-Name: EclipseLink 2 Bundle
Bundle-ManifestVersion: 2
Bundle-SymbolicName: eclipselink
Bundle-Version: 2
Export-Package: eclipselink;version="2.0.0"

스프링 번들 한 개와 두개의 eclipselink 번들이 있다. 물론 실제 번들은 아니다. spring 번들은 [1.0, 2.0) 버전 번위의 eclipselink 패키지를 사용한다. 분명히 오직 eclipselink_1 번들만이 이 제약 사항을 만족한다. 이제 다른 두 개의 애플리케이션 manifest를 살펴보자.

Manifest-Version: 1.0
Bundle-Name: App1 Bundle
Bundle-ManifestVersion: 2
Bundle-SymbolicName: app1
Bundle-Version: 1.0.0
Import-Package: spring.orm.hibernate,eclipselink;version="[1.0, 1.0]"

Manifest-Version: 1.0
Bundle-Name: App2 Bundle
Bundle-ManifestVersion: 2
Bundle-SymbolicName: app2
Bundle-Version: 1.0.0
Import-Package: spring.orm.hibernate,eclipselink;version="[2.0, 2.0]"

app1은 exlicpselink [1.0, 1.0] 범위를 참조하고, app2는 eclispelink [2.0, 2.0] 범위를 참조한다. 만약 이 두 개의 번들을 이퀴녹스에 설치하고 app 번들들을 start 시도하면, 콘솔에서 다음과 같은 결과를 확인할 수 있다.

id      State       Bundle
0       ACTIVE      org.eclipse.osgi_3.4.0.v20080605-1900
2       RESOLVED    spring_2.5.5
3       RESOLVED    eclipselink_1.0.0
4       RESOLVED    eclipselink_2.0.0
5       ACTIVE      app1_1.0.0
6       INSTALLED   app2_1.0.0

sprig과 eclipselink 번들들은 모두 잘 리졸브 된 걸 볼 수 있다. app1 번들은 시작(start)했지만, app2 번들은 시작하지 못했다. 이유를 알아보기 위해 diag 커맨드를 사용할 수 있다.

osgi> diag app2
file:/Users/robharrop/dev/resdiag/uses/app2/bin [6]
  Package uses conflict: Import-Package: spring.orm.hibernate; version="0.0.0"

여기서 우리는 spring.orm.hibernate 패키지를 임포트하는 부분에서 uses 충돌로 인해 해당 번들을 리졸브 할 수 없다는 것을 알 수 있다. 이것은 app2에서 spring.orm.hibernate를 임포트하는 것을 안 된다는 것이다. 그 이유는 다른 import로 인해 spring.orm.hibernate를 제공하는 번들의 uses 제약 사항이 깨질 수 있기 때문이다.

이를 진단하는 과정 처음으로 할 일은 spring.orm.hibernate 번들의 가용한 공급자를 찾아내는 것이다. 우리는 이미 해당 공급자가 spring 번들이라는 걸 알고 있지만, 만약 공급자를 모른다면 packages 커맨드를 사용할 수 있다.

osgi> packages spring.orm.hibernate
spring.orm.hibernate; version="2.5.5"<file:/Users/robharrop/dev/resdiag/uses/spring/bin [2]>
  file:/Users/robharrop/dev/resdiag/uses/app1/bin [5] imports

여기서 spring.orm.hibernate 패키지를 번들 2에서 공급(export)했다는 것을 알 수 있다. 이 정보를 가지고 번들 2의 spring.orm.hibernate에서 uses 지시어에 어떤 패키지가 등록되어 있는지 확인할 수 있다.

osgi> headers 2
Bundle headers:
 Bundle-ManifestVersion = 2
 Bundle-Name = Spring Bundle
 Bundle-SymbolicName = spring
 Bundle-Version = 2.5.5
 Export-Package = spring.orm.hibernate;version="2.5.5";uses:="eclipselink"
 Import-Package = eclipselink;version="[1.0, 2.0)"
 Manifest-Version = 1.0

여기서 우리는 uses에 있는 유일한 패키지 eclipselink 패키지가 범인이라는 걸 알 수 있다. 사실, 스프링 번들은 eclipselink [1.0, 2.0) 범위를 참조하는 반면 app2는 eclipselink [2.0, 2.0] 범위를 참조하는 걸 확인할 수 있다. 이 두 범위는 상충한다. app2는 스프링 번들이 사용하는 eclipselink와 동일한 버전을 연결할 수 없다.

uses 목록이 긴 경우는, 어떤 패키지의 제공자가 둘 이상인지를 확인하여 위반을 한 패키지 범위를 좁혀볼 수 있다. uses 제약을 위반 패키지를 제공하는 공급자는 반드시 둘 이상이다.

버전 불일치는 의존 제약 불일치의 유일한 원인이 아니다. 속성도 버전처럼 제약 문제를 발생 시킬 수 있다.

설치 순서 문제


앞선 예제를 다시 살펴보자. spring 번들의 manifest를 변경하여 eclipselink 2.0 패키지를 참조하도록 변경하고 app1은 1.0 이상의 모든 버전을 허용하도록 수정하여 문제를 수정해보자.

Manifest-Version: 1.0
Bundle-Name: Spring Bundle
Bundle-ManifestVersion: 2
Bundle-SymbolicName: spring
Bundle-Version: 2.5.5
Export-Package: spring.orm.hibernate;version="2.5.5";uses:="eclipselink"
Import-Package: eclipselink;version="[1.0, 2.0]"

Manifest-Version: 1.0
Bundle-Name: App1 Bundle
Bundle-ManifestVersion: 2
Bundle-SymbolicName: app1
Bundle-Version: 1.0.0
Import-Package: spring.orm.hibernate,eclipselink;version="1.0"

번들들을 설치하고 app 번들을 시작하면 큰 변화가 생긴걸 볼 수 있다.

id      State       Bundle
0       ACTIVE      org.eclipse.osgi_3.4.0.v20080605-1900
1       RESOLVED    spring_2.5.5
2       RESOLVED    eclipselink_1.0.0
3       RESOLVED    eclipselink_2.0.0
4       ACTIVE      app1_1.0.0
5       ACTIVE      app2_1.0.0

이제 두 개의 app 번들 모두 시작 할 수 있다. 불행히도 좀 더 교묘한 이슈가 우리를 기다리고 있다. 설치 순서에 따라, 이 번들 집합체는 같이 실행되지 않을 수도 있다. 이를 실험해보기 위해서, spring, eclipselink_1과 app1을 한 묶음으로 설치하고 app1을 실행한다.

id      State       Bundle
0       ACTIVE      org.eclipse.osgi_3.4.0.v20080605-1900
1       RESOLVED    spring_2.5.5
2       RESOLVED    eclipselink_1.0.0
3       ACTIVE      app1_1.0.0

자 이제 eclipselink_2와 app2를 설치한다.

id      State       Bundle
0       ACTIVE      org.eclipse.osgi_3.4.0.v20080605-1900
1       RESOLVED    spring_2.5.5
2       RESOLVED    eclipselink_1.0.0
3       ACTIVE      app1_1.0.0
4       RESOLVED    eclipselink_2.0.0
5       INSTALLED   app2_1.0.0

app2 번들은 시작되지 않는다. diag 통해 왜 그런지 살펴보자.

osgi> diag app2
file:/Users/robharrop/dev/resdiag/uses/app2/bin [5]
  Package uses conflict: Import-Package: spring.orm.hibernate; version="0.0.0"

uses 충돌이 다시 발생했다. 이번에는 앞선 진단 과정이 아무런 도움이 되지 않느다. 의존성 제약 불일치가 없기 때문이다. 첫 번째에 모두 잘 리졸브 됐기 때문에 이건 이미 알고 있다.

이슈는 리졸루션 순서에 있다. 번들들은 두 덩어리로 나눠서 설치하고 리졸브 했다. 첫 번째 덩어리는 spring, eclipselink_1, app1 이고 두 번째 덩어리는 eclipselink_@와 app2다. (app1 번들을 시작(start)한 결과로..)첫 번째 덩어리가 리졸브 될 때, spring 번들은 esclipselink 패키지를 가져올 때 eclipselink_1 번들에 묶이게 된다. 이것을 콘솔에서 확인해보자.

osgi> bundle app1
file:/Users/robharrop/dev/resdiag/uses/app1/bin [3]
  Id=3, Status=ACTIVE      Data Root=/opt/springsource-dm-server-1.0.0.RELEASE/lib/configuration/org.eclipse.osgi/bundles/3/data
  No registered services.
  No services in use.
  No exported packages
  Imported packages
    spring.orm.hibernate; version="2.5.5"<file:/Users/robharrop/dev/resdiag/uses/spring/bin [1]>
    eclipselink; version="1.0.0"<file:/Users/robharrop/dev/resdiag/uses/eclipselink1/bin [2]>
  No fragment bundles
  Named class space
    app1; bundle-version="1.0.0"[provided]
  No required bundles

import packages 섹션에서 eclipselink 버전 1.0.0이 eclipselink_1 번들에서 가져온 걸 확인할 수 있다. 두 번째 덩어리를 설치하면 app2 번들은 eclipselink 버전 2를 필요로 하는데, spring이 이미 eclipselink 1.0.0 버전에 묶여 있어서 리졸브되지 못한다. 한 덩어리로 모든 번들을 설치하고 리졸브 할 때는, OSGi 리졸버가 spring.orm.hibernate의 uses 제약도 만족하면서도 다른 모든 제약사항을 만족하도록 시도할 것이다.

이 문제를 고치기 위해 우리 번들을 수정할 필요는 없다. 대신, 모든 번들을 한 덩어리로 설치하거나 spring 번들을 리프래쉬 하면 된다. 그렇게 해서 OSGi가 다시 리졸루션 과정을 거치도록 한다. 이제 eclipselink_2 번들이 설치되고 이번에는 다른 결과를 예상할 수 있다.

osgi> refresh spring

osgi> ss

Framework is launched.

id      State       Bundle
0       ACTIVE      org.eclipse.osgi_3.4.0.v20080605-1900
1       RESOLVED    spring_2.5.5
2       RESOLVED    eclipselink_1.0.0
3       ACTIVE      app1_1.0.0
4       RESOLVED    eclipselink_2.0.0
5       ACTIVE      app2_1.0.0

osgi> bundle spring
file:/Users/robharrop/dev/resdiag/uses/spring/bin [1]
  Id=1, Status=RESOLVED    Data Root=/opt/springsource-dm-server-1.0.0.RELEASE/lib/configuration/org.eclipse.osgi/bundles/1/data
  No registered services.
  No services in use.
  Exported packages
    spring.orm.hibernate; version="2.5.5"[exported]
  Imported packages
    eclipselink; version="2.0.0"<file:/Users/robharrop/dev/resdiag/uses/eclipselink2/bin [4]>
  No fragment bundles
  Named class space
    spring; bundle-version="2.5.5"[provided]
  No required bundles

spring 번들을 리프래시해서 app2 번들도 리졸브 된 걸 볼 수 있다. spring 번들에서 연결할 eclipselink 패키지가 eclipselink_2 번들의 2.0 버전으로 바꼈다.

dm 서버에서 uses 제약 사항

uses 제약 위반이 dm 서버에서 발생하면, 여러분이 해야할 분석 절차를 알아서 제공해준다. 특히 불일치하는 패키지를 담고 있을 가능성이 있는 의존성 제약을 식별할 때 도움이 된다.

Could not satisfy constraints for bundle 'app2' at version '1.0.0'.
 Cannot resolve: app2
  Resolver report:
    Bundle: app2_1.0.0 - Uses Conflict: Import-Package: spring.orm.hibernate; version="0.0.0"
      Possible Supplier: spring_2.5.5 - Export-Package: spring.orm.hibernate; version="2.5.5"
        Possible Conflicts: eclipselink

uses 제약사항은 엔터프라이즈 라이브러리에서 매우 흔히 사용하며 손수 실패 원인을 분석하는 것은 악몽같은 일이다. 특히, uses를 사용하는 패키지가 10 개 이상 있을 때는, 가용한 충돌을 판별하는 작업은 상당한 시간-낭비를 초래한다. 따라서 자동화 검진은 필수이며, 나는 dm 서버에서 진당 코드가 향상되어 흔히 발생하는 문제가 아무것도 아닌 것처럼 다룰 수 있게 되길 바란다.

다음 배포판에서는, 진단 도구를 dm 서버 이클립스 툴에 바로 포함시켜서 dm 서버에서 이런 문제들을 대부분 자동으로 분석하도록 할 수 있게 할 계획이다.
신고
top


초보자를 위한 책(기술 서적)이 뭔가요?

모하니?/Thinking : 2008.11.23 17:57


인터넷에 검색하면 금방 나오는 내용들을 잘 간추려서 묶어둔 책?

영어로 된 자료를 잘 번역하고 요약하고 짜집기해서 묶어둔 책?

이해보다는 당장 써먹을 수 있는 코드 조각으로 가득차있는 책?

그런 책들이 정말 어떤 기술을 처음 접하는 초보들에게 도움이 된다고 생각하시나요??

제가 생각하는 초보를 위한 책은 이런 책입니다.

초보가 고수로 도약할 수 있게끔 생각할 여지를 주는 책.

자신이 초보일 때 (성장한) 경험을 담을 책.

코드 조각 보다는 개념과 원리를 쉽게 이해할 수 있게 돕는 책.

저런 책이야 말고 진짜 초보를 위한 책 아닐까요? 어떻게 생각하면 초보를 위한 책같은 건 없어 보입니다.

코드 조각 위주의 책이 무의미 하다는 건 절대 아닙니다. 개념과 이해를 기반으로한 코드까지 있어야 완벽하다는 것이죠. 단순히 코드만 보여주고 그걸 이해도 못하고 쓰게 하는 책은 절대로 초보를 위한 책이 아니라... 초보로 만드는 책이라는 생각합니다.

좋은 책이 나와주길 바라며~
신고
top


OSGi "uses" 지시어 이해하기

Spring DM/etc : 2008.11.23 17:08


참조 및 번역: Understanding the OSGi "uses" Directive

스프링 DM 서버 또는 다른 어떤 OSGi 플랫폼 기반의 애플리케이션을 빌드 할 때, 여러분은 아마도 머지않아 "uses"라는 지시어를 보게 될 것이다. 이 지시어의 목적을 분명하게 이해하지 않는다면, 여러분은 언제 그것을 사용해야 하는지도 모를 뿐더러, "uses" 충돌("uses" conflict)로 인해 번들 resovle가 되지 않을 때 의문만 생길 것이다. 본 기사에서 "uses" 지시어를 이해하고, 언제 사용해야 하는지, 그리고 어떻게 "uses" 충돌을 디버깅하는지 살펴보겠다.

번들 리졸루션(Resolution)


OSGi는 일단 번들이 "리졸브"(resolve) 상태가 되도록 설계되어 있다. 클래스 캐스트 예외나 타입이 맞지 않아서 발생하는 그와 비슷한 문제들이 발생하지 않도록 해야 한다. 이는 OSGi가 각각의 번들마다 하나의 클래스 로더를 사용하기 때문에 사용자들이 타입 불일치 문제를 만나게 될 여지가 많다. 그래서 매우 중요하다.

런타임에 사용하려면 일단 클래스 로더에 의해 자바 타입이 로딩이 되어야 해당 타입의 클래스나 객체 같은 것을 사용할 수 있다. 런타임 타입은 타입의 전체 클래스 이름과 해당 타입을 정의한 클래스 로더의 조합으로 정의한다. 만약 동일한 전체 클래스 이름이 두 개의 다른 클래스 로더를 사용하여 정의되어 있다면, 두 개의 호환하지 않는 런타임 타입을 생성한다. 이런 비호환성으로 인해 두 타입의 어떤 "접촉"(contact)을 하게 될 경우 런타임 에러를 발생한다. 예를 들어, 이 두 타입 중 하나를 다른 타입으로 캐스팅을 시도할 때 클래스 캐스트 예외가 발생한다.

OSGi는 유일한 클래스 로더 기반 자바 모듈 시스템이 아니지만 지금까지 가장 성숙한 시스템이다. 즉 OSGi 설계자들은 오랫동안 힘들게 이런 종류의 문제들을 다려왔고 그 해결책을 OSGi 스펙에 포함시켜왔다. OSGi 설계는 이런 문제들을 애플리케이션 코드가 동작하기 전에 발경하는 것이다. 즉 리졸루션(resolusion)이라는 단계에서 말이다. 리졸루션(Resolution)은 자바와 같은 엄격한 타입 제한 프로그래밍 언어에서 애플리케이션 코드를 실행하기도 전에 특정 문제들을 발견할 수 있는 컴파일과 유사하다. 여러분의 번들을 resovle 하려면 가끔 머리가 아플 수도 있다 하지만 이는 클래스 캐스트 예외와 같은 런타임 에러 진단을 해준다.

그래서 번들 리졸브(resolve)는 무엇을 의미하는가? 이것은 번들의 의존성을 확인했다는 뜻이다. 일반적으로 해당 번들이 사용하는(import) 패키지를 공개한(export) 번들들을 찾았고 그 버전 제약을 만족시킨다는 뜻이다. 가장 명확한 제약 사항은 모든 공개된(export) 패키지 버전이 사용하려는(import) 패키지 버전 범위 내에 포함되어야 한다. 또 다른 제약 사항으로는 패키지 임포트(import)에 기술 할 수 있는 임의 속성이 그에 대응하는 패키지 익스포트(export) 속성과 일치해야 한다는 것이다.

여러 번들에 의해 공개된 패키지


우리가 곧 살펴볼 uses 지시어는 하나 이상의 번들에 의해 공개되는 패키지에서 발생하는 타입 불일치를 해결할 목적으로 사용한다. 어떤 한 번들의 타입을 다른 번들의 타입으로 사용할 필요가 있을 때, 런타임 타입이 호환되지 않기 때문에, 타입 불일치 문제가 발생한다. 예를 들어, 어떤 번들에서 다른 번들의 클래스 이름이 같지만 다른 타입으로 타입 캐스팅을 시도할 때 클래스 캐스팅 예외가 발생한다. 어떻게 이런 일이 발생할까? 번들은 동일한 패키지를 하나 이상의 번들에서 가져올(import) 수 없기 때문이다. 상충하는 타입을 접촉(contact) 시킬 어떤 방법이 있어야 한다. It happens by a type being passed "through" a type in another package..

어떤 타입을 다른 타입으로 전달(pasess through)하는 방법은 두 가지가 있다. 첫 번째 방법은 어떤 타입이 다른 타입을 명시적으로 참조하는 것이다,. 예를 들어, 다음은 org.bar 패키지에 있는 Bar 타입의 어떤 메소드는 org.foo 패키지의 Foo 타입을 참조할 수 있다.

public Foo getFoo();

어떤 타입을 다른 타입으로 암묵적으로 전달하는 두 번째 방법은 서브타입을 이용하는 것이다, 예를 들어, 다음은 서브타입을 참조하는 메소드 시그너쳐다.

public Object getFoo();

암묵적인 경우, 서브타입의 객체는 어느 순간에는 상충하는 타입으로 캐스팅될 것이다.

자바 코드 수준에서 그런 타입 불일치가 어덯게 발생하는가. 번들 manifest가 어떻게 생겼는지 살펴보자.

필요한 타입 Foo는 org.bar 패키지를 공개하는(export) 번들과 동일한 번들이 공개하거나

bundle-symbolicname: B
bundle-manifestversion: 2
export-package: org.foo,org.bar

또는 다른 번들(F)이 공개할 수도 있을 것이다.

bundle-symbolicname: B
bundle-manifestversion: 2
export-package: org.bar
import-package: org.foo

bundle-symbolicname: F
bundle-manifestversion: 2
export-package: org.foo

"uses" 지시어는 OSGi가 위와 같은 타입 불일치를 번들 리졸루션 과정에서 진단할 수 있도록 도입되었다.

"uses" 지시어


위와 같은 잠재적인 타입 불일치를 리졸루션 과정에서 찾아내기 위해, 자바 코스 수준에서의 명시적인 또는 암묵적인 타입을 그에 상응하는 번들 manifest에 선언해야 한다. 공개하는 패키지는 "uses" 지시어를 붙여서 해당 패키지가 참조할 패키지를 선언해준다.

위 예제에서, 공개하는 패키지 org.bar는 org.foo 패키지를 "사용"(use) 한다고 선언한다.


export-package: org.bar;uses:="org.foo"


"uses" 지시어에서 사용하는 패키지나 패키지들은 "uses" 지시어를 사용하고 있는 번들 manifest에서 공개(export) 또는 가져올(import) 패키지에 명시되어 있는 것들이어야 한다. 따라서 다음은 유효한 manifest지만


export-package: p;uses:="q,r", q
import-package: r


다음은 유효하지 않은 manifest다.(q 패키지를 export 또는 import 하고 있지 않기 때문에)


export-package: p;uses:="q,r"
import-package: r


추이적인 "ueses"


타입 참조는 추이적이다. 예를 들어, 타입 C를 참조하는 타입 B를 타입 A가 참조할 경우에, A의 사용자는 B를 통해서 C를 참조할 수 있다.

타입 참조가 이렇게 추이적이기 때문에, OSGi는 자동적으로 이를 고려했다. "uses" 지시어의 "추이적인 클로져"(transitive closure)라고 알려져 있는 것이 바로 그것이다. 이것은 "uses" 지시어를 사용하기만 하면 OSGi가 알아서 추이적인 타입 참조를 다뤄준다는 것이다.

예를 들어, 다음 번들 manifest를 보자


export-package: p;uses:="q,r", q;uses:="r"
import-package: r


문법에 맞다. 다음 번들 manifest는 "p에서 q", "q에서 r" 그리고 "(추이적으로) p에서 r" 타입 참조를 충분히 잘 표현한 것이다.


export-package: p;uses:="q",q;uses:="r"
import-package: r


(역자 주, 위랑 아래랑 같으니까 아래처럼 사용해도 된다는 뜻입니다.)

"uses" 충돌 감지하기(Diagnosing)


번들 레졸루션 과정은 모든 제약 사항을 확인하는 것이 주목적이다. 따라서 모든 "uses" 제약 사항이 만족하지 않을 경우 "uses" 충돌을 보고할 것이다. 스프링 dm 서버가 주는 진단 이슈는 이런 문제를 해결하는데 도움을 준다.

원리를 이해하기 위해 만든 예제를 살펴보자. 클라이언트 번들 C가 사용할 몇몇 유틸리티 번들 F와 B을 만들고 있다고 가정해보자. 새로운 버전의 F를 추가하고다음 mainfest들을 가지고 서버에 배포한다고 가정해보자.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: F
Bundle-Version: 1
Bundle-Name: F Bundle
Export-Package: org.foo;version=1

(역자 주, 버전이 1이니까 이전에 사용하던 F 유틸 번들 이겠네요.)

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: F
Bundle-Version: 2
Bundle-Name: F Bundle
Export-Package: org.foo;version=2

(역자 주, 버전이 2니까 이번에 새로 추가한 F 유틸 번들인가 봅니다.)

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: B
Bundle-Version: 1
Bundle-Name: B Bundle
Export-Package: org.bar;uses:="org.foo"
Import-Package: org.foo;version="[1,2)"

(역자 주, 이것도 유틸 번들인데, F 유틸 번들 1와 2가 공개하는(export) org.foo 패키지 버전 1 이상 2 미만을 사용하고 있군요. 결국 F 유틸 번들 버전 1을 사용하겠네요.)

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: C
Bundle-Version: 1.0.0
Bundle-Name: C Bundle
Import-Package: org.bar,org.foo;version="[2,3)"

(역자 주, 이건 클라이언트 번들인 C 인데 org.foo 패키지를 사용하는 데 그 버전이... 이런.. 2 이상 3 미만을 사용합니다. 그러면 이 번들은 지금 새로 설치한 F 유틸 번들 버전 2를 사용하게 됩니다. 뭔가 꼬였군요. 왜냐면 여기서 또 사용하기로(import)되어 있는 org.bar 패키지에서는 F 유틸 번들 버전 1의 org.foo 패키지를 사용하니까요. 두 패키지가 호환되지 않자나요. 같은 패키지지만 다른 번들이 공개한 거니까 런타임 타입이 다르죠. 왜냐면 클래스로더가 다르니까.)

C 번들을 설치하려고 하면, dm 서버는 다음과 같은 로그 메시지를 출력한다,

<SPDE0018E> Unable to install application from location 'file:/xxx/C.jar/'. Could not satisfy constraints for bundle 'C' at version '1.0.0'.
Cannot resolve: C
Resolver report:
Bundle: C_1.0.0 - Uses Conflict: Import-Package: org.bar; version="0.0.0"
Possible Supplier: B_1.0.0 - Export-Package: org.bar; version="0.0.0"
Possible Conflicts: org.foo

이 중에서

Bundle: C_1.0.0 - Uses Conflict: Import-Package: org.bar; version="0.0.0"

이 줄은 org.bar 패키지 임포트와 관련하여 "uses" 제약 위반이 있다는 것을 알려준다. 즉, C가 사용하려고 하는 공개된(export) org.bar의 "uses"가 만족스러운 상황이 아니라는 것이다.

Possible Supplier: B_1.0.0 - Export-Package: org.bar; version="0.0.0"

이 줄은 org.bar 공급자가 의심스럽다는 것이고

Possible Conflicts: org.foo

이 줄은 어떤 패키지에서 "uses" 제약 사항이 위반되는지 알려준다.

구체적인 것에서 다시 돌아와서, 우리는 "uses" 충돌이 발생한 이유를 알고 있다. 번들 C가 가져오는 org.foo 패키지가 번들 B가 가져오는 것과 버전이 다르기 때문이다. B가 최신 버전의 F를 사용하도록 설정하는 것을 깜빡했다.

B의 manifest를 다음과 같이 수정한다.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: B
Bundle-Version: 1
Bundle-Name: B Bundle
Export-Package: org.bar;uses:="org.foo"
Import-Package: org.foo;version="[2,3)"

이제 번들 C를 성공적으로 배포할 수 있다.

복잡한 "uses" 충돌 진단하기


의도적으로 만든 "uses" 충볼은 번들 manifest를 보고서로 알 수 있을 만큼 간단한 문제였다. 하지만 매우 많은 충돌 가능성이 있는 "uses" 지시어 목록과 같은 좀 더 복잡한 "uses" 충돌의 경우, Equinox 콘솔(2401포트로 telnet)을 사용하여 성공적으로 설치된 번들을 확인해 볼 수 있다.(dm 서버는 성공적으로 배포하지 못한 번들은 uninsatll 시킨다.)

이퀴녹스 콘솔 명령어를 사용하여 설치된 번들 목록을 확인할 수 있다.,

osgi> ss

위에서 만들어본 문제 상황에서 다음과 같은 목록을 확인할 수 있다.


82 ACTIVE F_1.0.0
84 ACTIVE F_2.0.0
85 ACTIVE B_1.0.0

B 번들 manifest를 보려면 다음과 같이 한다.

osgi> headers 85

그리고 패키지 org.foo 패키지를 공개한 번들과 사용하는 번들을 보려면 다음과 같이 한다.

osgi> packages org.foo

요약


본 기사는 "uses" 지시어 필요성을 살펴봤고, 이를 사용하여 타입 불일치 에러 문제를 조기에 진단할 수 있는 방법을 보았다. 그리고 dm 서버 진단과 이퀴녹스 콘솔을 사용하여 "uses" 제약 위반을 확인하는 방법도 살펴보았다.

(마지막 단락은 번역 스킵)

You may think the "uses" directive is more trouble than it is worth, but when you consider the alternative of tracking down the reason for a possibly obscure class cast exception while your application is running, you should start to see the rationale for "uses". Indeed any Java module system which doesn't provide the equivalent of "uses" constraints is likely to give you class cast exceptions at runtime once you have gotten to the point of having multiple versions of your application modules. The OSGi "uses" directive solves a general problem of Java modularity.
신고
top


미국 가기 전 몸무게 73.05

모하니?/Thinking : 2008.11.23 15:27




조만간 미국에 컨퍼런스(Spring One Ameria)와 회사일로 보름 정도를 다녀와야 하는데 사부님께서 5kg를 찌게 해줄테니 걱정(?)하지 말라고...ㅋㅋㅋ

요즘은 운동도 안 했는데 1kg가 빠졌네요. 회사 이사 때문에 청소하느라 그런건지. 날씨가 추워져서 평소보다 열량 소모가 더 컸던거건지. 어쨌든 네 달전 여자친구한테 차였을 때 당시 몸무게에서 5키로를 뻇습니다. 키가 177~8 정도 되니까 여기서 5키로를 더 빼야 평균 체중이 됩니다. 하지만 네 달 걸려서 뺀 걸 보름 만에 롤백시키는 일이 벌어질지도 모르겠습니다.

과연~ 미국에 다녀와서 몸무게가 몇이 될 것인가... 저도 궁금합니다. +_+
신고
top


Toby's J2EE Development without EJB 정리

Spring/etc : 2008.11.21 15:04


이렇게 다른 사람의 자료를 정리해서 올리는 건 처음 인거 같네요. 제가 올렸던 글도 거의 정리를 안 하는데;; 전 사부님이 이런 글을 올렸었는지 몰랐습니다. 우왕;;

J2EE Development without EJB (1) - Why "J2EE Without EJB"?

J2EE Development without EJB (2) - Goal

J2EE Development without EJB (3) - Architecture

J2EE Development without EJB (4) - The Simplicity Dividened

J2EE Development without EJB (5) - EJB, Five Years On

J2EE Development without EJB (6) - Lightweight Container & IoC

J2EE Development without EJB 정리는 이만


안 그래도 어려운 책. 읽기 힘드시죠? 집어 던지고 싶으시죠? 시간만 잡아 먹는 것 같고, 머리만 아프고.. 일단 토비님이 정리한 걸 한 번 읽어 보신 다음에 다시 읽어보시면 조금 편하지 않을까요? 대충 문맥과 요점을 알고 보는거니깐 말이죠~

놀라운 사실은.. 글을 정리한 시점이 2004 ~ 2005년 자료라는 거... ㄷㄷㄷ 최근 글을 보니까 2004년 부터 사용하고 계셨던 것 같은데, 거의 4년을 앞서 달려온 셈입니다. 정말 놀라울 뿐입니다.
신고
top


회사 이사 중



어제부터 이사갈 건물을 청소하고 있습니다. 어젠 유리창 닦고 오늘은 바닥이랑 벽을 문질러야 되는데;; 난.. 잠을자도 잔거 같지가 않고, 온 몸이 쑤시고, 어차피 누가 대신 청소 해줄 것도 아니고~

본격적인 이사는 월요일에 하기로 했는데... 기상청에서는 그 날 전국적으로 비온다고 하고.. 그날 저녁에 KSUG 모임도 있는데.. 난 녹초되서 뻗을지도 모르겠고~

이 슬픈 마음을 피아노로 달래봅니다. 러브 스토리 테마곡인데 그걸 쉽게 편곡한 악보가 있길래 ㅋㅋ



중간 중간 좀 맥이 끊기거나, 음이 비거나, 이상한 부분은 악보가 원래 그런게 아니라 제가 잘 못 친거랍니다.ㅋ
신고

'모하니? > 그냥 놀아' 카테고리의 다른 글

미국 Alabama에 있는 햄버거 가게와 서점  (4) 2008.12.07
저는 이제 Alabama에 왔습니다.  (0) 2008.12.07
LA에서 보낸 하루(?)  (6) 2008.12.01
지금은 공항이에요  (8) 2008.11.30
LA, 마이애미, 아틀란타 날씨  (0) 2008.11.28
회사 이사 중  (2) 2008.11.21
개발자들의 수다 후기  (0) 2008.11.09
꺄오~~ 살꺼야. 키보드. 카시오 PX-320  (8) 2008.10.30
보고 싶은 피아노 공연  (0) 2008.10.22
방송탔네~  (0) 2008.10.01
KSUG 도배 성공  (2) 2008.10.01
top

TAG 이사, 회사

하이버네이트 사용시 Association Fake Object라는 기술을 사용해 보세요.

Hibernate/etc : 2008.11.19 11:28


이 기술은 사부 토비님이 알려준 기술입니다.
 
Fake Object라는 이름으로 배운 기술인데 보다 적당한 이름이 생각나서 붙여봤습니다. 유즈케이스를 보여드리자면 Post -> Board 관계에서 Post를 추가하려고 할 때 Post에 Board 객체를 어디선가 setBoard로 묶어줘야 합니다.

그걸 폼을 보여주기 전에 하거나 아니면 폼을 받아서 처리할 때 하거나.. 언젠간 해야되죠. 그럴 때 보통 다음과 같은 코드를 작성하게 될 겁니다.

폼 보여줄 때 세팅할 경우를 생각해보죠.

    @RequestMapping(method=RequestMethod.GET)
    public void add(int boardId, ModelMap model){
        Post post = new Post();
        post.setBoard(boardService.getById(boardId));
        model.addAttribute(post);
    }

결국 저 문장은 서비스 타고 트랜잭션 내에서 DAO로 가서 DB로 가서 board 하나를 select하는 쿼리가 날아가게 합니다. 하지만  Association Fake Object 기술을 사용하면 그 쿼리를 보내지 않고도 아주 잘~ 연관을 맺은 상태로 객체를 저장할 수 있습니다.

Association Fake Object 라는 이름이 이미 사용 중인 용어인지는 모르겠는데, 연관 맺을 때 사용하는 가짜 객체 라는 뜻입니다.

어떻게?? 비밀입니다. 아.. 사실 비밀도 아닙니다. OSAF에서 아주 잘 활용하고 있거든요, 후후훗.
신고
top


스프링을 사용하는 애플리케이션의 성능 최적화 방안

Spring/etc : 2008.11.18 13:38


참조: Spring In Production White Paper
번역, 요약, 편역: 백기선

어떻게 하면 스프링을 사용한 애플리케이션의 성능을 향상 시킬 수 있을까?

처음으로 할 일은 성능을 측정하여 핫스팟을 발견하고 변경으로 인해 얻을 수 있는 이점을 정량화 한다. 최적화는 두 분류 효율적인 청사진 만들기(설정 튜닝하기)와 효율적인 런타임 기능 사용하기(애플리케이션 설계 최적화)로 나뉘어진다.

측정하기

튜닝은 측정부터.. 아파치 JMeter, Selenium 그리고 프로파일러를 사용한다. 스프링소스 컨설턴트들은 JAMon을 Spring AOP나 ApsectJ와 함께 사용해서 컴포넌트의 동작이나 요청 처리 경로를 프로파일링 할 때 좋은 성과를 봤다.

효율적인 청사진 만들기

효율적인 청사진 만들기의 비밀은 배포 플랫폼의 장점을 충분히 활용하는것에 있다. 스프링이 환경 종속적인 정보를 애플리케이션 코드 밖으로 빼내어 관리하기 때문에 이렇게 하는 것이 훨씬 쉽다.

데이터베이스 커넥션 풀의 경우, 애플리케이션 서버 위에서 실행하고 있다면 풀 설정을 관리자 콘솔에서 하고 스프링에는 JNDI를 통해 참조하도록 할 수 있다.

<jee:jndi-lookup id="dataSource"
    jndi-name="jdbc/MyDataSource"/>

이렇게 하면 두 가지 장점이 생긴다. 하나는 애플리케이션을 애플리케이션 서버 콘솔을 통해 운영팀이 관리하기 쉬워진다. 두 번째는 애플리케이션 서버 밴더가 커넥션 풀을 최적화 할 것이다.

같은 이유로 JMS ConnectionFactory 와 Destinationeh 애플리케이션 서버에 설정하고 JNDI로 얻어올 수 있다.

트랜잭션 관리의 경우도, 스프링은 커스텀 플랫폼 트랜잭션 매니저를 제공하여 여러분 배포 환경에 맞는 걸 사용할 수 있도록 해준다. ex) WebLogicJtaTransactionManager, Oc4jJtaTransactionManager,
스프링 2.5에 추가된 <tx:jta-transaction-manager/> 태그가 자동으로 기반으로 하고 있는 플랫폼을 찾아서 적절한 구현체를 선택할 것이다.

스프링 JMX를 사용하여 애플리케이션 자원을 노출할 때, 제품 플랫폼이 제공하는 MBeanServer와 연동하고 싶을 것이다. ex)  웹로직-JNDI (“java:comp/env/jmx/runtime”), WebSphereMBeanServerFactoryBean,
스프링 2.5에 추가된  <context:mbean-server ... /> 태그를 사용하면 자동으로 적절한 MBeanServer를 찾아준다.

이런 장점이 있지만, 통합 테스트를 애플리케이션 서버 밖에서 하고 싶을 것이다. 예를 들어, 기본적인 메시징 테스트는 ActiveMQ를 사요해서 하지만 실제 제품을 배포할 때는 IBM의 MQSeries를 사용할 수 있다. 스프링이 여러 설정 파일을 사용하는 기능이 있기 때문에 쉽게 처리할 수 있다. 우리는 모든 환경-독립적인 설정을 핵심 애플리케이션 설정에서 분리하는 것을 추천한다. 최선책은 애플리케이션 모듈 마다 하나의 설정 파일을 유지하는 것이다. 여기에 추가로 integration-test.xml 설정과 proeduction.xml 같은 설정을 정의할 수 있을 것이다. 통합 테스트를 할 때는 적절한 모듈 설정 파일과 integration-test.xml을 사용하여 application context를 만들면 된다. 배포할 때는 production.xml 파일을 사용하면 될 것이다.

이와 관련있는 설정으로 PropertyPlaceholderConfigurer는 설정 값을 외부화 하여 운영 팀에서 변경할 수 있도록 할 때 매우 유용하다. 스프링소스 컨설턴트가 성공적으로 사용하고 있는 방법은 다음과 같이 properties 파일을 연쇄적으로 사용하는 것이다.

1. classpath*:*.properties.local: 이에 해당하는 프로퍼티 파일들은 소스 코드 관리 시스템에 포함시키지 않느다. 개발자 마다 재정의해서 쓰도록 한다.

2. classpath*:META-INF/*.properties.default: 이 속성 파일들은 빌드에 의해 생성되는 애플리케이션 요소에 포함되며 기본 설정 값들을 가지고 있다. 프로젝트의 요구사항에 따라 이 수준은 생략할 수도 있다.

3. classpath*:*.properties: 이 파일들은 애플리케이션 요소들 밖에 존재두고, 운영팀에서 쉽게 수정할 수 있게 한다.

<context:property-placeholder
  location="classpath*:META-INF/*.properties.default,
classpath*:*.properties,
            classpath*:*.properties.local"/>

효율적인 청사진 만들기에 추가적으로 생각해 봐야 할 것들
  • 최적의 JDBC 커넥션 풀 갯수 찾아보기. 테스트 할 때 실제 배포 시나리오대로 해볼 것
  • 쓰레드 풀 구현체를 사용하는 스프링의 TaskExecutor를 사용할 때 최적의 쓰레드 풀 크기를 찾아볼 것. 처음은 CPU 갯수와 동일한 쓰레드 갯수로 설정해두고, 로컬 파일 I/O를 쓰면 쓰레드 하나를 추가하고. 네트워크 기반 I/O를 할 떈 또 몇 개를 추가하는 식으로..
  • read-only 트랜잭션일 경우에는 read-only 속성을 선언할 것. 이렇게 하면 하이버네이트를 사용하여 많은 객체를 데이터베이스에서 읽은 다음 아무 일도 하지 않았을 때 정말로 성능이 향상된다. 이렇게 하면 FlushMode.NEVER로 설정되기 때문에 세션에서 불필요한 dirth checking을 하지 않는다.
  • 만약 2단 커밋이 필요 없다면, JTA 대신에 로컬 트랜잭션 매니저 사용을 고려해 보라. 스프링은 HibernateTransactionManager를 통해서 정말 쉽게 JDBC와 Hibernate 데이터 접근을 동일한 트랜잭션에서 처리하게 해준다. 둘은 다른 방법으로 DB에 접근하지만 동일한 트랜잭션을 사용한다.
  • acknowledge=”transacted" 설정을 통해 메시지 리스너 컨테이너에 네이티브 JMS 트랜잭션 사용을 고려하라.

런타임 최적화하기

대부분의 엔터프라이즈 애플리케이션 성능 문제는 영속 계층으로부터 기인한다. Good performance here is often a function of sound design choices. 몇 가지 팁을 살펴보자.
  • ORM 툴을 사용할 때, eager와 lazy 로딩 전략의 균형을 잘 맞춰야 한다. 기본으로 로딩 지연을 사용하고, 특정 경우에만 fetch-join으로 튜닝하여 이른 로딩 장점을 활용한다. 쿼리를 튜닝할 때는 데이터 셋을 제품이 지금부터 향후 1년 간을 기준으로 하라.
  • ORM 툴이나 데이터베이스를 사용하여 로그에 SQL문이 보이도록 하라. 너무 많은 쿼리가 발생하는 이규가 생길 때 이를 쉽게 찾을 수 있다.
  • 하이버네이트를 사용할 때, 하이버네이트 Statistics 객체를 사용하여 런타임에 무슨 일이 벌어지는지 알 수 있게 하라. 프로그래밍을 통해 statics에 접근하거나, 스프링을 사용하여 하이버네이트 Statics MBean을 여러분의 MBean 서버에 노출시킬 수 있다. 프로그래밍을 통한 statics 객체 사용을 JUnit 테스트에 활용하여 여러분이 예측 가능한 쿼리가 얼마나 많이 발생하는지 확인하거나, 허용하는 쿼리 수를 기술 할 수 있다. 그 수를 벗어나면 테스트가 실패하도록.
  • 배치 스타일의 기능, 벌크 업데이트 또는 추가, 스토어드 프로시저는 보통 ORM 보다는 JDBC를 사용하는 것이 최선책이다. 스프링은 이들을 혼용하기 쉽게 해준다. 예를 들어 하이버네이트와 JDBC 데이터 접근을 동일한 트랜잭션으로 할 수 있다. 이 때 동일한 테이블을 사용하는 JDBC가 제대로 동작하려면 하이버네이트 세션을 적절한 시기에 flush 해주어야 한다.
  • 데이터베이스가 제공하는 기능을 활용하라.
    • 엑셀 스프레드시트를 일겅야 하는 애플리케이션에서 간단하게 변환하고 각 행을 SQL 서버 테이블에 넣어야 한다면 3시간이 걸리는 일도 SQL 서버 lined 쿼리를 사용하면 17초 만에 뚝딱.
    • 하이버네이트로 데이터 트리를 특정 뎁쓰로 변환하는 작업을 아무리 튜닝해도 시간도 오래 걸리고 메모리로 쫑나는데, 이걸 오라클의 스토어드 프로시저로 오라클의 계층 쿼리 기능으로 하니까 5초 미만으로 해결 됨.
    • flat 파일을 오라클 데이터베이스로 읽을 필요가 있을 때, 오라클 SQL 로더를 사용하여 데이터를 staging 테이블로 읽어들인다음, 스토어드 프로시저로 변경하고 데이터를 복사하여 원하는 테이블에 넣을 수 있다.
  • 만약 (비즈니스 로직은 전혀 없고)완전한 영속 로직만 있는 메소드가 있다면 데이터베이스의 스토어드 프로시저로 옮기고 스프링 JDBC를 사용하여 그것을 호출하라.
  • 읽기 전용 참조 데이터는 메모리 내부의 캐시에 둘 수 있다.
배치 애플리케이션은 추가적으로 고려할 것이 있다. 메소드 사용이 중요하기 때문이다. 스트림-기반 알고리즘이 최선의 선택이다. 예를 들어 컬렉션 보다는 이터레이터를 사용하라. 파일을 가지고 작업할 때, 만약 줄을 나눠야 한다면 스프링-기반이 아니라 캐릭터-기반을 사용하라. 우리는 이런 접근 방법을 사용하여 2백 50만 줄을 읽어 들인 적이 있다. 파싱하고 처리하는데 4초 미만이 걸렸고 메모리는 102K만 사용했다.

XML을 사용하는 배치 애플리케이션도 스트리밍을 사용하라. 우리는 280mb 파일에 들어있는 100,000개의 복잡한 XML 이벤트를 처리해야 할 필요가 있었다. DOM 기반의 접근 방법으로 2.5 시간이 걸렸고, 가비지 컬렉팅으로 9분이 필요했다. XML pull-parshing 기반 접근 방법으로 바꾸었더니 3초 만에 처리가 끝났고 200k 메모리를 사용했다.

또 다른 팁으로 단위 테스트와 통합 테스트를 할 때 java.lang.management 패키지에 있는 JVM 통계정보를 사용하는 것이다. 그것을 사용하면 CPU와 가비지 컬렉션 시간들을 확인할 수 있다.

데이터 계층을 위한 마지막으로 조언으로  every team benefits from access to a good DBA.

이밖에 스프링소스 컨설턴트로부터 얻은 다른 최적화 방안은 다음과 같다.
  • 스프링 배치 프로젝트가 제공하는 retry 기능을 사용하여 실패시 재시도가 필요할 때 사용할 수 있다.(예를 들어, 오라클 RAC의 개별 노드에서 실패한 기능의 경우) 사용자가 에러를 만나는 부담을 덜어줄 수 있다.
  • 웹 요소 랜더링 비용을 과소평가 하지 말아라. 트랜잭션 밖에서 되길 원할 것이다.(이부분 때문에 OSIV 패턴 이야기가 나왔군..)
  • application context를 요청 마다 새로 생성하지 말아라.
  • 스프링의 비동기 task executer를 사용하여 백그라운드에서 실행해도 될 작업을 사용자가 기다리게 하지 말아라.
  • 적절한 리모팅 프로토콜을 선택하라. 만약 SOAP 호환이 필요없다면, 스프링의 HttpInvoker 같이 간단한 스키마를 사용하는 것이 더 간단하고 빠를 것이다.
  • 스프링 AOP를 애플리케이션의 굉장히 여러 부분에 적용하고 있다면 ApsectJ 사용을 고려하라
스프링소스 컨설턴트들이 최적화에 도움을 얻은 참고자료는 다음과 같다.
  • Thomas Kyte's “Runstats.sql” test harness
  • “Effective Oracle by Design” (Thomas Kyte)
  • “Java Performance Tuning” (Jack Shirazi)
  • Sun's Java Performance Guides


신고
top


하이버네이트, 스프링, 트랜잭션, OSIV(Open Session In View) 패턴

Spring/Chapter 12 : 2008.11.17 15:10


참조

No Hibernate Session bound to thread 에러로 시작한 OSIV 얘기
http://forum.springframework.org/archive/index.php/t-33082.html

논쟁에서 언급한 HibernateTemplate API
http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/orm/hibernate3/HibernateTemplate.html

스프링의 OpenSessionInViewFilter API
http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.html

하이버네이트 위키 OSIV
http://www.hibernate.org/43.html

손권남님의 OSIV 정리
http://kwon37xi.springnote.com/pages/1075048

InfoQ에서 Spring In Production 요약한 것
http://www.infoq.com/news/2007/11/spring-production

댓글에 보면 OSIV 패턴이 안티 패턴인가에 대한 내용이 있음
http://blog.springsource.com/2007/11/09/download-the-spring-in-production-white-paper/

Tip4에서 OSIV 패턴은 안티 패턴이라고 한다.
http://www.realsolve.co.uk/site/tech/orm-performance.php

이미 세션이 닫힌 상태에서 뷰에서 Detached 객체에서 아직 로딩하지 않은 객체에 접근하면 에러(LazyInitializationException)가 발생합니다. 이 에러는 정상적인 에러죠. 하이버네이트 맵핑을 Lazy loading으로 최소한의 객체만 로딩하도록 하고 필요할 때 연관을 맺고 있는 객체를 추가로 가져오도록할 때 흔히 발생하는 아주 정상적인 에러입니다.

이런 상황을 극복하려면 필요한 객체를 미리 팻치(Eager Fatch)해둔 상태로 로딩하는 메소드를 DAO쪽에 구현해서 뷰에서 추가로 세션을 사용할 필요없이 뷰 랜더링을 마치도록 하면 되기도 하고..

아니면 OSIV 패턴을 사용해서, 인터셉터나 필터를 적용해서 뷰를 완전히 랜더링 할 때까지 세션을 열어 두는 겁니다. 그럼 뷰를 랜더링 하다가 필요한 객체가 있으면 세션을 사용해서 로딩할 수 있겠죠. 그럼 위의 방법처럼 DAO에 이른 팻치를 해서 가져오는 별도의 메소드나 쿼리를 만들지 않아도 되겠죠.

흠.. 하지만 뷰에서 자신도 예측하지 못한 쿼리가 계속 발생할 여지도 있고, 웹 단에서 데이터 캡슐화를 깨기 때문에 OSIV를 안티패턴으로 보고 사용을 최소화 해야 한다는 주장도 있습니다.

스프링 + 하이버네이트 조합을 쓸 때 OpenSessionInViewFilter를 자주 사용하는데, 이 API는 아주 잘 봐둘 필요가 있습니다. 그 중에서 가장 주목해야 할 부분은 다음과 같습니다.

1. 기본 플러시 모드는 FlushMode.NEVER입니다. NEVER는 deprecated 됐는데, 아직 사용하고 있습니다. 이 걸 왜 주의해야 하냐면, OSIV를 등록하고 만약 서비스 계층에 @Trasaction을 설정하지 않았다고 해봅시다. 그럴 때 트랜잭션 처리는 됩니다. 왜냐면 OSIV 때문이죠. 요청이 들어오면 해당 요청을 처리할 쓰레드에 새로운 세션 만들고 그걸로 트랜잭션 만들어서 쓰기 때문에 트랜잭션은 있는데 문제는 플러시 모드가 NEVER라서 명시적으로 flush()를 호출하기 전까지는 절대로 DB에 반영이 안 됩니다.

2. Conversation을 하나의 세션을 늘리는 방법(extending a sesion for conversation)으로 구현할 경우에, persistence 객체의 reassociation을 최대한 요청 처리 초기에 해야 합니다. 안 그럼 나중에 동일한 객체가 또 있다고 충돌 날 수가 있습니다. 이 문제에 대응하기 위해서 singleSession이라는 옵션에 false 값을 줄 수도 있지만, 그렇게 하면 매 요청 마다 새로운 Session 만들어서 사용하겠다는 것이고 Conversation을 구현하는 다른 방법(detached 객체를 가지고 구현하는 방법)으로 구현해야 될 것 같습니다. 즉 코딩할 때 조금 주의해서 단일 세션으로 Conversation을 사용할 것이냐, 아님 단순하게 요청 마다 새로운 세션으로 만들고 객체들을 붙였다 띄었다 할 것이냐 인데.. 필요한 객체를 계속 하나의 세션에 들고 유지하는게 좀 더 효율적이지 않을까 싶네요.


신고
top


최근에 맛들린 피아노~



토비님 추천으로 카시오 PX-320을 지르고 매일 1~2 시간을 연습하고 있습니다. 요즘 맹렬히 연습하고 있는 곡은 따로 있는데 자꾸 중간 중간 틀려서 녹음 시도를 몇번이나 했지만.. 실패했습니다. ㅠ.ㅠ 대신에 아~주 쉬운걸로.. ㅎㅎ 영화 "말할 수 없는 비밀"에서 주인공 아버지가 아들이 집에 없는 틈에 혼자 감정 잡고 피아노 치다가 걸리는 부분에 나오는 건데.. 정말 쉽습니다.




신고
top


새로운 스프링소스 웨비나 일정

Spring/Webinar : 2008.11.16 12:38


참조: http://www.springsource.org/node/828

일시: 한국 시간으로 11월 25일 밤 11시~12시
주제: Apache Tomcat Tips and Tricks from the Pros
내용: 아파치 톰캣을 보다 빠르고, 쉽고, 생산적으로 관리하는 방법
세부내용
    * Setting up your Apache Tomcat infrastructure for large scale deployments
    * How to upgrade and easily rollback different Apache Tomcat and JVM versions
    * How to migrate your Apache Tomcat configurations during upgrades
    * Apache Tomcat connector configurations
    * Best practices around virtual host configurations in Apache Tomcat
    * Undocumented configurations options

신고
top


Validator에도 여러 가지가 있네

모하니?/Coding : 2008.11.15 23:15


JSF 스캐(스크린캐스팅)를 찍다가 알게 된건데, 기본 검증기, Application-level 검증, 커스텀 검증기, 표준 검증기가 있었습니다.

기본 검증기는 프레임워크에서 제공하는 것으로 JSF에는 길이 검사라던가, 숫자가 최소치와 최대치 사이의 값인지 범위를 검사할 수 있는 기본 Validator들을 제공하고 있었습니다. 스프링 MVC는 어떨까요? 글쎄요. 없는 것 같네요. ValidationUtils는 있지만 JSF 처럼 간단하게 뷰에서 바로 써먹을 수 있는 건 없는 것 같습니다.

다음은 폼에서 이미 검증을 마쳐서 모델에 사용자가 입력한 데이터를 담은 상태로 비즈니스 로직을 검사하는 검증입니다. 이 검증은 프레임워크에 독립적이며 도메인 클래스가 해당 로직을 가지고 있기도 합니다. 예를 들어.. member.validateBy주민번호() 같은 메소드(주민등록 번호로 성별과 생년 월일이 일치하는지 검사하는 로직)를 만들고 이를 컨트롤러에서 호출한 다음에 예외를 잡아서 화면에 어떤 에러 메시지를 출력하는 방법이 있겠습니다. 비즈니스 로직에 적합한지 검사하려면 역시 화면에 붙어있는 검증기와는 별개로 이런게 필요한 것 같습니다. 스프링MVC에서도 검증 로직이 순전히 도메인 레벨에서 가능하다면 이런 식으로 검증할 수도 있겠습니다.

다음은 검증기는 검증기인데, 특정 인터페이스를 따르지도 않고 완전한 POJO 검증기 입니다. 위에서 애플리케이션 검증 로직을 별도의 클래스로 빼내고 그 로직을 뷰에서 값을 입력 받을 때 호출하게 하는 건데, JSF의 EL은 메소드 호출도 정말 간단하게 할 수 있더군요. 그냥 이런 검증기를 managed-bean으로 등록하고 그 로직을 호출하면 됐습니다. 검증 로직을 별도의 클래스로 분리하고 한 곳에서 관리할 때 좋겠습니다.

마지막은 스프링이 제공하는 Validator인터페이스 처럼 프레임워크의 틀에 맞는 검증기를 구현하고 그것을 설정하여 사용하는 겁니다. JSF에도 그런 구조가 갖춰져 있죠. 이 걸 사용하는 장점은 어떤 틀이 있기 때문에 위처럼 중구 난방으로 작성할 수 있는 코드에 규약을 정하고 그걸 따르는 검증기를 공유할 수 있다는 겁니다. JSF는 스프링 @MVC와 달리 이 검증 로직 실행을 프레임워크의 Phase 중에서 Validation Phase에 하기 때문에 이 검증 로직을 만족하지 못하면 모델에 값이 들어갈 수가 없습니다. 스프링은 아니죠. 일단 모델에 값을 받은 상태에서 검증을 하는거죠.

흠~~ 그래서 결론적으로 생각해볼 때, 여러 검증 단계와 방법을 제공하는 건 JSF가 더 좋아보이지만, 모델에 값을 설정한 상태에서 Validator라는 규격을 가지고 그 안에서 비즈니스 로직 검사도 수행(application-level 검증)도 할 수 있는.. 스프링 MVC의 단순한 구조가 오히려 개발을 더 깔끔하게 할 수 있게 해주지 않나 생각합니다. 모든 개발자가 검증 로직을 사방한대서 한다고 생각하면.. 어휴.. 끔찍하죠.ㅋㅋ
신고
top


하이버네이트 Criteria 검색 쿼리 골치



select this_.id as y0_ from Post this_ where this_.board_id=?

select this_.id as id1_0_, this_.author as author1_0_, this_.board_id as board7_1_0_, this_.contents as contents1_0_, this_.created as created1_0_, this_.title as title1_0_, this_.updated as updated1_0_
from Post this_
where this_.id in (?, ?, ?, ?, ?, ?) and  lcase(this_.title) like ? or lcase(this_.contents) like ?

===============================================

select this_.id as id1_0_, this_.author as author1_0_, this_.board_id as board7_1_0_, this_.contents as contents1_0_, this_.created as created1_0_, this_.title as title1_0_, this_.updated as updated1_0_
from Post this_
where this_.board_id=? and (lcase(this_.title) like ? or lcase(this_.contents) like ?)

================================================

select this_.id as id1_0_, this_.author as author1_0_, this_.board_id as board7_1_0_, this_.contents as contents1_0_, this_.created as created1_0_, this_.title as title1_0_, this_.updated as updated1_0_
from Post this_
where this_.id in
(select this0__.id as y0_ from Post this0__ where this0__.board_id=?)
and (lcase(this_.title) like ? or lcase(this_.contents) like ?)

=================================================

셋 다 똑같네.. 아.. 이런 ㅠ.ㅠ OTL... 뭐야 ㅠ.ㅠ 어떻게 짜야되지. 흠...

(lcase(this_.title) like ? or lcase(this_.contents) like ?)

이 부분이 잘못 됐나? title에 ?가 있거나 contents에 ?가 있는 것들 검색하려는데 분명 테스트 데이터에는 두 개가 나와야 되는데 계속 한 개만 나오네. 흠... 모르겠네... 모르겠어..

=====================
id | title       | contents
1  | keesun | toby
2  | toby      | toby
3  | toby      | keesun
=====================

이 상태에서 서브 쿼리나 in 뒤에 담겨있는 id는 전부 1, 2, 3이라고 치고... titke이 keesun이거나 contents가 keesun이 row를 갖다 달라는 거자나.

그럼 1번 row를 보면 title이 keesun이니까 맞자나. title이 keesun 이자나 contents는 아니고 그럼 일단 하나.
그리고 3번은 contents가 keesun이니까 맞고..

그럼 결과가 2개가 되야 하는데

결과는 1번만 가져오는... 이 상황은 ..;;; 어렵네~
신고
top


음헤헷 봄싹 게시판 검색 MVC 완성





먼저 뷰는 위 그림과 같이 간단합니다. 기본값을 설정해서 바로 검색 버튼 눌러서 검색할 수 있도록 해뒀습니다.

기본 값은 다음과 같습니다.

현재일 까지 세 달치 검색, 검색어가 없으면 모두 검색. 있으면 해당 키워드가 있는 제목 또는 본문을 가진 글 검색.

작성일 검색 조건 바뀔 때마다 달력으로 검색 범위를 표현해주면 좋겠는데.. 그런 멋진 UI는 나~~~~중에.. 해보기로 하구요. 일단 저렇게 해놨습니다.

<h1>${board.name} 게시판 검색</h1>
<form:form commandName="param" action="/post/list.do">
    검색어 <form:input path="keyword"/>
    <form:checkboxes items="${ref.fieldNames}" path="fieldNames" /><br/>
    작성일: <form:input path="basicDate"/>
    <form:select path="dateSearchingType" items="${ref.dateSearchingTypes}" />
    <form:select path="dateSearchingTerm" items="${ref.dateSearchingTerms}" /><br/>
    <input type="submit" value="검색"/>
</form:form>


뷰 핵심 코드는 스프링 form 태그를 이용해서 간단하게~ 샤샥...

저 화면을 보여주는 컨트롤러 코드는

    @RequestMapping
    public void search(int boardId, ModelMap model){
        model.addAttribute("param", new PostSearchParam());
        model.addAttribute(boardService.getById(boardId));
    }


참 쉽죠?

저 화면의 폼 처리를 하는 컨트롤러 코드는

    @RequestMapping
    public void list(@ModelAttribute("param")PostSearchParam param, ModelMap model){
        System.out.println(param.getKeyword());
        System.out.println(Arrays.toString(param.getFieldNames()));
        System.out.println(param.getBasicDate());
        System.out.println(param.getDateSearchingTerm().name());
        System.out.println(param.getDateSearchingType().name());
//        model.addAttribute(postService.list(param));
    }

요거.. 전 아직도 sysout 디버깅이 넘 좋아요.ㅋㅋ 일단 잘 받는 것 까지 해야 그 다음으로 DAO에서 검색해서 가져오고. 어쩌구 저쩌구를 구현해야 하는데 여기서 한 번 끊고 가는거죠. DAO쪽에선 검색 조건 테스트 할 께 많을테니까요. 짧은 단위로 개발하기..

자.. 저 정도 코드면 될까요? 안 돼죠. 저 녀석들이 주연이면 조연이 필요합니다.

public enum DateSearchingTerm {

    ONE(1, "한 달"), TWO(2, "두 달"), THREE(3, "세 달"), ALL(0, "모두");

    private int duration;

    private String description;

    DateSearchingTerm(int duration, String description) {
        this.duration = duration;
        this.description = description;
    }

    public int getDuration() {
        return duration;
    }

    public String getDescription() {
        return description;
    }

    public String toString() {
        return description;
    }
}

이 녀석은 작성일 검색 기간 enum으로 duraion은 나중에 DAO에서 검색 조건 만들 때 사용할 속성입니다. 약간 미리 예상하고 만들어 둔 속성이라 거시기 한데... 뭐 필요없어지면 지워버리죠. 하나를 봤으니 딴 건 안 보겠습니다.

public class DateSearchingTermPropertyEditor extends PropertyEditorSupport {

    @Override
    public String getAsText() {
        Object value = getValue();
        if(value == null)
            return "";
        else
            return value.toString();
    }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        if(text.equals("한 달"))
            setValue(DateSearchingTerm.ONE);
        if(text.equals("두 달"))
            setValue(DateSearchingTerm.TWO);
        if(text.equals("세 달"))
            setValue(DateSearchingTerm.THREE);
        if(text.equals("모두"))
            setValue(DateSearchingTerm.ALL);
    }

}

이 녀석은 프로퍼티 에디터 나중에 폼 처리하는 메소드에서 바인딩 할 때 모르는 타입이라고 에러가 날 겁니다. 그래서 이 녀석을 등록해줘야 하죠,

등록은 컨트롤러에서..

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);

        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
        binder.registerCustomEditor(DateSearchingTerm.class, new DateSearchingTermPropertyEditor());
        binder.registerCustomEditor(DateSearchingType.class, new DateSearchingTypePropertyEditor());
    }

이렇게 해도 되고 쟤들은 다른 컨트롤러도 사용할 테니까 나중에 글로벌하게 XML에 다음의 코드를 이용해서 등록해도 되겠죠

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="cacheSeconds" value="0" />
    <property name="webBindingInitializer">
        <bean class="org.springframework.samples.petclinic.web.ClinicBindingInitializer" />
    </property>
</bean>
from 스프링 레퍼런스 13장




쪼아.. 이제 DAO 구현하러 ㄱㄱㄱ...
신고
top


게시판에서 글 검색 기능은 어떻게 만들까?



이번주 봄싹 스터디에서는 검색 기능을 구현해 가려고 합니다. 원랜 페이징까지 구현해 가려고 했는데 요즘 번역이 좀 밀려서 번역에 에너지를 쏟았더니 눈이 아파서 코딩을 못하겠네요.

어쩃든, 검색 기능을 어떻게 구현할지 생각해 봤습니다. 제가 주로 이용하던 검색은 구글이나 네이버 같이 어떤 글을 검색할 땐 키워드 하나면 충분합니다. 그 키워드가 어떤 글의 내용이 될 수도 있고 작성자나 글 제목이 될 수도 있겠죠. 그래서 좀 더 세분화 하기 위해서 어떤 필드(제목, 내용, 글쓴이)를 검색할 키워드로 사용할 것인지를 선택할 수 있도록 기능을 제공해야겠다는 생각이 들었습니다.

다음은 글을 쓴 날짜가 관건인데 이 부분은 고민이 좀 됐습니다. 날짜를 두 개씩 받아서 Between으로 검색을 하자니 매번 날짜 입력하기도 참 불편하고 그렇다고 날짜가 없으면 가져오는 데이터가 너무 많고 그래서 샤워하다가 생각난 것이 은행 사이트의 거래 내역 조회입니다. 은행 사이트에서 거래 내역 조회할 때 보통 기본값으로 1주일이나 한 달치가 검색이 되고 어떤 사이트는 최대 Between을 세 달로 제한해서 검색 대상이 되는 데이터의 범위를 줄여놨습니다. 이걸 게시판에 응용해볼 생각입니다.

검색 조건 파라미터를 나타내는 클래스의 필드는 총 다섯개 입니다.

String keyword
Stringp[] filedNames
Date baseDate
DateSearchingTerm dateSearchingTerm
DateSearchingType dateSearchingType

필드 이름은 String 타입의 속성 이름 배열이 되고 그 중에서 keyword를 가진 녀석들을 검색할 겁니다. 그리고 날짜는 baseDate를 기준으로 type에 따라 하향(from), 상향(to), 중심(around)으로 term 만큼 검색을 할 겁니다. UI 기술이 좀 받쳐주면 아주 잼난 UI를 만들 수 있겠는데 일단은 단순 입력으로 가야겠죠. 전 UI에 약합니다. ㅠ.ㅠ

여기서 재밌는게 DateSearchingTerm 이랑 DateSearchingType 인데, 이 녀석들은 enum으로 만들 겁니다. enum으로 선택지를 만들어 두고 enum이 제공하는 name()과 values() 메소드를 이용해서 화면에 뿌릴 이름을 toString()을 재정의 해서 보여줄 것이고 선택지 컬렉션을 화면에 전달할 겁니다. 이 녀석들은 기본 타입이 아니라 스프링이 어떻게 바인딩 해야 하는지 당연히 모르겠죠. Date도 마찬가지 입니다. 그래서 커스텀 에디터를 만들어서 등록해주고, 차후에는 Date 검색 부분만 따로 분리해서 다른 도메인의 검색 파라미터에서도 재사용하기 쉽도록 해야겠습니다.

오늘은 맥주를 마셨으니 코딩은 내일로 미루고 오늘은 피아노나 조금 치다가 자야겠습니다. Good Night~
신고
top


@Repository를 쓴다면 하이버네이트 예외 변환기 직접 만들 필요 없습니다.

Spring/Chapter 12 : 2008.11.12 10:52


스프링이 2.0부터 제공하고 있었는데, 이제서야 알게 됐습니다. 저는 그동안 뭘...;;;; 한 거죠.. ㅋㅋㅋ 이 것 참..;; 혹시 저만 빼고 다들 알고 계셨던건 아니겠죠? 저는 게다가 항상 @Repository 애노테이션을 쓰고 있었거든요. 그런데도 몰랐습니다. @Repository 애노테이션 API에도 안 나와있네요.

하이버네이트 예외 변환기가 언제 필요하냐면.
1. 하이버네이트 DAO 구현을 스프링 API에서 독립적으로 구현하고 싶을 때. 다른 말로 하이버네이트 SessionFacotry를 직접 주입해서 사용하고 싶을 때.
2. 하이버네이트 예외를 스프링 DataAccessException으로 변환하고 싶을 때.

위 두 가지 조건이 만족한다면 사용하고 싶을 겁니다. 그럴 때 만약 @Reposity라는 애노테이션으로 빈 스캔을 사용해서 빈을 등록하고 있다면 예외 처리기를 만들 필요 없이 빈 하나만 등록해주면 끝납니다.

<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

끝~ 저 클래스는 이름이 암시하듯이 스프링의 빈 포스트 프로세서로, 등록된 빈 중에 @Repository가 붙어있는 빈에 persistenceExceptionTranslationAdvisor 이런 어드바이저를 적용한 프록시 빈으로 교체해주는 멋진 녀석입니다. AOP와 빈 포스프 프로세서의 조합. 캬오... 스프링엔 이렇게 멋진 코드가 곳곳에 숨어있군요.

핵심코드 감상 하기...
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> targetClass =
                (bean instanceof Advised ? ((Advised) bean).getTargetSource().getTargetClass() : bean.getClass());
        if (targetClass == null) {
            // Can't do much here
            return bean;
        }
       
        if (AopUtils.canApply(this.persistenceExceptionTranslationAdvisor, targetClass)) {
            if (bean instanceof Advised) {
                ((Advised) bean).addAdvisor(this.persistenceExceptionTranslationAdvisor);
                return bean;
            }
            else {
                ProxyFactory proxyFactory = new ProxyFactory(bean);
                // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
                proxyFactory.copyFrom(this);
                proxyFactory.addAdvisor(this.persistenceExceptionTranslationAdvisor);
                return proxyFactory.getProxy(this.beanClassLoader);
            }
        }
        else {
            // This is not a repository.
            return bean;
        }
    }

위 코드는 유겐 휄러와 로드 좐슨이 작성한 코드입니다.

ProxyFactory를 사용해서 직접 프록시 만드는 방법은 어제 올린 스크린 캐스팅에 포함되어 있었죠. Advised 인터페이스에 대해서도 언급 했었구요. 스프링 AOP 스캐를 보신 분들이라면 무리 없이 이해하실 수 있을 겁니다. 귿~
신고
top


SpringSource DM Server 실습할 것 1

Spring DM/etc : 2008.11.11 23:01


서버 로그 확인
- cd serviceability/trace/
- less trace.log

서버 실행 할 때 옵션주기
- bin/startup.sh -jmxremote
- jconsole

덤프뜨기(jconsole에서)
- 덤프 버튼 클릭
- 생성된 덤프 파일 확인(amte 파일경로)

웹 프로젝트 만들기
- new -> project -> springsource dm server -> module project
  - 모듈 타입을 web으로 설정 할 것
  - 페이지 컨텍스트 설정 할 것
- MODULE-INF 폴더 만들기(웹 기본 폴더가 되는 듯), 그 뒤에 웹 리소스 쫘르륵..
- 컨트롤러 추가하기
- Manifest.mf에 Import-Library: org.springframework.spring;version="[2.5.5.A,3.0.0)" 추가
- META-INF 밑에 spring 폴더 만들고 스프링 설정 파일 추가.
  - module-context.xml
  - 컴포넌트 스캔
  - 뷰 리졸버
  - AnnotationMethodHandlerAdapter
- 프로젝트를 S2DM 서버로 드래그 앤 드랍
- localhost:8080/페이지 컨텍스트 경로 확인.

동영상을 보고 따라해보려고 해봤지만, 굵은 글씨 부분에서 막혔습니다. 저렇게 추가를 해도 라이브러리를 못찾습니다. 번들 클래스 패스에 추가가 되어야 할텐데 그게 안 되네요. 흠.. 플러그인 문제인듯.. 그게 잘 되야 좀 편하게 개발할텐데..
 
신고
top







티스토리 툴바