Whiteship's Note

'Spring'에 해당되는 글 355건

  1. 2009.10.27 [전자정부 개발프레임워크 교육자료] 표준 프레임워크 개요 PPT 감상문 (6)
  2. 2009.10.18 [스프링 3.0] @Valid 실습
  3. 2009.10.18 [스프링 3.0] @Valid 이론
  4. 2009.09.28 [스프링 3.0] 애노테이션 기반 스케줄링 (2)
  5. 2009.09.26 드이어 스프링 3.0 RC1이 나왔습니다. (3)
  6. 2009.09.22 [Expert One-on-One J2EE Design and Development] J2EE 프로젝트를 위한 설계 기술과 코딩 표준 2
  7. 2009.09.18 [Expert One-on-One J2EE Design and Development] J2EE 프로젝트를 위한 설계 기술과 코딩 표준 1
  8. 2009.09.15 [Expert One-on-One J2EE Design and Development] 실용적인 데이터 접근 2
  9. 2009.09.15 [Expert One-on-One J2EE Design and Development] 실용적인 데이터 접근 1 (4)
  10. 2009.09.03 [Expert One-on-One J2EE Design and Development] J2EE 아키텍처 3
  11. 2009.09.02 [Expert One-on-One J2EE Design and Development] J2EE 아키텍처 2 (2)
  12. 2009.09.01 [Expert One-on-One J2EE Design and Development] J2EE 아키텍처 1 (2)
  13. 2009.08.20 [스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 4
  14. 2009.08.19 [스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 3
  15. 2009.08.13 [스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 2
  16. 2009.08.13 [스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 1
  17. 2009.07.27 스프링의 이메일 기능 지원과 테스트를 살펴보자 (2)
  18. 2009.06.10 [Spring 3.0] HiddenHttpMethodFilter (4)
  19. 2009.04.21 Spring Expression Language(SpEL) (2)
  20. 2009.04.20 What's new in Spring 3.0? (2)
  21. 2009.04.03 우와~ 스프링 tc 서버다!! (6)
  22. 2009.03.23 스프링 프레임워크 트레이닝 갈까말까 (6)
  23. 2009.03.17 스프링 웨비나: Building Twitter with Grails in 40 Minutes
  24. 2009.03.09 REST in Spring 3: @MVC (8)
  25. 2009.03.05 STS(Spring Tool Suite) 2.0 RC 버전의 OSGi 개발 툴 (2)
  26. 2009.03.04 스프링 3.0 m2 빌드 삽질 중 (4)
  27. 2009.02.26 Petclinic을 통해 스프링 3.0 주요기능 살펴보기 (6)
  28. 2009.02.07 스프링 트랜잭션 주의할 것 (7)
  29. 2009.02.04 빈 속성에 값 설정 했는지 확인하기
  30. 2009.02.04 싱글톤, 비싱글톤 언제 써야 할까? (9)

[전자정부 개발프레임워크 교육자료] 표준 프레임워크 개요 PPT 감상문

Spring/etc : 2009. 10. 27. 17:45


6 페이지

개발프레임워크는 단위컴포넌트, 래퍼(Wrapper), 정적인아키텍처, 동적인아키텍처로 구성되어 있으며, 일반적으로 단위 컴포넌트는 오픈소스나 상용 솔루션을 도입함.

음.. 그렇구나. 개발 프레임워크는 네 가지로 구성 되는 구나. 근데 도통 모르겠네, 래퍼는 대충 뭔지 알겠는데, 단위 컴포넌트, 정적 아키텍처, 동적 아키텍처는 뭐야.

단위 컴포넌트는 특정한 기술적/업무적 목적을 지원하는 블라브라.. 아 몰라 몰라;;
정적 아키텍처는 객체들간의 연관 관계를 다루고 동적 아키텍처는 객체들간의 상호작용을 다룬다고??? 이게 뭔소리야!!!!! 아 놔.. @_@... 패스

58 페이지(MVC)

// 업무로직은 controller가 담당, 여러 View에서 재사용.

으응??? 진짜????? 컨트롤러가 담당한다고? ㅋㅋㅋㅋㅋ 여러 뷰에서 뭘 재사용해.. 뭘.. 컨트롤러를?? 흠..;; 이것 참...

 59 페이지(ORM)

일반적인 개발
매핑 적용: 테이블 컬럼과 자바 클래스간의 직접적인 매핑 필요
유연성: SQL 변경시 코드를 직접 변경하고 배포해야 함
표준 패턴: 패턴 없음
DB 제어: 직접적으로 DB제어 가능
활용 기술: SQL

ORM 구축
매핑 적용: 개발자는 직접 객체지향 관점에서 처리 가능
유연성: 매핑 정보의 수정만으로 적용 가능
표준 패턴: 매핑 정보, XML 등이 템플릿 형태로 적용됨
DB 제어: Mapping의 경우 직접적인 제어가 어려울 수 있음
활용 기술: Persistence 프레임워크 (Hibernate, iBatis)

이야.. ORM 좋네. 매핑 정보만 수정하면 배포 안 해도 되는거야?? 대신 DB 제어는 직접적으로(?) 못해?? 진짜?? ORM도 SQL 쓰지 안쓰나.. 흠.. 희한하네..

61 페이지(DI)

DI(Dependency Injection)는 컴포넌트 간 연관성 및 참조 정보를 직접적으로 코드 내에서 가지는 것이 아니라, 외부 파일 등에 연관 정보를 설정하고, WAS가 기동 하는 Run-Time시에 연관 정보를 가지도록 하는 것임

일반적인 개발
컴포넌트: EJB 컴포넌트 활용 (무겁고 복잡함)
유연성: 참조 변경이나 컴포넌트 재사용시 어려움 (컴포넌트 내부 코드 변경 필요)
표준 패턴: 패턴 없음
연관 제어: 연관성 파악이 어려움 (전체 코드 분석 필요)
활용 기술: EJB

DI 구축
컴포넌트: 순수 자바 코드 (POJO) 활용하여 컴포넌트 구현 Lightweight Component 체계
유연성: 쉽게 참조 변경 가능하고 재사용 가능 (컴포넌트 내부 코드 변경 불필요)
표준 패턴: 매핑 정보, XML 등이 템플릿 형태로 적용됨
연관 제어: 설정 파일 만으로 연관성 파악 가능
활용 기술: Component 프레임워크 (Spring, HiveMind)

DI하기 참~~ 어렵구만, WAS가 있어야 돼. 젠장...

근데, 정작 중요한 "테스트"에 대한 얘기는 거의 없네.. "테스트 도구" 얘기만 있고.. 테스트는 다른 PPT에서 다루나.

뭐 일단은 재밌네!! 캬캬캬.

다른 것도 봐야지
top

  1. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.10.27 22:23 신고 PERM. MOD/DEL REPLY

    살살.. ㅎㅎ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.10.27 22:38 신고 PERM MOD/DEL

    이정도면 살살아냐? 난 이제 영어 공부나 해야지

  2. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.10.28 14:51 PERM. MOD/DEL REPLY

    무슨 개그 콘서트 대본 인줄 알았네요...@_@;;;

    원본은 어디서 볼수 있나요?

    Favicon of http://whiteship.me BlogIcon 기선 2009.10.28 15:02 PERM MOD/DEL

    http://www.egovframe.go.kr/

    자료실 밑에 교.육.교재에 있습니다.

    Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.10.28 21:44 PERM MOD/DEL

    고맙습니다. :)

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.10.28 22:37 PERM MOD/DEL

    ㅎㅎ재밌게 보세요~

Write a comment.


[스프링 3.0] @Valid 실습

Spring/3.0 : 2009. 10. 18. 12:57


1. 라이브러리 추가.

        <!-- Validation -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>com.springsource.org.hibernate.validator</artifactId>
            <version>4.0.0.GA</version>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>com.springsource.javax.xml.bind</artifactId>
            <version>2.1.7</version>
        </dependency>

2. 빈 설정.

    <bean
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="cacheSeconds" value="0" />
        <property name="webBindingInitializer">
            <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
                   <property name="validator" ref="validator" />
               </bean>
        </property>
    </bean>
   
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

3. 애노테이션 기반 검증 설정

    @Column(length = 100)
    @NotEmpty(message="제목을 입력하세요!")
    private String title;
    @Column(columnDefinition="TEXT")
    @NotEmpty(message="제목을 입력하세요!")
    private String contents;

4. 컨트롤러 코드 수정.

    @RequestMapping(value = "/notice/update/{id}", method = RequestMethod.POST)
    public String updateForm(@Valid Notice notice, BindingResult result, SessionStatus status) {
        if (result.hasErrors()) {
            return "notice/update";
        } else {
            noticeService.update(notice);
            status.setComplete();
            return "redirect:/notice/" + notice.getId() + ".do";
        }
    }

끝~!! 기본 에러 메시지는 애노테이션에서 변경할 수 있습니다.

이제 JSR 303 애노테이션과 그 확장 애노테이션에 뭣들이 있는지 살펴봐야겠네요.
top

Write a comment.


[스프링 3.0] @Valid 이론

Spring/3.0 : 2009. 10. 18. 11:45


http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ch05s07.html#validation.mvc

스프링 3.0에서 검증(validation) 설정에 대한 자바 표준인 JSR-303을 지원하기 시작했습니다.

public class Person {

    @NotNull
    @Max(64)
    private String name;
   
    @Min(0)
    private int age;

}

이런식으로 도메인 모델에 검증 메타데이터를 정의할 수 있는거죠. 이렇게 정의해둔 정보들은 JSR-303 Validator가 검증할 때 활용합니다. 이 검증기는 하이버네이트가 구현한것도 있고, 스프링 3.0에서 제공하는 것도 있습니다.

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

스프링에서 제공하는 검증기는 위에 있는 클래스입니다 이 클래스는 javax.validation.Validator 인터페이스와 org.springframework.validation.Validator 인터페이스를 구현했기 때문에 필요한 곳에서 적당한 인터페이스 타입으로 참조해서 사용하면 됩니다.

이밖에도 커스텀 @Constraint 만드는 방법과 DataBinder에서 스프링 검증기 사용하는 방법이 나와있으나 그 부분은 생략하겠습니다. 저는 지금 스프링 3.0 MVC에 적용하는 방법을 익히려고 정리중입니다.

이전까지는 @Controller 기반 컨트롤러를 사용할 때는 Validation 과정을 일일히 손수 코딩해줘야했습니다. 그러나 이제는 스프링이 자동으로 검증로직을 호출도록 설정할 수 있습니다. 그 방법이 바로 이 글의 제목인 @Valid죠.

@Controller
public class MyController {

    @RequestMapping("/foo", method=RequestMethod.POST)
    public void processFoo(@Valid Foo foo) { ... }

}

스프링 바인딩이 끝나면, 해당 객체에 설정된 Validator를 호출해 줍니다. 이때 호출해야 할 Validator를 설정하는 방법은 두 가지가 있습니다. 하나는 @Controller의 @InitBinder 마다 설정하는 방법이고, 다른 하나는 글로벌한 InitBinder라고 볼 수 있는 WebBindingInitializer에 설정하는 방법입니다.

@Controller
public class MyController {

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.setValidator(new FooValidator());
    }
   
    @RequestMapping("/foo", method=RequestMethod.POST)
    public void processFoo(@Valid Foo foo) { ... }
   
}

이 방법과~

<!-- Invokes Spring MVC @Controller methods -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="webBindingInitializer">
        <!-- Configures Spring MVC DataBinder instances -->
        <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
            <property name="validator" ref="validator" />
        </bean>
    </property>
</bean>

<!-- Creates the JSR-303 Validator -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
               
이런 방법이 있군요.

그럼? 스프링이 검증 해준 다음은 어떻게 되는걸까요?? 검증 에러는 어떻게 받아오나? 검증 에러가 있으면 알아서 이전 폼을 다시 보여주나? 핸들러에서는 그럼 서브밋 됐을 때의 로직만 구현하는 되는건가? 실험해봐야겠군요.
top

Write a comment.


[스프링 3.0] 애노테이션 기반 스케줄링

Spring/3.0 : 2009. 9. 28. 18:17


참조: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ch25s05.html

웹 애플리케이션을 띄울 때 구글 토크 봇을 로그인 시켜두려고 스케줄링을 이용하려 했습니다. 찾아보니까 애노테이션 기반으로 설정할 수 있는 기능이 추가됐더군요.

<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>

<task:executor id="myExecutor" pool-size="5"/>

<task:scheduler id="myScheduler" pool-size="10"/>}

이렇게 task:annotation-driven 엘리먼트를 XML에 추가해주면 빈에 설정되어 있는 @Schedule과 @Async 애노테이션을 활성화 시켜줍니다.

@Schedule 애노테이션은 cron, fixedDelay, fixedRate 세 가지 속성 중 하나를 이용해서 설정해야 합니다. 반드시 이 셋 중에 하나는 설정되어 있어야 합니다.

@Async 애노테이션은 해당 메서드 호출을 비동기로 처리해주고 싶을 때 사용할 수 있습니다. 즉 이 애노테이션으로 스케줄링이 적용된 메서드를 호출하면 결과는 바로 리턴되고 실제 실행은 스프링의 TaskExecutor에 의해 별도의 Task 내부(이 녀석이 별도의 쓰레드겠죠)에서 실행됩니다.

막상 해보니 라이브러리 때문에 에러가 나더군요.

        <dependency>
            <groupId>edu.emory.mathcs.backport</groupId>
            <artifactId>com.springsource.edu.emory.mathcs.backport</artifactId>
            <version>3.1.0</version>
        </dependency>

그래서 필요한 라이브러리를 추가해주고 돌려보니까 잘 돌아갑니다.

그런데 해보고 나니까 굳이 반복 실행할 필요가 없는 메서드라;;; -_-;; @PostConstruct 애노테이션 붙여서 끝냈습니다.

이 간단한것을... 스캐쥴링은 머하러 찾아봤담;;
top

  1. 대한민국토리 2009.09.28 23:34 PERM. MOD/DEL REPLY

    그러게요. 글 처음에는 스케쥴링이 꼭 필요한 기능인 줄로만 느껴졌는데, 글 말미에는 스케쥴링이 필요없는 걸로 맺음 하셔서 읽고 나서 당황했어요^^

    덕분에 스케쥴링에 대해 찾아보고 좋았습니다.

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.09.29 00:10 PERM MOD/DEL

    ㅎㅎㅎ반전이죠.

Write a comment.


드이어 스프링 3.0 RC1이 나왔습니다.

Spring/3.0 : 2009. 9. 26. 08:14


http://www.springsource.org/node/2004

주요 변경 사항은 다음과 같습니다.

Changes in version 3.0.0.RC1 (2009-09-25)
-----------------------------------------

* upgraded to CGLIB 2.2, AspectJ 1.6.5, Groovy 1.6.3, EHCache 1.6.2, JUnit 4.7, TestNG 5.10
* introduced early support for JSR-330 "javax.inject" annotations (for autowiring)
* introduced early support for JSR-303 Bean Validation (setup and MVC integration)
* added default editors for "java.util.Currency" and "java.util.TimeZone"
* refined PathMatchingResourcePatternResolver's treatment of non-readable directories
* PathMatchingResourcePatternResolver understands VFS resources (i.e. works on JBoss 5.x)
* revised AccessControlContext access from BeanFactory
* AbstractBeanDefinitionParser can deal with null return value as well
* PropertyOverrideConfigurer's "ignoreInvalidKeys" ignores invalid property names as well
* PropertyPlaceholderConfigurer supports "${myKey:myDefaultValue}" defaulting syntax
* BeanFactory's default type conversion falls back to String constructor on target type
* BeanFactory tries to create unknown collection implementation types via default constructor
* BeanFactory supports ObjectFactory as a dependency type for @Autowired and @Value
* BeanFactory supports JSR-330 Provider interface as a dependency type for @Inject
* BeanFactory prefers local primary bean to primary bean in parent factory
* protected @Autowired method can be overridden with non-annotated method to suppress injection
* private @Autowired methods with same signature will be called individually across a hierarchy
* @PostConstruct processed top-down (base class first); @PreDestroy bottom-up (subclass first)
* ConfigurationClassPostProcessor detect @Bean methods on registered plain bean classes as well
* support for default "conversionService" bean in an ApplicationContext
* MBeanServerFactoryBean returns JDK 1.5 platform MBeanServer for agent id "" (empty String)
* changed NamedParameter/SimpleJdbcOperations parameter signatures to accept any Map value type
* refined logging in JMS SingleConnectionFactory and DefaultMessageListenerContainer
* introduced "ui.format" package as an alternative to PropertyEditors for data binding
* @RequestMapping annotation now supported for annotated interfaces (and JDK proxies) as well
* @RequestParam and co support placeholders and expressions in their defaultValue attributes
* @Value expressions supported as MVC handler method arguments as well (against request scope)
* JSR-303 support for validation of @MVC handler method arguments driven by @Valid annotations
* refined response handling for @ExceptionHandler methods
* @ResponseStatus usage in handler methods detected by RedirectView
* all @SessionAttributes get exposed to the model before handler method execution
* @Event/ResourceMapping uniquely mapped to through event/resource id, even across controllers
* MultipartRequest is available as a mixin interface on (Native)WebRequest as well
* removed outdated "cacheJspExpressions" feature from ExpressionEvaluationUtils
* introduced common ErrorHandler strategy, supported by message listener container
* Jpa/JdoTransactionManager passes resolved timeout into Jpa/JdoDialect's beginTransaction
* HibernateJpaDialect applies timeout onto native Hibernate Transaction before begin call
* Spring's Hibernate support is now compatible with Hibernate 3.5 beta 1 as well
* Spring's JPA support is now fully compatible with JPA 2.0 as in EclipseLink 2.0.0.M7
* SpringJUnit4ClassRunner is now compatible with JUnit 4.5, 4.6, and 4.7
* SpringJUnit4ClassRunner once again supports collective timeouts for repeated tests
* deprecated @NotTransactional annotation for test classes in favor of @BeforeTransaction

봄싹 사이트에 어서 적용해 봐야겠네요.
top

  1. 대한민국토리 2009.09.28 23:37 PERM. MOD/DEL REPLY

    2번항목의 JSR-330 에 대해서 언급한 블로그가 있길래 링크 겁니다.

    http://chanwook.tistory.com/789#comment4556871

    생각보다 관심가지고 계신 분들이 많은데요...^^

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.09.29 00:14 PERM MOD/DEL

    아.. 찬욱이네요.ㅎㅎ
    전 DI 표준 보다 JSR-303 벨리데이션 쪽이 더 관심이 갑니다.

  2. Favicon of http://www.timberlandbaratas.com BlogIcon zapatos timberland 2012.12.25 12:12 PERM. MOD/DEL REPLY

    This airport can offer you outdoor parking options. There are about 567 parking spaces accessible. Fees differ in accordance with the model of vehicle and they are paid for 24-hour period, http://www.timberlandbaratas.com Timberland. Car hire agencies introduced at the airport comprise Avis, http://www.timberlandbaratas.com zapatos timberland, Budget, http://www.timberlandbaratas.com Timberland Online, National, and Hertz. Bus services between Port Louis and the airport run quite often each 30-60 minutes during the day, http://www.timberlandbaratas.com Mujer Timberland. Taxis are accessible outside the terminal structure always. About 60 taxis serve the Mauritius airport. An information desk is put centrally in the terminal structure, http://www.timberlandbaratas.com outlet timberland. There are some ATMs out off the arrival hall, http://www.timberlandbaratas.com timberland niños, plus currency exchange service is accessible in the check-in hall located in departures area. Also, there are bank offices in the departures areas and arrivals. A post office is placed out off the arrivals hall.Related articles:


    http://skywalker.tistory.com/332 Le patron de la Société des courses de Compiègne (Oise) a démenti samedi avoir bénéficié d'un

    http://ebhanglobaltopics.tistory.com/162 Selon un communiqué de presse de l'organisateur chilien du Dakar-2011

Write a comment.


[Expert One-on-One J2EE Design and Development] J2EE 프로젝트를 위한 설계 기술과 코딩 표준 2

Spring/J2EE D&D : 2009. 9. 22. 11:04


참조: Expert One-on-One J2EE Design and Development 4장

Template Method 디자인 패턴

알고리즘 단계와 그 순서를 알고 있지만, 그 각각의 단계가 구체적으로 어떻게 수행될지는 예측할 수 없을 때 사용할 수 있는 디자인 패턴이다. 템플릿 메서드 패턴은 어떻게 수행될지 모르는 부분을 추상 메서드로 캡슐화 하고, 알고리즘을 순서대로 지니고 있는 추상 클래스를 제공한다. 중요한 개념은 그 추상 클래스가 워크 플로우를 관리한다는 것이다. public 상위 클래스의 메서드는 보통 final이고, 추상 메서드는 protected다.

이렇게 워크 플로우 로직을 추상 상위 클래스로 모아둔 것은 IoC의 예에 해당한다. 할리우드 원칙("Don't call me I'll call you")이라고도 하는 이 원칙은 일반적인 클래스 라이브러리처럼, 사용자 코드가 라이브러리를 사용하는 것이 아니라, 프레임워크 코드가 사용자 코드를 호출한다. 바로 이런 IoC가 프레임워크의 기본이며, 프레임워크는 보통 템플릿 메서드 패턴을 아주 많이 활용한다.

...

템플리세 메서드 패턴은 훌륭한 SoC(Separation of concern)를 제공한다. 상위 클래스는 비즈니스 로직에 집중하고 하위 클래스는 세부 기능 구현에 집중한다.

추상 상위 클래스가 인터페이스를 구현하도록 하는 것이 좋다.

Stratege 디자인 패턴

전략 패턴은 행위를 인터페이스로 빼낸다. 따라서 알고리즘을 알고 있는 클래스는 더이상 추상 클래스가 아니며 구체 클래스가 해당 인터페이스를 구현한 헬퍼를 사용한다. 전략 패턴은 템플릿 메서드 패턴 보다 작업할 것이 많지만, 더 유연하다.

저자(로드 존슨)는 다음과 같은 경우 템플릿 메서드 패턴보다 전략 패턴을 선호한다.

- 모든 스탭이 변하는 경우
- 스탭을 구현하는 클래스가 독립적인 인터페이스 계층 구조를 필요로 할 때.
- 스탭 구현이 다른 클래스와 연관이 있을 경우.
- 스탭 구현체가 실행시에 바뀌어야 하는 경우
- 스탭 구현체가 매우 다양하며 계속 늘어날 여지가 있는 경우.

확장성을 위해 콜백 사용하기

또다른 "IoC"를 사용하여 단일 작업을 매개변수화 해보자. 엄밀히 말하자면, 이것은 일종의 Strategy 디자인 패턴이다.

이 패턴은 메서드에서 호출할 여러 콜백 메서드로 구성된다.

이 패턴은 특히 JDBC같은 저수준 API를 사용할 때 유용하다.

*예제코드는 JdbcTemplate.query() 에서 사용하는  RowCallbackHandler*

다음과 같은 장점과 단점이 있다.

장점
- 프레임워크 클래스가 에러 처리, 자원 가져오기/반납하기를 할 수 있다. 즉 JDBC를 사용할 때 필요한 복잡한 에러 처리를 한 번만 작성하고 그것을 호출하여 사용할 수 있다. 에러 처리와 자원 반납이 복잡할수록 이 방법이 돋보인다.
- 이것을 사용하는(호출하는) 코드는 저수준 API를 신경 쓸 필요가 없다.
- JDBC 같은 저수준 API를 사용할 때 코드 재사용성을 높여준다.

단점
- 실행 플로우 자체를 다루는 코드를 실행하는 것 보다 덜 직관적이다. 코드를 이해하기 어려울 수 있고 관리가 어려워질 수 있다.
- 콜백 핸들러 객체를 만들어야 한다.
- 드문 경우, 인터페이스를 통해 콜백을 호출하니까 성능이.. 문제가..  (이건 좀.. )

이 패턴은 콜백 인터페이스가 매우 가단한 경우에 최대의 가치를 지닌다.

Observer 디자이니 패턴

인터페이스를 사용하는 것 처럼, 옵져서 디자인 패턴도 변경 없이 확장을 가능케하며(Open Closed Principal) 컴포넌트 간의 의존성을 낮춘다. 또한 관심사 분리(Separation of concerns)에도 기여한다.

주의할 것. 리스너는 작업을 빨리 마쳐야한다. 악당같은 리스너는 애플리케이션을 대기시킬 수 있다. 최대한 빨리 리턴하도록 하고 오래 걸리는 작업은 별도의 쓰레드로 분리한다. 리스너는 또한 동기화와 공유 객체 문제도 피해야하고 반드시 멀티 쓰레드에 안전해야 한다.

옵저버 디자인 패턴은 단일 서버보다 클러스터 배포시에 덜 유용하다. 오직 단일 서버에서만 이벤트를 발생시켜주기 떄문이다. 예를 들어 데이터 캐시를 갱신하는데 옵저버 패턴을 썼다면 그런 갱신은 오직 단일 서버에서만 발생할 것이다. 하지만, JMS를 사용한다면 클러스터 환경에서도 그러한 것이 가능하다. 하지만 API 복잡도와 성능 부담은 증가할 것이다.

저자의 경험상 옵저버 패턴은 EJB 단 보다는 웹 단에서 유용하다.

11장에서 옵저버 디자인 패턴을 애플리케이션 프레임워크에서 구현하는 방법을 살펴보겠다.

메서드 매개변수 뭉치기

public void setOptions(Font f, int lineSpacing, int linesPerPage,
                       int tabSize);

이런 것을

public void setOptions(Options options);

이렇게. (이건 리팩토링 기술에 있던것 같은데. 흠..)

주요 장점은 유연성이다. 더 많은 매개변수를 추가해도 메서드 시그너쳐를 변경하지 않아도 된다.

Command 디자인 패턴이 이런 접근 방법을 사용한다.

단점은 객체 생성이 많아질 수 있다는 것이다. 사용하는 메모리가 늘어나고 가비지 컬렉션을 필요로 하게 될 것이다. 객체는 힙 사이즈를 소비하지만, 기초타입은 그렇지 않는다. 이게 문제가 될지는 메서드가 얼마나 자주 호출되느냐에 달려있다.

 
top

Write a comment.


[Expert One-on-One J2EE Design and Development] J2EE 프로젝트를 위한 설계 기술과 코딩 표준 1

Spring/J2EE D&D : 2009. 9. 18. 11:37


참조: Expert One-on-One J2EE Design and Development 4장

좋은 코드란 무엇인가?

- 좋은 코드는 엄청난 변경이 필요없이도 확장이 용이하다.
- 좋은 코드는 읽기 쉽고 유지보수가 편하다.
- 좋은 코드는 문서화가 잘 되어있다.
- 좋은 코드는 나쁜 코드가 발생할 여지가 적다.
- 좋은 코드는 테스트하기 편하다.
- 좋은 코드는 디버깅하기 편하다.
- 좋은 코드는 중복 코드가 없다.
- 좋은 코드는 재사용된다.

J2EE 애플리케이션을 위한 객체지향 설계 권고사항

많은 개발자들이 J2EE API를 익히는데 시간을 많이 소비하지, 좋은 코딩 습관을 기르는데는 너무 시간을 투자하지 않는다. SUN의 J2EE 예제 애플리케이션만 봐도 그런 걸 알 수 있다.

저자(로드존슨)의 경험을 바탕으로 볼 때 좋은 객체지향 원칙을 따르느 것은 탁상공론에 그치는 것이 아니라 실용적인 가치를 전해준다.

객체지향 설계는 (J2EE나 심지어 자바 같은) 특정 구현 기술 보다도 더 중요하다. 좋은 프로그래밍 습관과 적절한 OO 설계는 좋은 J2EE 애플리케이션의 기반이다. 나쁜 자바 코드는 나쁜 J2EE 코드가 된다.

인터페이스를 통해 의존성 낮추기(Loose coupling)

"구현체가 아닌 인터페이스를 사용하여 프로그래밍하라."
Progeam to an interface, not an implementation.

인터페이스 기반 접근방법의 장점

- 호출하는 쪽 코드를 변경하지 않고도 구현 내용을 변경할 수 있다.
- 인터페이스 구현의 자유. 오직 하나의 클래스 상속에 모든 걸 맡길 필요는 없다.
- 간단하게 테스트 구현체와 스텁 구현체를 만들어 제공할 수 있다.

딱딱한 상속 보다는 객체 조합을 선호하라(Composition)

"클래스 상속보다 객체 컴포지션을 선호하라"
Favor object composition over class inheritance

C++과 달리 자바의 클래스 상속은 한개의 클래스만 상속할 수 있다. 클래스 계층 구조는 매우 엄격하다. 클래스의 구현체 일부만 바꾸는 것이 불가능하다.(상위 클래스를 바꾸면 나머지도 다 바뀐다는 뜻인듯.) 하지만, 인터페이스로 그 부분을 (Strategy 패턴과 위임을 사용하여)캡슐화하면 문제는 해결된다.

객체 컴포지션은 클래스 상속보다 훨씬 유연하다. 자바 인터페이스는 위임을 자연스럽게 만들어준다. 객체 컴포지션은 -호출하는 쪽에서 행위를 표현하고 있는 인터페이스의 구현체를 주입하여- 객체의 행위를 실행중(런타임)에 변경할 수 있게 해준다. Strategy와 State 패턴이 이런 접근방법을 사용한다.

클래스 상속이 잘못 사용되는 예

- 간단한 인터페이스 구현이 필요한 상황인데도, 사용자가 추상 또는 구체 클래스를 상속받아 쓰도록 강제한다.  이렇게 하면 사용자 코드가 자신만의 상속 구조를 만들 수 있는 권한을 빼앗는 것이다.

- 하위 클래스가 사용할 헬퍼 메서드들을 상위 클래스에 놓고 클래스 상속을 사용한다. 만약 그 클래스 계층구조 밖에서 헬퍼 메서드를 호출할 필요가 있다면 어떻게 되는가? 객체 컴포지션이 낫다.

- 인터페이스 대신 추상 클래스를 사용하는 경우. Template Method 패턴처럼 추상 클래스가 매우 유용할 떄도 있다. 하지만 추상 클래스는 인터페이스의 대체제가 아니다. 인터페이스를 구현하는 유용한 과정일 뿐이다. 타입을 정의하고자 추상 클래스를 쓰지는 말아라.  다중 상속이 막혀있는 자바에게는 문제가 될 수 있다.

인터페이스는 간단하게 유지할수록 그 가치가 극대화 된다. 인터페이스가 복잡해지면 많은 양의 코드 구현을 해야하기 때문에 추상 클래스 또는 구체 클래스 상속을 강요하게 될 것이다. 따라서 그 가치가 떨어진다. 인터페이스의 적덜한 세밀도가 중요한 경우이다.
 
인터페이스 상속(클래스로 부터 기능을 상속받는 것이 아니라 인터페이스를 구현하는 것)은 클래스 상속보다 훨씬 유연하다.

그럼 클래스 상속이 나쁘다는 걸까? 전혀 아니다. 클래스 상속은 객체 지향 언어에서 코드를 재사용하는 강력한 방법을 제공한다. 하지만 높은 수준의 설계 접근 방법 보다는 구현 방식으로 생각해야 한다. 애플리케이션의 전반적인 설계로 강요하기 보다는 그 사용 여부를 우리가 선택할 수 있어야한다.


top

Write a comment.


[Expert One-on-One J2EE Design and Development] 실용적인 데이터 접근 2

Spring/J2EE D&D : 2009. 9. 15. 21:05


참고: Expert One-on-One J2EE Design and Development 9장

일반적인 JDBC 추상 프레임워크

JDBC API와 그 이슈를 이해하는 것으로 충분하지 않다.

JDBC API를 사용할 때는 항상 도무이 클래스를 사용하여 애플리케이션 코드를 간편화하라. 하지만, O/R 맵핑 계층을 손수 작성하지는 말자. O/R 맵핑이 필요하다면 기존의 솔루션을 사용하라.

동기

저수준 JDBC 코딩을 하는 것은 고통스럽다. 문제는 SQL이 아니라, 코드량이다. JDBC API는 일부 엘레강트하지 않으며 애플리케이션 코드에서 사용하기에는 너무 저수준이다.

SQL 자체는 간단하지만 이 쿼리를 조회하는데 30줄의 JDBC 코드가 필요하다. 거기에 중첩 try-catch까지 보니까 프레임워크 클래스로 리팩토링하고 싶은 강한 욕구를 느낀다.

*고수준 추상화 API*

간단한 추상화 프레임워크를 만들어서 JDBC API 사용을 훨씬 간편하게 할 수 있다.

AvailabilityQuery  availabilityQuery  =  new AvailabilityQuery (ds); 
List 1= availabilityQuery.execute(1, 1) ;

이렇게 할 수 있다. 이 쿼리 객체를 재사용할 수 있으며, execute() 메서드는 런타임 예외를 던진다. 즉 복구가 가능할 경우 필요에 따라 예외를 잡아서 처리할 수도 있다. JDO의 Query 인터페이스와 비슷하다.

목표

파레토 원칙을 기억하는가(80:20) 최선의 결과는 JDBC 추상화 계층으로부터 얻을 수 있다. 추상화 계층은 다음 요소들에 초점을 맞춘다.

- 너무 많은 코드
- 에러 발생시 깔끔한 클린업 - 대부분이 깨진 try-catch를 사용하는데 이를 방지한다.
- SQLException 다루리 - 검증형 예외일 필요가 없다.
- 사용자 코드를 작성하기 쉽게한다.

놀랍게도 이 문제를 다루는 프레임워크와 라이브러리가 많지 않다. 따라서 내가(로드 존슨) 예제 애플리케이션에서 사용할 용도로 프레임워클 개발했다.

이게 유일한 방법은 아니지만, 간단하고 매우 효율적이다.

예외 처리

JDBC API는 예외를 어떻게 사용하지 말하야하는지에 대한 교훈이다.

JDBC는 단일 예외 클래스를 사용한다. "뭔가 잘못됐다" 라는 것 빼고는 알 수가 없다. 이미 살펴봤다시피, 벤더 관련 코드와 SQL 예외를 구분할 수 있다.

다음은 모든 RDBMS에서 의미가 있는 에러들이다.
- 문법 에러
- 데이터 무결성 제약 위반
- SQL의 값을 부적절한 타입의 변수에 바인딩 시도

이런 문제는 java.lang.SQLException의 하위 클래스로 만들어져야 한다. 우리가 만들 추상화 프레임워크에서 풍부한 에러 계층 구조를 제공할 것이다.

JDBC 에러 처리를 할 때 다음의 이슈들도 다룬다.

- 우리가 만들 추상화 계층 코드가 JDBC에 묶이지 않기를 원한다. DAO 패턴 구현체에서 사용할 수 있도록 의도하고 있다. 만약 DAO를 사용하는 코드가 SQLException 같은 특정 리소스에 국한된 것을 처리해야 한다면 비즈니스 로직과 (DAO 패턴을 구현한)데이터 접근 구현체 간의 디커플링(decoupling)을 할 수가 없다. (메서드 시그너처에 들어가기 떄문에..) 따라서 JDBC API는 JDBC 관련 예외를 사용하더라도 우리가 만들 예외 계층 구조는 JDBC에 묶이지 않게 만들겠다.

- 4자에서의 검증형 예외와 비검증형 예외 논의에 따라 모든 예외를 런타임 예외로 만들겠다. JDO가 이런 접근 방법을 통해 좋은 결고를 냈다. JDBC 예외는 대부분 복구가 불가능하기 때문에 이런 방법이 적절하다.

- EJB를 쓴다면 블라 블라. 생략.

일반적인 데이터 접근 예외 계층구조

일반적인 데이터 접근 예외 계층구조를 만들어서 위와 같은 요구사항을 만족시킬 수 있다. JDBC 사용에만 국한 되지 않고 데이터베이스를 사용하는 DAO에서 모두 사용할 수 있다.

계층 구조의 최상위는 DataAccessException 클래스다. NestedRunitmeException을 상속받았다. 이 상위 클래스는 감쌓아야 할 예외를 스택 트레이스에 유지할 수 있게 해준다. 자세한건 4장에..

DataAccessException은 구체적인 데이터 접근 문제를 나타내는 하위 클래스를 가지고 있다.
- DataAccessResourceFailureException
자원을 가져오지 못한 경우에 발생. JDBC용 구현에서는 데이터베이스에서 connectino을 가져오지 못했을 때 발생한다.
- CleanupFailureDataAccessException
작업 수행을 잘 마치고 깨끗히 정리를 못했을 때 발생. JDBC용 구현에서는 Connection을 닫지 못했을 때 발생.
- Datalntegr ityViolationExcept ion
- InvalidDataAccessApiUsageException
- InvalidDataAccessResourceUsageException
부적절한 SQL을 날릴 때 발생
- OptimisticLockingViolationException
- DeadlockLoserDataAccessException
- UncategorizedDataAccessException
차마 분류하지 못한 것들...

JDBC 예외를 일반적인 예외로 변환하기

지금까지는 SQL 예외를 일반적인 예외로 변환하는 방법을 생각하지 않았다. 그렇게 하려면 SQLState 코드와 벤더 코드를 분석해야 한다. 하지만 SQLState로는 모든 문제를 분석하기에 적절치 않다. RDBMS 구현체 특화된 옵션들을 분석해야 한다.

변환 기능을 제공하는 인터페이스를 만든다. (보통 인터페이스를 사용하는 설계가 이식성을 얻을 수 있는 최선책이다.) 이 책에서는 SQLExceptionTranslater 인터페이스를 구현할 것이다.

public interface SQLExceptionTranslater {
    DataAccessException translate(String task, String sql, SQLException  sqlex);
}

*SQLState 코드를 사용하는 SQLExceptionTranslater 기본 구현체 코드*

정적인 데이터 구조(HasSet)를 만들어서 if/else 문을 줄였다.(묶을 수 있는 에러덩어리들을 하나의 맵에 넣어두고 map.contains()를 사용하여 if문 사용을 줄였군요.. 오호...)

*오라클에 특화된 구현체 OracleSQLExceptionTranslater*

벤더 코드가 SQLState 코드 보다 훨씬 많다.

2 단계 추상화 계층

강력하면서도 데이터베이스에 종속적이지 않은 예외 처리 계층 구조를 가지게 되었다. JDBC 사용을 간편하게하는 추상화 프레임워크를 구현해보자.

JDBC 프레임워크를 2 단계 추상화 계층으로 나눌 수 있다.

낮은 수준의 추상화는 com.interface21.jdbc.core 패키지에 있다. JDBC 워크프롤우와 예외 처리를 담당한다. 콜백 접근 방법을 취하였으며 애플리케이션 코드가 콜백 인터페이스를 구현토록 한다.

높은 수준의 추상화는 com.interface21.jdbc.core.object 패키지에 있다. JDO와 비슷하게 보다 객체 지향적인 방법을 제공한다. RDBMS 작업을 자바 객체로 표현할 수 있다.

JDBC 워크프롤우와 에러 처리를 담당하는 프레임워크

낮은 수준의 추상화는 JDBC 쿼리를 보내고 SQLException을 SQLExceptionTranslater를 사용하여 일반적인 예외 계층 구조로 변환한다.

다시 보는 "Inversion of Control"

일반적인 클래스 라이브러리 있는것처럼 애플리케이션 코드가 인프라 코드를 호출하는 것이 아니라.. 인프라 코드가 애플리케이션 코드를 사용하도록(이 부분이 "IoC"라 불리는 접근방법) 복잡한 예외 처리 코드를 그(인프라 코드) 안으로 넣어서 해결하는 방법을 보았다. 이런 접근 방법을 사용한 패키지를 "프레임워크"라 하고 그렇지 않은 것을 라이브러리라 한다.

com.interface21.jdbc.core 패키지

이 패키지에서 가장 중요한 클래스는 JdbcTemplate이다(오오.. 드디어.. 등장이다.) 핵심 워크 프롤우와 애플리케이션 코드 호출을 담당한다. jdbcTemplate에 있는 코드는 PreparedStatements 생성을 위임하여 쿼리를 실행하고 그 결과를 JDBC ResultSet에서 뽑아내는 콜백을 사용한다. 그 두 인터페이스가 바로 PreparedStatementCreator와 RowCallbackHandler 인터페이스다. 애플리케이션 개발자는 이 두 인터페이스 구현체만 만들면 된다. JDBC statement를 직접 실행하거나 예외를 처리할 필요가 없다.

preparedStatementCreator 인터페이스와 관련 클래스

preparedStatementCreator 인터페이스는 java.sql.PreparedStatement를 만들 애플리케이션 클래스가 반드시 구현해야 한다. 즉 SQL과 매개변수만 바인딩 시키면 jdbcTemplate이 실행해줄 것이다. 이것을 구현할 때 Connection을 가져오는 것이나 SQLException 처리는 신경쓰지 않아도 된다.

public interface PreparedStatementCreator {
PreparedStatement createPreparedStatement(Connection conn)
throws   SQLException; }

PreparedStatementCreatorFactory는 동일한 SQL에 매번 다른 매개변수로 PreparedStatementCreator 객체를 만들 때 도와주는 클래스다. 이 클래스는 높은 수준 추상화 프레임워크에서 빈번하게 사용한다.

RowCallbackHandler 인터페이스와 관련 클래스

RowCallbackHandler는 쿼리가 반환하는 ResultSet의 행에서 컬럼 값을 축출하는 클래스가 구현해야하는 인터페이스다. JdbcTemplate이 모든 ResultSet을 순회할 때 사용한다. 이 인터페이스는 SQLException을 그대로 나뒀다. JdbcTemplate이 처리한다.

public  interface RowCallbackHandler  {
void processRow(ResultSet  rs)   throws  SQLException; }

구현체는 컬럼의 수와 데이터 타입을 알고 있어야 한다.

RowCountCallbackHandler 클래스는 이 인터페이스의 구현체로 컬럼 이름과 타입 그리고 ResultSet의 행 갯수에 대한 정보를 가지고 있다. 비록 구체적인 클래스이지만, 애플리케이션 클래스가 이것을 상속받아서 사용한다.

ResultReader 인터페이스는 RowCallbackHandler를 확장하여 가져온 결과를 java.util.List에 저장하는 인터페이스다.

그밖의 클래스

JdbcTemplate 클래스는 SQLExceptionTranslator 객체 하나를 사용하여 SQLException을 일반화된 예외 계층구조로 변환한다. 중요한 건 JdbcTemplate의 동작을 매개변수화 했다는 것이다.

DataSourceUtils 클래는 javax.sql.DataSrouce 에서 Connection을 가져오는 static 메서드, SQLException을 일반화된 계층 구조로 변환하는 메서드, Connection을 닫는 메서드, JNDI에서 DataSource를 가져오는 메서드를 담고 있다.

JdbcTemplate은 DataSourceUtils 클래스를 사용한다.

JdbcTemplate 클래스의 핵심 워크 플로우

이 API가 전반적으로 java.sql.Connection 객체가 아니라 DataSource를 사용하는 이유는 다음과 같다.
- 그렇게 하지 않으면 connection을 어디에선가 얻어와야 하는데 그럼 애플리케이션 코드가 복잡해지고 DatsSrource.getConnection() 메서드를 사용한다면, 애플리케이션 코드에서 SQLException을 처리해야 할 것이다.

- JdbcTemplate이 사용한 connection을 닫는 것이 중요한데 connection을 닫을 때 예외가 발생할 수 있기 때문에 모든 JDBC 예외를 처리를 우리 프레임워크에 맡기고 싶다. 그러나 connection을 사요하면 connection을 외부에서 가져오고 그것을 JdbcTemplate에서 닫는 건 이상하고 이미 닫혀버린 connectino을 사용할 수 있는 여지를 만들게 된다.

JdbcTemplate 클래스 사용하기

조회하기

*JdbcTemplate 사용하여 조회(query)하는 예제 코드*

익명 내부 클래스르 사용하여 RowCallbackHandler와 PreparedStatementCreator 인터페이스를 구현했다.

가장 중요한 것은 JdbcTemplate을 사용함으로써 주요 에러 발생을 제거했다는 것이다. Connection이 닫히지 않을 위험이 없어졌다.

갱신하기

*JdbcTemplate 사용하여 갱신(update)하는 예제 코드*

PreparedStatementCreator 구현체를 만들고 그 객체를 jdbcTemplate.update()에 넘겨주면 끝. 단 한줄이다.


top

Write a comment.


[Expert One-on-One J2EE Design and Development] 실용적인 데이터 접근 1

Spring/J2EE D&D : 2009. 9. 15. 20:28


참고: Expert One-on-One J2EE Design and Development 9장

데이터 접근 기술 선택

J2EE 애플리케이션에서 사용할 수 있는 데이터 접근 기술 들을 두 개의 카테고리로 분류할 수 있다. SQL 기반과 O/R 맵핑 기반이다.

SQL 기반 기술

JDBC

JDBC는 SQL을 기반으로 한다. 저장 프로시저, 커스텀 쿼리, RDBMS에 특화된 기능들을 사용할 때 적절하다.

중 요한 것은 우리가 JDBC를 어떻게 사용하느냐이다. 나이브한(안일한) 접근 방법은 애플리케이션 코드에서 JDBC 코드와 SQL문을 사용하는 것인데 이것은 큰 재앙을 가져올 것이다. 전체 애플리케이션을 특정 영속화 전략에 묶어버려서, 데이터 스키마가 바뀔 때 문제가 생길 것이다. 하지만 다음의 가이드라인만 지킨다면 애플리케이션 코드에서 JDBC를 효율적으로 사용할 수 있다.

- JDBC 접근 코드를 비즈니스 로직에서 최대한 분리하라. JDBC 코드는 오직 DAO에만 있어야 한다.
- JDBC API를 직접 사용하는 저수준(쌩짜) JDBC 코드를 기피하라. JDBC 에러 처리는 생산성을 심각하게 저하할 정도로 난잡하다. 에러 처리같은 저수준의 구체적인 내용들은 도우미 클래스로 빼버리고 고수준 API를 사용하라. SQL 제어권에 지장없이 그렇게 하는 것이 가능하다.

JDBC를 쓰는 것에 대해서는 아무 문제가 없다 다면, 세션 EJB같은 비즈니스 객체나 DAO에서 조차 JDBC를 직접 사용하지는 말자. 비즈니스 컴포넌트를 저수준 JDBC에서 분리할 수 있는 추상화 계층을 사용하라.

SQLJ

생략

O/R 맵핑 기술

O/R 맵핑 기술은 JDBC나 SQLJ 같은 API와는 전혀 다른 프로그래밍 모델이다. 이것을 사용해서도 J2EE 애플리케이션에서 DAO를 구현할 수 있다.

기업 수준에서 사용할만한 O/R 맵핑 솔루션을 제공하는 오픈 소스 제품이 없다.(로드 존슨이 이 책을 쓸 당시 하이버네이트가 없었거나.. 그리 알려지지 않았었나 봅니다.), 

상용 제품

생략

TopLink

생략

CoCoBase

생략

JDO

JDO는 J2EE에 중요한 기술이지만, 미션-크리티컬한 엔터프라이즈 애플리케이션에서 사용하기에는 아직 성숙도가 증명되지 않았다.(역시 책이 쓰여진 시점을 신경쓰며 읽으셔야겠죠)

샘플 애플리케이션에서 사용할 데이터 접근 기술 선택하기

(어찌저찌해서 JDBC 선택! 캐싱할 껀덕지도 별로 없고 저장 프로시저도 효율적으로 사용해야 하기 때문이라고 하는군요.)

JDBC 자세히 보기

그간의 경험을 통해 심각한 문제를 야기할 수 있는 J2EE 애플리케이션에서 sloppy(지져분한, 더러운, 진흙물이 튄것 같은) JDBC 코드를 보았다.

*에러 처리를 제대로 못한 예제 코드*
(대부분의 JDBC 코드와 con.close(); 까지 하나의 try-catch 문으로 묶여있습니다.)

이렇게 코딩을 하면 전체 애플리케이션이 깨지거나 데이터베이스가 뻗을 수 있다. con.close()까지 가기 전에 SQLException이 발생하면, 커넥션을 반환하지 못할 것이기 때문이다.

*에러 처리를 제대로 한 예제 코드*
(con.close();를 finally 블럭에서 null 체크를 한 다음에 수행하면서 try-catch로 묶어줬습니다.)

이렇게 하는것이 좀 더 견고하지만 너무 장황하다. 가장 간단한 JDBC 기능을 하나 수행하는데 39줄의 코드가 필요하다. 자.. 이제 JDBC API를 직접 쓰는것 말고 더 좋은 어떤 방법이 필요하다는 것을 분명히 알 수 있다.

SQLException에서 정보 축출하기

JDBC 예외 처리에서 또 다른 중요한 것은 SQLExcpetion에서 최대한 정보를 뽑아내는 것이다. 불행히도 JDBC는 이 걸 매우 복잡하게 만든다.

java.sql.SQLException은 getNextException() 메서드로 다음 SQLException을 받아올 수 있다. JDBC는 모든 예외 상황에 대해 오직 한 개의 예외 클래스만 사용하고 있다. 또한 벤더 코드와 SQLState 코드를 포함하고 있다.

벤더코드는 getErrorCode() 메서드가 반환하는 int 값이다. 그 이름이 암시하듯이 벤더 코드는 벤더마다 다를 수 있다. 따라서 이 코드에 의존하는 것은 이식성을 저해한다.

getSQLState() 메서드는 5자리 문자열을 반환한다. 이론적으로는 이식이 가능한 에러 코드다. 처음 두 자리는 고수준의 정보를 담고 있고 다음 세자리는 보다 상세한 정보를 담고 있다.

불행히도 SQLState 코드는 모든 데이터베이스에서 지원하지 않으며 문제에 대해 충분한 정보를 제공해주지도 못한다. 때에따라 벤더 코드가 구체적인 정보를 얻을 수 있는 유일한 방법이 된다. 대부분의 데이터베이스는 SQLState 코드보다 훨씬 많은 벤더 코드를 제공하며 더 잘 정리된 문서를 제공하고 있다.

java.sql.SQLWarning 예외도 SQLException 만큼이나 잘 이해할 필요가 있다. SQLException처럼 검증형 예외(checked exception)지만, JDBC API가 실제로 던지지는 않는다. 치명적이지 않은 SQL 에러로 여기고 그 내용을 ResultSet, Statement, Connection에 덭 붙여준다. 이런 JDBC API에 getWarnings() 메서드를 호출해서 가져올 수 있다.

이런 Warning이 JDBC를 직접사용하면 좋치않은 이유 중 하나다. JDBC를 직접사용하는 코드에서 Warging을 확인하는 과정을 추가하면 111줄의 코드가 더 추가된다. 실제로 하기엔 너무 많다.

PreparedStatement 질문

java.sql.PreparedStatement 인터페이스와 java.sql.Statement 인터페이스의 차이를 이해하는 것이 중요하다. prepared statent는 변수들을 바인딩할 위치와 각각의 위치에 매개변수를 설정할 수 있는 기능을 제공한다.

SQL에 적합한 문자 형태로 바꿔주는 역할을 해준다.

문자열 보다 더 효율적이다. 처음 prepared statement를 실행하면 파싱되고 데이터베이스에 의해 컴파일 되며 statement 캐시에 저장될 수 있다. 반면, 일반적인 SQL 문자열은 매번 변수 값이 달라질 경우 이렇게 캐시를 할 수가 없다.

JDBC 2.0은 prepared statement 캐싱을 필수로 하지 않았지만, 3.0에서는 표준으로 정했다.
top

  1. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.09.15 23:23 PERM. MOD/DEL REPLY

    Statement와 PreparedStatement 의 중요한 차이점을
    한가지 더 생각해 보면,
    Statement는 별도로 체크하고
    escaping을 하지 않으면, SQL Injection 을 당할수가 있고,
    PreparedStatement 는 set 메소드 사용해서
    입력값을 삽입할때 알아서 escaping되서
    그런 위험이 없다는 것이겠죠. :)
    물론 컴파일후 삽입 형태가 아닌
    query에 입력값까지 포함시켜버리는 실수를 하면 안 되겠죠...ㅡ_ㅡ;;;

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.15 23:28 신고 PERM MOD/DEL

    오호.. 그런 차이가 있군요.
    하이버네이트한테 기대서 살았더니 JDBC에 대해 모르는게 많아요. 흐흐;;

  2. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.09.23 19:41 PERM. MOD/DEL REPLY

    저는 ORM 보다 JDBC를 더 많이 사용했거든요...ㅡ_ㅡ;;;
    근데 블로그 돌아다니다 보면, 저거 모르는분들이
    의외로 많더군요. 요즘 가르치는 학생들한테도
    알려줬는데, 이것들이 귀찮은건지 전부 Statement 만 사용하고...:(
    과제 채점할때 전부 감점이죠... :)

    그러고 보면 ORM은 여러모로 편하죠. 프로그래머가 DB보다는
    개발하는 어플에 더 집중하게 해줄수 있는것 외에도,
    SQL Injection 걱정도 덜어주고, boilerplate 코드도 줄어들게 해주고...

    그나저나,
    JEE Server 에 Hibernate + JPA 사용해보니
    Tomcat에서 Spring + Hibernate + JPA 사용하는거보다
    설정이 더 짜증나는군요...ㅡ_ㅡ;
    물론 예전에 EJB2 쓸때보다 훨씬 간편해 지긴 했지만요.
    예전에 WebLogic Server에 EJB2 쓸때
    그 XML들 하며... EJB는 별도의 컴파일 과정을 거쳐야 하고...

    최근의 JEE Server에 EJB3는 진짜 많이 간편해 졌는데,
    WebLogic, JBoss, Geronimo, GlassFish 정도
    사용해보고 느낀게...
    여전히 Tomcat + Spring 이 훨씬 간편하다는겁니다.
    SpringSource에서 주장하는
    -J2EE should be easier to use
    를 실감할수 있었습니다.
    (그래도 Spring은 여전히 XML 사용을 좀 줄여야 할꺼 같네요.
    요즘 annotation으로 대체해 나가는거 같아서 다행입니다).

    암튼, 요즘 JEE 관련 과목을 가르치고 있는데,
    학생들이 대부분의 시간을 어플 만드는거보다는
    설정에 문제가 있어서 그거 해결하는데 소비를 하더라구요.
    얼마나 안타깝던지...
    물론 instruction을 제대로 안 따라한 경우도 있고,
    혹은 lab 컴에 문제가 있는경우나 네트워크 문제도
    있긴 합니다만...

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.23 20:14 신고 PERM MOD/DEL

    저도 어서 호주가서 케빈님 강의 듣고 싶어요.
    3년만 기다리세요.ㅋㅋ

    저는 역시;;; tomcat+spring 구조에만 기대 살고 있답니다. 흔히들 말하는 was 서버와 관련된 이슈는 그래서 하나도 모른답니다. 흑흑.. :'(

Write a comment.


[Expert One-on-One J2EE Design and Development] J2EE 아키텍처 3

Spring/J2EE D&D : 2009. 9. 3. 14:00


Web Ties Design

이전에 보았던 각기 다른 네 가지 아키텍처에 모두 적용가능하다.

웹 단을 미들 단의 비즈니스 인터페이스에 의존하는 별도의 계층으로 구분하는 것이 중요하다. 그렇게 해야 비즈니스 객체를 바꾸지 않고도 웹 단을 수정할 수 있으며 웹 단을 참조하지 않고도 비즈니스 객체를 테스트할 수 있다.

MVC 아키텍처 패턴

이 패턴은 스몰토크 유저 인터페이스를 위해 처음으로 문서화 되었으며 가장 성공적인 OO 아키텍처 패턴중 하나이다.

중략~

웹 단에서 MVC 아키텍처 패턴을 사용하라. 스트럿츠같이 작성해야 할 애플리케이션 코드의 양을 줄여주며, 기본적인 MVC 패턴 구현체를 사용하라.

Designing Applications for Portability

특정 플랫폼에 종속적인 것은 추상화 계층을 사용하여 구현해야 한다. 인터페이스 자체는 플랫폼에 독립적이기 때문이다.

구현 이식성과 디자인 이식성의 차이를 알아야 한다. 구현 이식성이랑 어떤 서버에 배포하든 코드를 고칠 필요가 없는 것이고, 디자인 이식성은 분명한 인터페이스 약간을 다시 구현하기만 하면 어떤 서버에든 배포할 수 있는 것이다. 완전한 구현 이식성을 달성하기는 매우 많은 노력이 필요할 수 있지만, 디자인 이식성은 달성할만하며 충분한 비즈니스 가치를 가져다 준다. 이식성이 비즈니스 요구사항이 아니더라도, 디자인 이식성은 좋은 OO 디자인 실천으로 자연스래 달성할 수 있다.

Summary

- 분산 아키텍처의 단점: 보다 복잡하고, 구현, 테스트, 유지보수 하기 힘들다. 주의깊게 설계하지 않으면 성능 문제가 발생한다.
- 분산 아키텍처의 장점" 특정 경우에 따라, 보다 견고하고 확장성이 좋을 수 있다. 특정 비즈니스 요구사항에 따라 분산 아키텍처가 필요할 수도 있다.
=> 진짜 장점을 주지 못한다면 분산 아키텍처를 피하는 것이 최선이다.

- EJB 2.0에 웹 서비스가 포함되었다. 따라서 RMI에 종속적이지 않게 되었다. 로컬 인터페이스를 통해 EJB가 실행되고 있는 동일한 JVM에 접근할 수 있다. 따라서 분산 아키텍처에 종속적이지 않게 되었다.

- 언제 EJB를 사용할 것인가. EJB는 특정 문제를 매우 잘 해결할 수 있는 복잡하고, 강력한 기술이다. 하지만 대부분의 애플리케이션에 적절하지 않다.

- 나머지 dao, tiered architecture, four J2EE architecture, web-tire design issue 생략~
top

Write a comment.


[Expert One-on-One J2EE Design and Development] J2EE 아키텍처 2

Spring/J2EE D&D : 2009. 9. 2. 18:19


Accessing Data

(예전) EJB를 사용하면 엔티티 빈이라는 하나의 선택지 밖에 없다. (EJB 3.0부터는 JPA가 있지요.)

J2EE Data Access Shibboleths

- 데이터베이스 간의 이식성은 항상 중요하다.
- O/R mapping은 관계형 DB를 사용할 때 항상 최선의 솔루션이다.

데이터 접근 전략을 사용할 때, 비즈니스 로직과 데이터 접근 로직을 추상화 계층으로 분리하는 것이 좋다.

Entity Beans

특정 DB에 종속되지는 않지만, EJB 컨테이너와 특정 O/R 맵핑 기술에 묶이게 된다. 성능이 안 좋다. 아키텍처적인 유연성이 떨어지고 테스트하기 어렵다.

EJB 2.0이 되고나서도, 너무 기초적인 O/R 맵핑인데다, 비효율적으로 관계형 DB를 사용하기 때문에 성능이 좋치 않다.

JDO

JDO는 엔티티 빈에 비해 성능이 좋고, 특정 RDBMS에 종속적이지도 않다. EJB에도 종속적이지 않다. 단점은  JDO 구현체가 아직 비교적 성숙하지 못하다는 것이다.

다른 O/R 맵핑 솔루션

탑링크와 코코베이스는 JDO 보다 성숙한 O/R 맵핑 솔루션으로 대부분의 J2EE 애플리케이션에서 사용할 수 있다. 다양한 기능과, 고성능의 O/R 맵핑을 제공한다. (하이버네이트 얘기는 하나도 없지 왜..)

JDBC

암묵적인 J2EE에서 JDBC와 SQL은 악마라는 소문이있다. 하지만 이 책에서 제공하는 고 수준의 라이브러리를 사용하면 (이때부터 JdbcTemplate이 나오나 봅니다. 캬..) O/R 맵핑이 없는 상황에서 최선책이 될 수 있다. 제대로 사용하면 JDBC는 좋은 성능을 발휘할 것이다. 데이터를 자연스럽게 캐시할 수 있는 O/R 맵핑 계층이 있다면 JDBC는 적절하지 않다.

상태 관리

J2EE 아키텍처에서 또 다른 중요한 의사결정은 서버-측 상태를 어떻게 관리할 것이냐이다. 이것으로 인해 서버 클러스터 환경에서 애플리케이션이 어떻게 동작하는지 그리고 어떤 J2EE 컴포넌트를 사용해야 하는지 결정된다.

서버-측 상태가 필요한지 결정하는이 중요하다. 애플리케이션을 단일 서버에서 운영할 떄는 서버-측 상태를 유지하는 것이 별 문제는 아니다. 여러 서버를 클러스터 환경에서 운영한다면 페일오버(failover)나 server affinity 문제 등을 피하기 위해 서버-측 상태를 복사해야 한다.

서버-측 상태가 필요하다면 유지해야 할 양을 최소화 하는 것이 좋다.

서버-측 상태를 유지하지 않는 애플리케이션이 그러는 애플리케이션보다 확장성이 좋고, 간결하며 클러스터 환경에 배포하기 좋다.

서버-측 상태를 어디에 저정해야 할지 결정해야 한다. 저장할 정보의 종류에 따라 달라진다. 사용자 세션 정보냐, 비즈니스 객체 상태냐. 둘 다냐. 분산 EJB는 웹 단의 상태와 상관없이 stateless session bean으로 확장성을 최대화 한다.

J2EE는 웹 애플리케이션에서 상태 관리에 사용할 두 가지 옵션을 제공한다. HTTP session 객체와 stateful session EJB다.  상태 관리가 필요하다고 해서 EJB가 필요한건 아니다.

J2EE 아키텍처

생략~


top

  1. 우가가 2009.10.19 16:48 PERM. MOD/DEL REPLY

    좋은 글 읽고 갑니다.
    직접 번역하신 건가요? ^^

    그리고 하이버네이트 1.0이 릴리즈 되었을 때가 2002년 7월이고 로드 존슨이 저 책을 2002년 10월에 탈고했으니까 아마 당시 듣보버전이었던 녀석을 책에 언급했을 것 같지는 않네요. 판본이 바뀌면서 수정하지 않았다면요.

    Favicon of http://whiteship.me BlogIcon 기선 2009.10.19 16:57 PERM MOD/DEL

    넹. 제가 번역/요약한 글입니다.
    시간까진 안 따져봤는데, 시기를 보니 그럴만도 하군요. :)

Write a comment.


[Expert One-on-One J2EE Design and Development] J2EE 아키텍처 1

Spring/J2EE D&D : 2009. 9. 1. 08:47


엔터프라이즈 아키텍처의 목표
- 견고함(be robust): 사용자가 신뢰할 수 있고 버그가 없어야 한다.
- 성능과 확장성이 좋아야 함: 확장을 고려하여 보통 여러 개의 서버 인스턴스를 하나의 클러스터에 배포한다. 클러스터링은 복잡한 애플리케이션 서버 기능을 필요로 한다. 애플리케이션이 클러스터 환경에서 효율적으로 동작하도록 설계되어 있는지 확인해야 한다.
- OO 설계 원리 장점 취하기: we should apply J2EE to realize OO design, not let J2EE technologies dictate object design
- 불필요한 복잡성 기피하기: XP에서는 "동작하게 만드는 가장 간단한 것"을 하도록 권장한다.
- 유지보수와 확장성: 각각의 컴포넌트가 분명한 책임을 가지고 있는지, 컴포넌트 끼리 강하게 결합되어 유지보수를 방해하진 않는지 확인하라.
- 제 때 배포하기
- 쉽게 테스트하기
- 재사용 권장하기

다음은 비즈니스 요구사항에 따른 부가적인 목표
- 다양한 클라이언트 타입 지원하기: 웹 애플리케이션, Swing 애플리케이션, 자바 애플릿 등. 보통은 "얇은" 웹 인터페이스만 널리 사용하고 있다.
- 이식성: 비즈니스 요구사항에 따라 데이터베이스 같은 자원의 이식성이 얼마나 용이한지 고려해야 할 수도 있다.

분산 아키텍처를 사용할 것인지 결정하기
- 분산 애프리케이션은 복잡하고, 런타임 오버헤드를 증가시키며, 만족할만한 성능을 내기 위해 충분한 설계를 필요로하기 때문에 중요한 의사결정이다.

분산 아키텍처가 제공하는 장점
- 다양한 클라이언트를 지원할 수 있는 능력
- 애플리케이션 컴포넌트를 각기 다른 물리적 서버에 배포할 수 있는 능력.

분산 아키텍처의 문제
- 성능 문제: 원격 호출은 로컬 호출보다 느리다.
- 복잡도: 개발, 디버그, 배포, 유지보수가 힘들다.
- OO 설계 적용에 제약이 생긴다

J2EE 설계에서 새로 고려할 것
- 생략

EJB 사용 시점
- EJB는 J2EE가 제공하는 하나의 선택일 뿐이다.
- 요구사항이 분산 아키텍처를 필요로 하고 RMI/IIOP가 원격 프로토콜로 적당할 경우 EJB는 표준 구현체를 제공해줄 수 있다.

EJB를 사용한다는 것의 의미
- 애플리케이션을 테스트하기 힘들다.
- 애플리케이션을 배포하기 힘들다.
- 원격 인터페이스는 OO 디자인 실천을 방행한다.
- 간단한 것도 어렵게 만든다.
- 애플리케이션 서버 선택 범위가 좁아진다.

EJB 사용에 대한 의문
- 생략

EJB 사용을 강하게 주장하는 경우
- 생략

경우에 따라 EJB 사용을 고려해볼 만한 경우
-  개발자가 멀티-쓰레드 코드를 작성하지 않아도 된다.
- CMT(컨테이너가 관리하느 트랜잭션)를 통해 Transparent 트랜잭션 관리를 제공한다.
- 선언적인/프로그래밍적인 롤-기반 시큐리티를 제공한다.
top

  1. 조대협 2009.09.01 15:53 PERM. MOD/DEL REPLY

    EJB는 Transaction 관리, 특히 분산 트렌젝션 관리에 유용하져. 여러개의 컴포넌트들을 통해서 트렌젝션을 전파하거나 여러개의 트렌젝션을 동시 사용하거나.
    그리고 JMS와 함께 쓰는 Message Driven Bean의 장점도 무시할 수 는 없져. ;)
    2.1 스펙부터는 Annotation이 나와서 개발하기도 쉬워졌어요. ;)

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.01 16:45 PERM MOD/DEL

    맞습니다. MDB에 대한 내용도 있었는데 생략한 부분에 포함되어 있었나 봅니다.

Write a comment.


[스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 4

Spring/3.0 : 2009. 8. 20. 00:00


참고: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ch14s04.html

oxm 네임스페이스를 스프링 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"
    xmlns:oxm="http://www.springframework.org/schema/oxm"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/oxm
    http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">

현재 지원하는 태그는 다음과 같다.
    •    jaxb2-marshaller
    •    xmlbeans-marshaller
    •    jibx-marshaller

각각의 태그는 해당 섹션에서 자세히 설명하겠다. 예를 들어, 다음은 JAXB2 마샬러를 설정한 모습니다.

<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>

top

Write a comment.


[스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 3

Spring/3.0 : 2009. 8. 19. 23:52


참조: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ch14s03.html

14.3 Marshaller와 Unmarshaller 사용하기

다음은 마샬링, 언마샬링에서 사용할 JavaBean이다.

public class Settings {
    private boolean fooEnabled;

    public boolean isFooEnabled() {
        return fooEnabled;
    }

    public void setFooEnabled(boolean fooEnabled) {
        this.fooEnabled = fooEnabled;
    }
}

다음 Application에서는 위의 객체를 settings.xml로 저장하고 다시 그것을 읽어들인다.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;

public class Application {
    private static final String FILE_NAME = "settings.xml";
    private Settings settings = new Settings();
    private Marshaller marshaller;
    private Unmarshaller unmarshaller;

    public void setMarshaller(Marshaller marshaller) {
        this.marshaller = marshaller;
    }

    public void setUnmarshaller(Unmarshaller unmarshaller) {
        this.unmarshaller = unmarshaller;
    }

    public void saveSettings() throws IOException {
        FileOutputStream os = null;
        try {
            os = new FileOutputStream(FILE_NAME);
            this.marshaller.marshal(settings, new StreamResult(os));
        } finally {
            if (os != null) {
                os.close();
            }
        }
    }

    public void loadSettings() throws IOException {
        FileInputStream is = null;
        try {
            is = new FileInputStream(FILE_NAME);
            this.settings = (Settings) this.unmarshaller.unmarshal(new StreamSource(is));
        } finally {
            if (is != null) {
                is.close();
            }
        }
    }

    public static void main(String[] args) throws IOException {
        ApplicationContext appContext =
            new ClassPathXmlApplicationContext("applicationContext.xml");
        Application application = (Application) appContext.getBean("application");
        application.saveSettings();
        application.loadSettings();
    }
}

위에서 설정할 Marshaller와 Unmarshaller는 다음 스프링 설정 파일에서 설정한다.

<beans>
    <bean id="application" class="Application">
        <property name="marshaller" ref="castorMarshaller" />
        <property name="unmarshaller" ref="castorMarshaller" />
    </bean>
    <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/>
</beans>

위 설정에서 사용한 Marshaller는 Castor 라이브러리인데, 이 것은 부가적인 설정이 필요 없기 때문에 빈 설정이 간단하다. 도한 CastorMarshaller가 스프링의 Mashaller와 Unmashaller를 모두 구현하고 있다. 따라서 이 빈이 Application의 Marshaller와 Unmashaller에 설정된다. 위 애플리케이션은 다음과 같은 XML 파일을 만들어 낸다.

<?xml version="1.0" encoding="UTF-8"?>
<settings foo-enabled="false"/>


top

Write a comment.


[스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 2

Spring/3.0 : 2009. 8. 13. 18:18


요약, 번역, 참조: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ch14s02.html

14.2 Marshaller와 Unmarshaller

14.2.1. Marshaller

스프링은 모든 마셜링 과정을 org.springframework.oxm.Marshaller 인터페이스로 추상화 시켰다. 주요 메서드는 다음과 같다.

public interface Marshaller {

    /**
     * Marshals the object graph with the given root into the provided Result.
     */
    void marshal(Object graph, Result result)
        throws XmlMappingException, IOException;
}

(실제로는 boolean supports(Class<?> clazz)  이것도 있음.)

메서드에 전달받은 Object graph를 javax.xml.transform.Result 객체로 변환해 준다. Result는 태깅 인터페이스로 기본적으로 XML을 추상화한 것이다. 다음과 같은 다양한 구현체들이 있다.

Result implementation    Wraps XML representation
DOMResult    org.w3c.dom.Node
SAXResult    org.xml.sax.ContentHandler
StreamResult    java.io.File, java.io.OutputStream, or java.io.Writer

노트: marshal 메서드가 Object 타입의 객체를 받긴 하지만, 대부분 임의의 객체를 전달하진 않는다. 맵핑 파일에 맵핑한 객체 또는 애노테이션을 표시해둔 객체, 마샬러에 등록한 객체 또는 임의의 상위 클래스를 지닌 객체를 넘긴다. 자세한 내용은 O/X 기술 선택 챕터를 참조하라.

14.2.2. Unmarshaller

Mashaller와 비슷하게 org.springframework.oxm.Unmarshaller 인터페이스도 있다.

public interface Unmarshaller {

    /**
     * Unmarshals the given provided Source into an object graph.
     */
    Object unmarshal(Source source)
        throws XmlMappingException, IOException;
}

(이 녀석도 boolean supports(Class<?> clazz) 이걸 가지고 있음)

javax.xml.transform.Source 타입의 객체를 넘겨주면 Object를 반환해준다. 다음과 같은 Source 구현체들이 있다.
 
Source implementation    Wraps XML representation
DOMSource    org.w3c.dom.Node
SAXSource    org.xml.sax.InputSource, and org.xml.sax.XMLReader
StreamSource    java.io.File, java.io.InputStream, or java.io.Reader

14.2.3. XmlMappingException

스프링은 사용중인 O/X 맵핑 툴의 예외 계층 구조를 XmlMappingExcpetion 계층 구조로 변환해준다. 사용중인 툴이 마샬링과 언마샬링 예외를 구분하고 있지 않더라도,,. 스프링에서 이것을 구분해 준다.


top

Write a comment.


[스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 1

Spring/3.0 : 2009. 8. 13. 18:06


요약, 번역, 참조: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ch14.html

14.1 도입

객체/XML 변환 과정, 즉 XML 마샬링(Marshalling) 또는 XML 직렬화(Serialization)에 대해 다룬다.

marshaller는 객체 그래프를 XML로 변환해주고..
unmarshaller는 반대로 XML을 객체 그래프로 변환해 준다.

스프링 OXM을 사용할 때의 장점
- 간편한 설정: JAXB context나 JiBK bidning factory 없이도 간단하게 설정할 수 있다. XML 설정시 oxm 네임스페이스를 제공해준다.
- 일관된 인터페이스: 스프링이 제공하는 Marshaller와 Unmashaller 인터페이스를 사용하면 된다. 클라이언트 코드 변경 없이 O/X 맵핑 프레임워크를 교체할 수 있다.
- 일관된 예외 구조: 제각각인 예외들을 스프링의 XmlMappingExcption 이하의 계층 구조로 변환해 준다. 런타입 예외로 기존의 예외를 감싸기 때문에 에러 정보를 분실하진 않는다.


top

Write a comment.


스프링의 이메일 기능 지원과 테스트를 살펴보자

Spring/etc : 2009. 7. 27. 12:20


스프링이 지원하는 이메일은 JavaMail과 JAF라는 것이 있습니다. 사용법은 간단하니.. 다음에 심심할 때 살펴보기로 하고, 지금은 사부님이 올리신 글과 관련 된 부분을 찾아보는게 급선무입니다.

스프링 이메일 기능은 context.support 모듈에 들어있습니다. 주요 클래스는 o.s.mail.javamail에 들어있는 JavaMailSender 인터페이스와 그 구현체인 JavaMailSenderImpl 클래스입니다. 인터페이스의 API를 읽어보면 다음과 같은 내용이 있습니다.

...

Clients should talk to the mail sender through this interface if they need mail functionality beyond SimpleMailMessage. The production implementation is JavaMailSenderImpl; for testing, mocks can be created based on this interface. Clients will typically receive the JavaMailSender reference through dependency injection.

...

The entire JavaMail Session management is abstracted by the JavaMailSender. Client code should not deal with a Session in any way, rather leave the entire JavaMail configuration and resource handling to the JavaMailSender implementation. This also increases testability.

A JavaMailSender client is not as easy to test as a plain MailSender client, but still straightforward compared to traditional JavaMail code: Just let createMimeMessage() return a plain MimeMessage created with a Session.getInstance(new Properties()) call, and check the passed-in messages in your mock implementations of the various send methods.

즉, 이 API를 만든 의도에 사용성 편의 뿐만 아니라, 테스트 편의성도 포함되어 있다는 암시를 읽어낼 수 있습니다. JavaMail의 Session API를 사용하지 않고 스프링의 JavaMailSender를 목킹해서 테스트 하라는 것인데, 왜 그렇게 했는지는 맨 마지막 부분의 JavaMail의 Session API 사용법(Session.getInstance(new Properties())에서 볼 수 있습니다. 바로 static 메서드입니다.

JavaMail 레퍼런스에서 그 사용법을 보면, 다음과 같은 코드로 JavaMail을 이용하는 모습을 볼 수 있습니다.

//메시지를 만들고,,
     Properties props = new Properties();
     props.load(new FileInputStream(propfile));

     Session session = Session.getInstance(props, null);
     MimeMessage msg = new MimeMessage(session);

...

//전송합니다.
    // Set the content for the message and transmit
    msg.setContent(mp);
    Transport.send(msg);

코드 대부분을 생략했습니다. 중요한 부분은 위에 다 나와있습니다. 바로 static 메서드를 사용한다는 것이 중요한 부분입니다.

이런 API 사용을 클래스를 단위 테스트 하려면 막막합니다. 도무지 static 메서드를 호출하는 부분을 mock으로 바꿀 수가 없습니다. 그렇다고 테스트를 하는데 실제로 메일을 매번 보내기도 뭐하고 말이죠. 그래서 테스트 하려면 static 메서드 호출을 사용한 클래스를 거의 다시 만들다시피 구현한 stub을 만들어서 테스트 해야 하는데 이건 엄청난 수고가 필요합니다. JavaMail 예를 들면 거의 Transport를 테스트용으로 다시 구현해서.. sendMessage에서 실제로 메일을 보내지 않고 그냥 보내는 메시지 목록에 메시지만 모아두는 식의 작업이 필요해집니다. 그리고 테스트 할 떄는 그런 스텁 Transport를 사용하는 또 다른 스텁 MailSender가 필요해지겠죠.(실제로 이 작업들은 스프링의 JavaMailSenderTests에서 수행하고 있습니다.)

하지만, 테스트를 편하게 하는 방법이 아주 없는 건 아니었습니다. 오늘 톱님께서 올리신 글을 보면 static 메서드를 호출하는 코드를 비교적 편하게 테스트하는 방법 세 가지를 알 수 있습니다.

하나는 JavaMailSender처럼 static 메서드 호출 부분을 랩핑한 클래스를 만들고, 그 클래스를 목킹한 다음 해당 메서드가 호출되는지 테스트하는 것입니다. 그렇게 만들어 두면, 테스트 하려는 대상이 JavaMail의 Transport.send 같은 static 메서드를 호출하지 않고, 그것을 사용한 JavaMailSender를 사용하기 때문에 JavaMailSender의 mock을 만들고 그 객체의 send가 호출될 때 어떤걸 하라고 mocking 한다던지 해서 호출이 제대로 됐는지, 어떤 메시지가 넘어갔는지 등을 확인할 수 있겠습니다.

두 번째 방법은 로드존슨이 만들었다는 AspectJ를 이용하는 방법이고, 세 번째 방법은 PowerMock을 이용하는 방법인데, 둘 다 결국 바이트코드를 조작해서 static 호출 부분을 mock으로 호출로 교체하는 기술 인듯합니다. 이 두 가지는 일단 논외로 치

결론은.. 스프링의 JavaMailSender를 사용하면 JavaMail의 static 메서드 호출과 관련하여 테스트를 어떻게 작성할까 고민할 필요없이, JavaMailSender를 목킹해서 테스트를 만들면 된다는 것입니다.

덤으로 JavaMail의 static 메서드 호출을 사용한 JavaMailSender의 테스트 클래스를 보면, static 메서드 호출을 하는 클래스에 대한 테스트 실마리를 얻을 수 있습니다. static 메서드를 호출해서 가져오는 객체를 가져오는 부분을 별도의 메서드로 분리하고 그 부분을 테스트 용으로 재구현하고 그것을 테스트에서 사용하는 방법인데.. 이거 이거.. 귀찮아서 원... @_@..  그래서 static은 테스트의 적인가 봅니다. 그래도 이길 수 있는 적이라는거..
top

  1. openmaya 2010.01.18 12:08 PERM. MOD/DEL REPLY

    굉장히 예전에 쓰신글을 이제야 봅니다 ㅋstatic 메서드와 호출관련해서 비슷한 경험을 한적이 있는데요. 다름이 아니라 HTTP호출을 하는 클래스를 static으로 선언한 경우 입니다. 데이터 자체는 openapi를 이용해 가져오고 HTTP 호출을 하기위해서는 인증을 위해 헤더값 추가까지 하는 경우에 하려는 것에 비해 Method클래스 등등 많은 작업이 필요하게 되는데요. 이 부분이 다른 분이 작성한 부분이라서 결국엔 랩핑클래스를 만들고 그 클래스를 테스트 해야 했지요. 이런경우에 단점이 기존의 다른 분이 만드신 코드들은 래핑클래스를 사용하지 않는 상황이라서 코드가 이원화 되어버린 상황이랄까요.

    Favicon of http://whiteship.me BlogIcon 기선 2010.01.19 10:52 PERM MOD/DEL

    "HTTP호출을 하는 클래스를 static으로 선언한 경우"

    어이쿠.. 그렇군요. 스프링 3.0에 추가된 RestTemplate인가하는 클래스랑은 대조적이네요.

Write a comment.


[Spring 3.0] HiddenHttpMethodFilter

Spring/3.0 : 2009. 6. 10. 10:47


어제 밤에 스프링 ROO가 제공하는 REST 코드를 보다가 잠들었는데, 아침에 사부님 댓글을 보니, DELETE와 PUT method를 현재 브라우저와 HTML에서는 완전히 지원하지를 않더군요. 그래서 스프링 레퍼런스를 봤더니 역시나..

org.springframework.web.filter.HiddenHttpMethodFilter

이 녀석을 제공해주고 있었습니다. 사용하는 방법은 간단합니다.

    <filter>
        <filter-name>UrlRewriteFilter</filter-name>
        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>UrlRewriteFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

이렇게 web.xml에 추가해주면 되죠. 어젯밤엔 졸려서 이부분을 그냥 지나간것 같습니다.

해주는 일은 post method로 넘겨온 파라메터 중에 _method가 가지고 온 값으로 HTTP method를 실제 원하는 method로 바꿔주는 겁니다.

<form:form method="delete">
    <p class="submit"><input type="submit" value="Delete Pet"/></p>
</form:form>

스프링 폼 태그를 이용해서 저렇게 method를 명시해주면 히든 필드 _method에 delete라는 값을 요청에 같이 포함해서 보내주며 실제 보내는 요청은 post가 됩니다. 하지만 이 필터가 _method의 값인 delete를 읽고서 HTTP method를 DELETE로 변경해주고, 그 결과 아래에 있는 핸들러가 이 요청을 처리하게 됩니다.

@RequestMapping(method = RequestMethod.DELETE)
public String deletePet(@PathVariable int ownerId, @PathVariable int petId) {
    this.clinic.deletePet(petId);
    return "redirect:/owners/" + ownerId;
}

REST 스타일을 적용할 때 꼭 필요한 라이브러리 인 듯 합니다.
top

  1. Favicon of http://jjaeko.tistory.com BlogIcon 째코 2009.06.10 13:19 PERM. MOD/DEL REPLY

    ssimini에서도 restful을 지원할때 별도의 파라미터(_http__method)를 이용 하빈다...
    restful 정말 매력적인듯 하네요.

    Favicon of http://whiteship.me BlogIcon 기선 2009.06.10 17:44 PERM MOD/DEL

    오호 ssimini도 REST를 지원하는군요~

  2. Favicon of http://kwon37xi.egloos.com BlogIcon 권남 2009.07.06 15:35 PERM. MOD/DEL REPLY

    저기 HiddenHttpMethodFilter 랑 org.tuckey.web.filters.urlrewrite.UrlRewriteFilter 가 무슨상관인지 잘 모르겠어요... org.tuckey.web.filters.urlrewrite.UrlRewriteFilter 를 설정하면 자동으로 HiddenHttpMethodFilter가 적용되는건가요??

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.07.06 15:39 신고 PERM MOD/DEL

    UrlRewriteFilter랑은 아무 관계가 없는 것 같습니다. 다만 이 글을 올릴 때 제가 전에 못 봤었던 부분을 같이 긁어다 붙인것 같네요.

Write a comment.


Spring Expression Language(SpEL)

Spring/3.0 : 2009. 4. 21. 17:12


참조: 7. Spring Expression Language (SpEL)

번역, 요약 및 편역 합니다.

7.1 도입

스프링 EL(SpEL)은 실행시(runtime)에 객체 그래프 질의와 조작을 지원하는 강력한 EL(Expression Language)이다. 통합 EL(Unified EL)과 언어 문법이 비슷하지만, 메서드 호출과 기본 문자열 템플릿 같은 추가 기능을 제공한다.

OGNL, MAVEL, JBoss EL 같은 다른 자바 EL도 있지만, 스프링 EL은 스프링 커뮤니티에 모든 스프링 포트폴리오 제품에서 사용할 수 있는 단일 EL을 제공하기 위해 만들었다. 이 언어의 기능은 스프링 포트폴리오의 요구사항을 기반으로 도출했다. 그 중에는 이클립스 기반의 스프링소스 툴 스위트(STS)에서 코드 완성에 필요한 도구도 포함되어 있다.

SpEL이 스프링 포트폴리오에 표현 평가(evaluation) 기반을 제공하기는 하지만, 그렇다고 해서 스프링에 강력하게 묶여있지는 않다. 독립적으로 사용할 수 있다. 독립적으로 사용하는 예제가 이 번 장에 많이 나와있다. 그러려면 약간의 부트스트랩 역할을 하는 (파서 같은)기반 클래스들을 만들어야 한다. 스프링 사용자들은 그런 기반 시설을 사용할 필요가 없고 그저 표현식을 사용하면 된다. 일반적인 SpEL 사용법은 XML 또는 애노테이션 기반 빈 설정에 사용하는 것인데 빈 정의할 때 EL 사용하기 절에서 살펴볼 수 있다.

이번 장은 EL 기능과 API와 그리고 문법을 살펴본다. 

7.2. 기능 개요

EL은 다음의 기능을 제공한다.

      Literal expressions: 상수 표현
      Boolean and relational operators: 불린과 관계형 연산자
      Regular expressions: 정규 표현식
      Class expressions: 클래스 표현식
      Accessing properties, arrays, lists, maps: 속성, 배열, 리스트, 맵에 접근하기
      Method invocation: 메서드 호출
      Relational operators: 관계형 연산자
      Assignment: 대입
      Calling constructors: 생성자 호출
      Ternary operator: 3항 연산자
      Variables: 변수
      User defined functions: 사용자 정의 함수
      Collection projection: 콜렉션 보기
      Collection selection: 콜렉션 선택
      Templated expressions: 템플릿 표현식

7.3. 스프링의 Expression 인터페이스를 사용한 표현식 평가

이번 절에서는 간단한 SpEL 인터페이스와 그 EL 사용법을 살펴보겠다. EL 레퍼런스에서 자세한 내용을 참조하라.

다음 코드는 SpEL API를 사용하여 상수 문자열 표현식 'Hello World' 값을 구한다.

ExpressionParser parser = new SpelAntlrExpressionParser();
Expression exp = parser.parseExpression("'Hello World'");
String message = (String) exp.getValue();

message 변수의 값은 'Hello World'다.

여러분이 주로 사용할 SpEL 클래스와 인터페이스는 org.springframework.expression 패키지와 그 하위 패키지 spel.antlr과 spel.support에 있다.

EL은 ANTLR 문법을 사용하며 lexer와 파서(parser)를 구성할 때 사용한다. ExpressionParser 인터페이스는 표현식 파싱을 책임진다. 이 예제에서 표현식은 홑따옴표로 둘러쌓여있는  문자열 상수다. Expression 인터페이스는 앞에서 정의한 표현식 값을 도출하는 책임을 지니고 있다. parser.parseExpression을 호출할 때는 ParseException이 발생할 수 있고 exp.getValue를 호출할 때는 EvaluationException이 발생할 수 있다.

SpEL은 메서드 호출, 속성 접근, 생성자 호출 같은 다양한 기능을 제공한다.

다음 예제는 메서드 호출의 예로, concat 메서드를 호출한다.

ExpressionParser parser = new SpelAntlrExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('!')");
String message = (String) exp.getValue();

SpEL은 . 기호를 사용하여 속성의 속성에도 접근할 수 있다. 예를 들어 prop1.prop2.prop3에 접근할 수 있고 값을 설정할 수 있다.

ExpressionParser parser = new SpelAntlrExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.bytes.length");  // invokes 'getBytes().length'
int length = (Integer) exp.getValue();

문자열의 생성자도 호출할 수 있다.

ExpressionParser parser = new SpelAntlrExpressionParser();
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()");
String message = exp.getValue(String.class);

여기서 public <T> T getValue(Class<T> desiredResultType) 이 메서드를 주목해서 살펴보자. 이 메서드를 사용하면 결과 값을 캐스팅하지 않아도 된다. 값이 T 타입 또는 등록된 타입 컨버터로 캐스팅이 되지 않을 때는
EvaluationException가 발생한다.

좀 도 흔한 SpEL 사용처는 특정 객체 인스턴스에 대한 표현식일 것이다. 다음 예제는 Inventor 클래스의 인스턴스에서 Name 속성을 가져온다.

// Create and set a calendar
GregorianCalendar c = new GregorianCalendar();
c.set(1856, 7, 9);

//  The constructor arguments are name, birthday, and nationaltiy.
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");

ExpressionParser parser = new SpelAntlrExpressionParser();
Expression exp = parser.parseExpression("name");

EvaluationContext context = new StandardEvaluationContext();
context.setRootObject(tesla);

String name = (String) exp.getValue(context);

마지막 줄에서 'name' 변수는 "Nikola Tesla"가 설정된다. StandardEvaluationContext 클래스에 "Name" 속성을 찾아볼 객체를 알려준다. 같은 표현식을 새로운 루트 객체로 설정해가며 여러 번 재사용할 수 있다. Expression은 리플렉션을 사용한다.

노트

SpEL을 독립적으로 사용할 때는 파서와 Evaluation context를 만들어야 한다. 하지만 설정 파일의 일부로 SpEL을 사용할 때는 파서와 Evaluation context, root 객체 등을 암묵적으로 스프링이 설정해 준다.

마지막으로 간략히 살펴볼 예제는 불린 연산자를 사용하는 것이다.

Expression exp = parser.parseExpression("name == 'Nikola Tesla'");
boolean result = exp.getValue(context, Boolean.class);  // evaluates to true

7.3.1 EvaluationContext 인터페이스

EvaluationContext 인터페이스는 사용하여 속성, 메서드, 필드를 찾을 수 있고 타입 변환을 수행하는데 이용할 수 있다. 구현하여 제공하는 클래스로 StandardEvaluationContext가 있는데, 객체를 다룰 때 리플렉션을 사용하고, 최적화를 위해 Method, Field, Constructor 인스턴스를 캐싱한다.

StandardEvaluationContext의 setRootObject 메서드를 사용해서 식을 적용할 루트 객체를 명시한다. 또한 setVariable과 registerFunction을 사용하여 표현식에서 사용할 변수와 함수를 명시할 수 있다. 변수와 함수 사용법은 EL 레퍼런스의 변수와 함수 절을 참조하라. StandardEvaluationContext는 또한 커스텀 ConstructorResolver, MethodResolver, PropertyAccessor등을 등록하여 SpEL이 표현식을 다루는 방법을 확장할 수 있다. 자세한 내용은 이들 클래스의 JavaDoc을 참조하라.

7.3.1.1 타입 변환

SpEL은 기본으로 스프링 코어에서 사용할 수 있는 변환 서비스(org.springframework.core.convert.ConversionService)를 사용한다. 이 변환 서비스는 기본 변환기를 내장하고 있지만 커스텀 변환기를 추가하는 것도 가능하다. 또한 핵심 기능으로 제네릭(Generic)을 인식한다. 즉 표현식에서 제네릭 타입을 사용하면, 스프링은 타입 일관성을 유지하기 위해 해당 타입으로 변환을 시도한다는 것이다.

실제로 어떻게 될까? setValue()를 사용하여 문자열을 Boolean 타입의 리스트에 넣는다. SpEL은 해당 리스트의 요소가 Boolean 타입이어야 한다는 것을 인식하고 적절하게 문자열을 Boolean 타입으로 변환해준다.

class Simple {
    public List<Boolean> booleanList = new ArrayList<Boolean>();
}
       
Simple simple = new Simple();

simple.booleanList.add(true);

StandardEvaluationContext simpleContext = new StandardEvaluationContext(simple);

// false is passed in here as a string.  SpEL and the conversion service will
// correctly recognize that it needs to be a Boolean and convert it
parser.parseExpression("booleanList[0]").setValue(simpleContext, "false");

// b will be false
Boolean b = simple.booleanList.get(0);
       
7.4. 빈 정의할 때 EL 사용하기 절

SpEL 표현식은 XML과 애노테이션 기반 설정에서 BeanDefinition에 대한 메타데이터를 정의할 때 사용할 수 있다. 두 경우 모두 표현식을 정의할 때 #{표현식} 문법을 사용한다.

7.4.1. XML 기반 설정

속성 또는 생성자-인자 값을 아래와 같이 표현식에 설정할 수 있다.

<bean id="numberGuess" class="org.spring.samples.NumberGuess">
    <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>

    <!-- other properties -->
</bean>

'systemProperties' 변수는 미리 정의되어 있다. 따라서 아래 처럼 표현식에서 사용할 수 있다. 미리 정의되어 있는 변수는 #기호를 붙일 필요가 없다.

<bean id="taxCalculator" class="org.spring.samples.TaxCalculator">
    <property name="defaultLocale" value="#{ systemProperties['user.region'] }"/>

    <!-- other properties -->
</bean>

또한 다른 빈의 속성을 그 이름으로 참조할 수도 있다.

<bean id="numberGuess" class="org.spring.samples.NumberGuess">
    <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>

    <!-- other properties -->
</bean>


<bean id="shapeGuess" class="org.spring.samples.ShapeGuess">
    <property name="initialShapeSeed" value="#{ numberGuess.randomNumber }"/>

    <!-- other properties -->
</bean>

7.4.2. 애노테이션-기반 설정

@Value 애노테이션을 필드, 메서드 그리고 메서드와 생성자의 매개변수에 사용하여 기본 값을 설정할 수 있다.

다음 예제는 필드 변수에 기본 값을 설정한다.

public static class FieldValueTestBean

  @Value("#{ systemProperties['user.region'] }")
  private String defaultLocale;

  public void setDefaultLocale(String defaultLocale)
  {
    this.defaultLocale = defaultLocale;
  }

  public String getDefaultLocale()
  {
    return this.defaultLocale;
  }

}

이번에는 같은 작업을 세터 메서드에 한다.

public static class PropertyValueTestBean

  private String defaultLocale;

  @Value("#{ systemProperties['user.region'] }")
  public void setDefaultLocale(String defaultLocale)
  {
    this.defaultLocale = defaultLocale;
  }

  public String getDefaultLocale()
  {
    return this.defaultLocale;
  }

}

자동 연결(Autowiring)을 사용하는 메서드와 생성자에도 @Value 애노테이션을 사용할 수 있다.

public class SimpleMovieLister {

    private MovieFinder movieFinder;
    private String defaultLocale;

    @Autowired
    public void configure(MovieFinder movieFinder,
                          @Value("#{ systemProperties['user.region'] } String defaultLocale) {
        this.movieFinder = movieFinder;
        this.defaultLocale = defaultLocale;
    }

    // ...
}
public class MovieRecommender {

    private String defaultLocale;
   
    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao,
                            @Value("#{ systemProperties['user.country'] } String defaultLocale) {
        this.customerPreferenceDao = customerPreferenceDao;
        this.defaultLocale = defaultLocale;
    }

    // ...
}

7.5. EL 레퍼런스

생략

7.6. 예제에서 사용한 클래스

생략



top

  1. Favicon of http://jjaeko.tistory.com BlogIcon 째코 2009.04.27 01:41 PERM. MOD/DEL REPLY

    강력해 지는 만큼 복잡하고 어려워 지는군요... ㅠ

    Favicon of http://whiteship.me BlogIcon 기선 2009.04.27 09:41 PERM MOD/DEL

    SpEL은 모든 스프링 제품에서 공통으로 사용할 용도로 만들었다고 하니, 꼭 알아둬야 할 것 같아요.

Write a comment.


What's new in Spring 3.0?

Spring/etc : 2009. 4. 20. 19:34


참조: http://www.epril.com/resources/spring3/reference/html/ch02.html

요약 및 편역합니다.

2.1 자바 5

전페 프레임워크 코드를 제네릭, 가변인수(varargs) 같은 자바 5 기능을 사용하도록 수정했다. FactoryBean, 스프링 AOP, ApplicationListener 코드에 제네릭을 활용했다. 또한, TrasactionCallback과 HibernateCallback과 같은 콜백 인터페이스들은 제네릭한 결과를 반환하도록 수정했다. 스프링 코어 코드베이스를 전반적으로 자바 5에 최적화 시켰다.

스프링의 TaskExecutor 추상화 계층을 자바 5의 java.util.concurrent 시설과 밀접하게 통합되도록 수정했다. JSR-236(자바 EE 6 Concurrency Utilies)에 포함되어 있는 Callable, Future, ExecutorService 어댑터, ThreadFactory 연동 등을 지원한다. 또한 (EJB 3.1 @Asynchronous 또는) @Async 애노테이션을 사용하여 비동기 메서드 호출도 지원한다.

2.2. 개선한 문서

추가된 기능에 맞게 3.0 문서 작업을 새로 했고, 검증을 했지만 그래도 틀린 부분이 있다면 이슈를 등록해 달라.

2.3. 새로운 모듈 구조와 빌드 시스템

다음과 같은 모듈로 새롭게 개정했고 소스 트리당 모듈.jar로 관리한다.

      org.springframework.aop
      org.springframework.beans
      org.springframework.context
      org.springframework.context.support
      org.springframework.expression
      org.springframework.instrument
      org.springframework.jdbc
      org.springframework.jms
      org.springframework.orm
      org.springframework.oxm
      org.springframework.test
      org.springframework.transaction
      org.springframework.web
      org.springframework.web.portlet
      org.springframework.web.servlet

* 더 이상 모든 구성요소를 담고 있던 spring.jar는 제공하지 않는다.

새로운 스프링 빌드 시스템을 사용한다. 그 시스템은 다음 기능을 제공한다.

      Ivy 기반 "스프링 빌드" 시스템
      일관된 배포 절차
      일관된 의존성 관리
      일관된 OSGi manifest 생성

2.4. 새로운 기능 살펴보기

다음은 스프링 3.0이 새롭게 제공하는 기능이다. 이 기능들을 자세히 살펴보겠다.

      Spring Expression Language
      IoC enhancements/Java based bean metadata
      Object to XML mapping functionality (OXM) moved from Spring Web Services project
      Comprehensive REST support
      @MVC additions
      Declarative model validation
      Early support for Java EE 6

2.4.1. 자바 5에 맞게 핵심 API 업데이트

BeanFactory 인터페이스가 타입에 맞는 빈을 반환한다.

      T getBean(Stringname, Class<T> requiredType)
      Map<String, T> getBeansOfType(Class<T> type)

스프링의 TaskExecutor 인터페이스가 java.util.concurrent.Executor를 상속 받는다.

      AsyncTaskExecutor를 확장하여 표준 Callables와 Futures를 지원한다.

새로운 자바 5 기반의 converter API와 SPI
 
      stateless ConversionService와 Converters
      표준 JDK PropertyEditor 대체제

타입을 가지고 있는 ApplicationListener<E>

2.4.2. 스프링 EL(Expression Language)

스프링은 통합 EL과 비슷한 EL을 토입했다. EL은 XML 정의와 애노테이션 기반 빈 설정에서 사용할 수 있다. 이 기능에 대한 자세한 설명은 Spring Expression Language (SpEL).장을 참조하라.

스프링 EL은 모든 스프링 포트폴리오 제품에서 사용할 수 있는 단일 EL을 제공하기 위해 만들었다.

다음은 데이터베이스 설정 프로퍼티에 EL을 사용하는 예제다.

<bean class="mycompany.RewardsTestDatabase">
    <property name="databaseName"
        value="#{systemProperties.databaseName}"/>
    <property name="keyGenerator"
        value="#{strategyBean.databaseKeyGenerator}"/>
</bean>

이 기능은 애노테이션에도 사용할 수 있다.

@Repository
public class RewardsTestDatabase {

    @Value("#{systemProperties.databaseName}")
    public void setDatabaseName(String dbName) { … }

    @Value("#{strategyBean.databaseKeyGenerator}")
    public voidsetKeyGenerator(KeyGenerator kg) { … }
}

2.4.3. IoC 컨테이너

2.4.3.1. 자바 기반 빈 메타데이타

JavaConfig 프로젝트의 몇몇 핵심 기능을 스프링 프레임워크로 가져왔다. 즉 다음의 애노테이션을 직접 사용할 수 있다는 뜻이다.
   
      @Configuration
      @Bean
      @Primary
      @Lazy
      @Import
      @Value

다음은 JavaConfig 기능을 사용하는 기본적인 빈 설정 예제다.

@Configuration
public class AppConfig{
    private @Value("#{jdbcProperties.url}") String jdbcUrl;
    private @Value("#{jdbcProperties.username}") String username;
    private @Value("#{jdbcProperties.password}") String password;

    @Bean
    public FooService fooService() {
        return new FooServiceImpl(fooRepository());
    }

    @Bean
    public FooRepository fooRepository() {
        return new HibernateFooRepository(sessionFactory());
    }

    @Bean
    public SessionFactory sessionFactory() {
        // wire up a session factory using
        // AnnotationSessionFactoryBean
        asFactoryBean.setDataSource(dataSource());
        return (SessionFactory) asFactoryBean.getObject();
    }

    @Bean
    public DataSource dataSource() {
        return new DriverManagerDataSource(jdbcUrl, username, password);
    }
}

이 것이 동작하게 하려며 애플리케이션 컨텍스트 XML 설정 파일에 다음과 같이 컴포넌트 스캔을 추가한다.

<context:component-scan
    base-package="com.myco.config"/>
 
2.4.3.2. 애노테이션을 활용한 팩토리 빈 정의

FactoryBean은 스프링 컴포넌트 정의와 표준 컴포넌트-스캔 기술을 사용한 등록 방식으로 정의할 수 있다. 자세한 내용은 Factory Bean Definitions using annotations을 참조하라.

2.4.4. Data 단

스프링 웹 서비스 프로젝트에서 객체(Object)를 XML로 맵핑하는 기능(OXM)을 스프링 프레임워크로 가져왔다, 이 기능은 org.springframework.oxm 패키지에 들어있다. OXM의 자세한 사용법은 Marshalling XML using O/X Mappers를 참조하라.

2.4.5. Web 단

웹 단에서 가장 흥미로운 새 기능은 RESTful 웹 서비스와 웹 애플리케이션 지원 기능이다. 또한 새로운 애노테이션도 사용할 수 있다.

2.4.5.1. 방대한 REST 지원

RESTful 애플리케이션을 만드는 서버쪽 지원은 기존의 MVC 웹 프레임워크에서 주도적인 역할을 하는 애노테이션에 대한 확장 기능으로 제공한다. 클라이언트쪽 지원은 RestTemplate 클래스로 제공한다. 이 둘 모두 HttpConverter를 사용하여 객체와 그것에 대한 HTTP 요청과 응답 사이를 변환 해준다.

MarhsallingHttpMessageConverter는 앞서 언급한 Object to XML 맵핑 기능을 사용한다.

자세한 내용은 REST support를 참조하라.

2.4.5.2 @MVC additions

@CookieValue와 @RequestHeaders 애노테이션이 추가됐다. Mapping cookie values with the @CookieValue annotationMapping request header attributes with the @RequestHeader annotation을 참조하라.

2.4.6 선언적인 모델 검증

하이버네이트 검증기, JSR 303

작업중... 스프링 3.0 M3 배포에 포함되어 있지 않다.

2.4.7 발빠른 자바 EE 6 지원

새로운 애노테이션 @Async (or EJB 3.1's @Asynchronous 애노테이션)을 사용하여 비동기 메서드 호출을 지원한다.

JSF 2.0, JPA 2.0, 기타 등등

작업중... 스프링 3.0 M3 배포에 포함되어 있지 않다.


top

  1. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.04.21 20:13 신고 PERM. MOD/DEL REPLY

    부지런하네요;;ㅋㅋ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.04.21 21:14 신고 PERM MOD/DEL

    ㅎㅎ별말씀을~

Write a comment.


우와~ 스프링 tc 서버다!!

Spring/etc : 2009. 4. 3. 10:55


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

베타 버전이네요. 음.. 설치부터 간단하지가 않군요. 세 가지 구성요소를 설치해야 하는데, 하나는 tc 서버, 나머지는 AMS와 AMS 에이전트 입니다. 이 둘은 예~전에 한 번 설치해서 본적이 있었는데, 서버나 애플리케이션의 리소스 상황을 보여주고 관리하는데 편리한 기능을 제공하는 시스템이었습니다.

사용자 삽입 이미지

이 그림 한 장이면 이 세 개의 구성요소 간의 관계와 어떤 형태로 설치할 수 있는지 한 눈에 볼 수 있습니다.

AMS Sever, AMS Agent, tc Server를 한 컴퓨터에 모두 설치할 수도 있지만, 저렇게 나눠서 설치할 수도 있으며 그럴 때 AMS Server는 한 곳에만 설치하면 되고, 여러 컴퓨터에 각각 tc Server를 (한개 또는 여러개)설치하고  AMS Server로 정보를 보내줄 AMS Agent도 역시 컴퓨터 마다 하나씩만 설치하면 됩니다.

즉.. 이 들간의 관계를 그려보면 다음과 같다는 것을 알 수 있습니다.

사용자 삽입 이미지

드디어 나올 것이 나왔네요. 기쁩니다!! 이 녀석으로 개발을 시작해야겠습니다.
top

TAG tc Server
  1. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.04.03 12:22 신고 PERM. MOD/DEL REPLY

    ㄱㄱㄱ~~ ㅋㅋ

    Favicon of http://whiteship.me BlogIcon 기선 2009.04.03 13:27 PERM MOD/DEL

    응 이거 쓰자~

  2. slgmoney 2009.04.06 12:20 PERM. MOD/DEL REPLY

    1. tcserver-windows-beta3.sfx.zip 다운로드
    2. 압축 해제
    3. \tc서버\tcserver-windows-beta3.sfx\tcserver-windows-beta3 로 이동
    4. run.bat

    -- 인스톨 중 Checking for compatible JVM... funning Java6 : tc Server AMS will not run under Java6.

    이런 메세지 뜬 후에, 인스톨이 done 되긴 했는데요.

    그 이후에 quick setup 시키면,,

    Please ignore references to missing tools.jar
    java.lang.NoClassDefFoundError: org/apache/toors/ant/launch/Launcher
    WARNING: Default charset MS949 not supported, using ISO-8859-1 instead
    Exception in thread "main" Deleting temporary JRE
    ...hit return...

    이렇게 뜨고,, 인스톨메뉴로 돌아갑니다;,, 도와주세요;;

    Favicon of http://whiteship.me BlogIcon 기선 2009.04.06 13:04 PERM MOD/DEL

    저도 안해봐서 모르겠지만 기본 인코딩을 MS949 말고 ISO-8859-1을 써보시죠. 에러 메시지 경고 문구가 그렇게 하라네요. @_@

  3. slgmoney 2009.04.07 12:00 PERM. MOD/DEL REPLY

    WARNING: Default charset MS949 not supported, using ISO-8859-1 instead

    이 경고는 계속 나오지만 무시해도 되는것 같군요,

    디렉토리를 C:\springsource\tcServertmp 여기로 바꾸고 하니까,, 해결 됐어요,,

    꼭 그래야 하는건지는 모르지만 일단,, 설치는 다 해봤는데,, 화면이 아직 눈에 안익네요,, ,

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.04.07 16:44 신고 PERM MOD/DEL

    ㅊㅋㅊㅋ성공하셨군요!!

Write a comment.


스프링 프레임워크 트레이닝 갈까말까

Spring/etc : 2009. 3. 23. 10:56


참조: http://www.springsource.com/training/spr001/icn20090525

고민되네요. 참석하고 싶은데 걸리는게 조금 있습니다.

일단 돈이 문제입니다. 호주 달러로 거의 3000달러인데 그것도 4월 24일 전에 등록해야 2995달러고, 그 뒤에는 3230달러입니다. 세일 가격에 등록한다고 했을 때 한화로 300만원이 필요합니다.

일정이 문제입니다. 결혼식이 5월 30일인데 교육 일정이 25~28일입니다. 결혼식에 한참 신경써야 할 시기인데 색시가 서운하거나 내가 교육에 집중하지 못 할 일이 생기지는 않을지 걱정입니다.

그래도 가고 싶은 이유는 일단 실습 교육이라는 겁니다. 스프링소스 직원은 어떤 스타일로 스프링을 사용하는지 볼 수 있는 절호의 기회인 듯 합니다.

두 번째는 영어 실력 테스트입니다. 지난 번 스프링 컨퍼런스에 가서 느낀점은 스프링 보다는 영어가 중요하다는 거였습니다. 스프링은 영어를 마스터 하고 나서 해도 늦지 않겠다고 느꼈습니다. 그런데 게을러지다 보니까 쉬운거만 하게 되고 영어 공부보다는 스프링 공부가 쉬우니까 나태해졌는데.. 그런 제 자신에 경각심을 줄겸 영어 열공에 목표도 줄겸.. 여러모로 영어 학습에 기름을 부울 수 있는 계기가 될 것 같습니다.

세 번째는 스프링 자격증입니다. 스프링 자격증이 있다는 걸 모르시는 분들도 많을텐데요. 스프링 자격증을 따려면 교육 과정에 참여해야 합니다. 예외도 있긴 하지만 극히 드문 경우 같구요. 이번 교육에 참요하면 자격증 시험 등록비를 깍아 준다고 합니다. 보통 150$를 깍아 준다고 하니까 괜찮은 떡밥이라고 생각됩니다.

네 번째는 희소성입니다. 이번이 아니면 언제 또 한국에 와서 교육을 해줄지 모르기 때문에 오히려 이번에 교육을 받는게 낫지 않을까 하는 생각입니다.

시간과 돈에 여유가 있으신 분들은 참석하시면 좋을 듯합니다. 아웅~~~ 가고 싶다!!
top

  1. aStRe 2009.03.23 12:06 PERM. MOD/DEL REPLY

    여유되시면~ 가세요!
    이미 준비할껀 다 했는뎅 뭘 서운해해?

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.03.23 12:07 신고 PERM MOD/DEL

    아 그래??!! 할까 할까? ㅋㅋㅋ

  2. aStRe 2009.03.24 00:00 PERM. MOD/DEL REPLY

    ㅋㅋㅋ if you want you can do everything~!

    Favicon of http://whiteship.me BlogIcon 기선 2009.03.24 10:50 PERM MOD/DEL

    귿~~ My fiancee is generous. Ye~~

    But last night I dreamed about going into bankruptcy. ke ke ke

    show me the money.(You know, this is just a cheat-key in Starcraft.)

  3. aStRe 2009.03.24 10:35 PERM. MOD/DEL REPLY

    ㅡ.ㅡ 작히는 오타쟁이 ㅋㅋㅋ
    piancee = fiancee
    backrupcy= bankruptcy

    Favicon of http://whiteship.me BlogIcon 기선 2009.03.24 10:50 PERM MOD/DEL

    미안 내가 스펠링에 약해ㅋ

Write a comment.


스프링 웨비나: Building Twitter with Grails in 40 Minutes

Spring/Webinar : 2009. 3. 17. 22:59


내일 모래 목요일 한국 시간으로 밤 11시에 시작합니다.
https://www1.gotomeeting.com/register/844031096

스프링소스에서 Grails 개발을 담당하고 있는 Graeme Rocher가 직접 40분 안에 Grails를 사용해서 Twitter와 비슷한 애플리케이션을 만드는 데모를 보여준다고 합니다. +_+ 상상만해도 멋지네요.

스프링, JMS, Java Persistence 기술을 사용할 예정이며, Grails 애플리케이션을 Java EE 플랫폼에 배포하는 것과 관련된 고급 팁과 기술을 선보일 예정이라고 합니다.
  • 스프링-기반 도메인 객체를 사용하여 기본적인 Grails 프로젝트를 어떻게 구성하는지
  • Grails 애플리케이션에서 메시징과 영속성을 어떻게 다루는지
  • 애플리케이션에 필요한 기본 설정을 어떻게 하는지
살펴볼 수 있다고 합니다. 목요일은 오랜만에 웨비나에 참석해야겠습니다.

top

Write a comment.


REST in Spring 3: @MVC

Spring/etc : 2009. 3. 9. 11:10


참고: REST in Spring 3: @MVC

스프링 3.0의 RESTful 기능

- URI 템플릿
@PathVariable 애노테이션으로 URI의 특정 위치의 값을 맵핑해올 수 있음.
@RequestMapping("/hotels/{hotelId}")
public String getHotel(@PathVariable hotelId, ModelMap model) {
  List<Hotel> hotels = hotelService.getHotels();
  model.addAttribute("hotels", hotels);
  return "hotels";
}
이때 /hotels/1 이런 요청이 들어오면 hotelId 매개변수로 1이라는 값을 받아올 수 있음.

두 개 이상 맵핑 할 수도 있고 변수명을 다르게 줄 수도 있음.
@RequestMapping(value="/hotels/{hotel}/bookings/{booking}", method=RequestMethod.GET)
public String getBooking(@PathVariable("hotel") long hotelId, @PathVariable("booking") long bookingId, ModelMap model) {
  Hotel hotel = hotelService.getHotel(hotelId);
  Booking booking = hotel.getBooking(bookingId);
  model.addAttribute("booking", booking);
  return "booking";
}

Ant 스타일 경로를 지정할 수도 있음.
@RequestMapping(value="/hotels/*/bookings/{booking}", method=RequestMethod.GET)
public String getBooking(@PathVariable("booking") long bookingId, ModelMap model) {

}

데이터 바인딩도 사용할 수 있음.
@InitBinder
public void initBinder(WebDataBinder binder) {
  binder.initBeanPropertyAccess();
  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
  dateFormat.setLenient(false);
  binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}

@RequestMapping("/hotels/{hotel}/dates/{date}")
public void date(@PathVariable("hotel") String hotel, @PathVariable Date date)
                throws IOException {

}
/hotels/1/dates/2008-12-18 이런 요청을 받으면 2008-12-18 이 부분 문자열을 Date 타입으로 바인딩 해 줌.

- Content Negotiation
Accept HTTP 헤더로 뷰를 판단함. 서버 응답은 Content-Type를 통해 뷰를 전달한다. 이런 과정을 content negotiation이라고 한다.

주요 클래스: ContentNegotiatingViewResolver

- Views
RSS 피드를 만들 때 사용할 수 있는 뷰: AbstractAtomFeedView, AbstractRssFeedView
XML 뷰: MarshallingView
JSON 뷰: JacksonJsonView

- HTTP Method Conversion
HTTP에서는 GET, POST, DELETE, PUT을 제공하지만 HTML은 GET, POST만 지원한다. 따라서 POST를 사용하면서 hidden parameter로 Method를 명시하면 해당 Method로 변환해주는 HiddenHttpMethodFilter 제공.
스프링 form 태그에서 이 기능을 지원하기 때문에 form태그의 method에 delete, put도 사용 가능.
<form:form method="delete">
    <p class="submit"><input type="submit" value="Delete Pet"/></p>
</form:form>

@RequestMapping(method = RequestMethod.DELETE)
public String deletePet(@PathVariable int ownerId, @PathVariable int petId) {
    this.clinic.deletePet(petId);
    return "redirect:/owners/" + ownerId;
}

- ETag support
ETga는 HTTP 1.1 호환 응답 헤더로 해당 URL에 있는 컨텐츠가 변경 됐는지 확인할 때 사용.
스프링은 ShallowEtagHeaderFilter를 제공하여 JSP로 랜더링한 결과를 캐싱하고 MD5 해시를 만들고 응답에 ETag를 반환해준다. 다음에도 사용자가 같은 자원을 요청하면 이전에 만든 해시를 If-None-Match 값으로 사용한다. 두 개 해시값을 비교해서 같으면 304(Not Modified)를 반환한다.

차후에 제공할 deep ETag는 모데인 객체나 RDBMS 테이블과 관련되어 있어 좀 더 복잡한데 JPA의 @Version(낙천적-롹킹할 때 사용하는 애노테이션) 기반 또는 ApsectJ의 애스팩트로 지원할 예정~ 이라고 합니다.
top

  1. slgmoney 2009.03.09 12:21 PERM. MOD/DEL REPLY

    제가 궁금해서 그러는데요. 지금 스프링3 m2 버전 .. 이 버전 사용해도 괜찮은건지 궁금합니다. 스프링3가 나올때까지 기다려야 하는건지.. m2 라는것이 완전하진 않지만 사용해도 괜찮다는건지 모르겠네요.. 초보의 질문;; 일단 m이라는게 마일스톤이란 뜻이 맞나요? 그리고 이걸 왜 m2 라고 붙이나요?

    Favicon of http://whiteship.me BlogIcon 기선 2009.03.09 12:46 PERM MOD/DEL

    사용해도 괜찮습니다. 스프링은 충분한 개발자 테스트를 제품과 함께 제공하기 때문이죠.

    마일스톤이라는 뜻 맞구요. m2는 두 번째 마일스톤 버전을 줄여서 표현한 겁니다.

  2. ISU 2010.07.08 19:53 PERM. MOD/DEL REPLY

    안녕하십니까 spring 관련 정보를 많이 얻고 있습니다. 먼저 감사 드리고..
    @PathVariable을 사용하는데 도움을 얻고자 이렇게 문의를 드립니다.

    @RequestMapping(value={"/user/{id}","/user/{id}/book/{cd}"})
    public String home(@PathVariable String id, @PathVariable String cd

    이렇게 처리를 하면 첫번째 url로 접속시 에러가 발생합니다.

    @RequestParam(value = "cd", required = false) String cd

    로 처리를 하면 두번째 url로 접속을 하면 cd가 null로 떨어집니다

    url에 따라 cd도 param으로 받아야 하는데... 가능한 방법이 있을까요?

    Favicon of http://whiteship.me BlogIcon 기선 2010.07.08 23:36 PERM MOD/DEL

    첫번째 질문, URL 두개를 하나의 핸들러에 매핑시켰는데 그 중 첫번째 것으로 접근시 에러나는건 @PathVariable String cd에 바인딩할 부분이 URL에 없어서 그런것 같구요.

    두번째 질문, @RequestParam을 사용한 코드는 URL의 파라미터 부분.. 그러니깐.. member?cd=xxx 이런 부분을 매핑할 때 사용하는 것이지 URI 템플릿을 바인딩 할땐 @PathVariable을 사용하셔야 됩니다. 따라서 요청하신 URL에서 ?cd=xxx 이런 부분이 없기 때문에 null이 들어오는게 아닐까 싶네요.

    말씀하신대로 핸드러를 둘로 나누시는게 좋겠습니다.

  3. ISU 2010.07.08 20:24 PERM. MOD/DEL REPLY

    일단 url별로 두개로 나누고 한쪽에서 return "forward:~" 처리 했습니다.
    혹 더 좋은 솔루션이 있으면 코멘트 부탁드립니다.

    Favicon of http://whiteship.me BlogIcon 기선 2010.07.08 23:38 PERM MOD/DEL

    잘 처리하신것 같네요. forward: 프리픽스를 저럴때 사용할 수 있겠구요. 전 forward:를 잘 안써봐가지고요.ㅋㅋ

  4. ISU 2010.07.09 08:13 PERM. MOD/DEL REPLY

    ^^ 답변 감사드립니다~

    Favicon of http://whiteship.me BlogIcon 기선 2010.07.09 09:59 PERM MOD/DEL

    넵~ 보통은 질문만하고 가지는데 감사인사.. 감사합니다.

Write a comment.


STS(Spring Tool Suite) 2.0 RC 버전의 OSGi 개발 툴

Spring/etc : 2009. 3. 5. 20:29


원문 : OSGi Development Tools in STS 2.0

간단하게 요약만 합니다. 일단 새 제품 다운로드부터 해야겠죠?

기존에 제공하던 툴
  • dm Server Integration: dm 서버를 이클립스 WTP로 통합하여 dm 서버 인스턴스 생명 주기 관리와 OSGi 번들, PAR, 일반 JEE WAR 파일 배포를 할 수 있게 해줌. 또한 dm Server 통합은 설치한 구성물의 코드가 바뀌면 자동으로 업데이트하고 리프레쉬 해줌.
  • 프로젝트 마법사: OSGi 번들과 PAR 프로젝트 생성 마법사 제공.
  • Manifest 편집기와 검증: MANIFEST.MF 파일에서 코드 완성, 하이퍼링크, 검증 기능을 제공.
  • Classpath 관리: OSGi 의존성 메타 데이터를 MANIFEST.MF에서 가져와서 클래스패스 컨테이너를 만든다. 테스트 용 의존성은 테스트 소스 폴더의 META-INF/TEST.MF 사용.
  • 저장소 브라우저: 스프링소스 엔터프라이즈 번들 저장소에 쉽게 접근하게 해준다.
새 기능

STS 2.0은 Import-/Export-Pachage 관계와 서버를 기반으로 번들을 분석하고 그들의 의존성을 가시화하는 기능을 제공한다. OSGi 런타임 콘솔에서 볼 수 있는 텍스트 형태와 비슷한 정보에 접근할 수 있다. 장점은 그런 정보를 IDE에서 쉽게 이요할수 있고 번들 메타 데이터와 연결을 비주얼 툴에서 클릭으로 네비게이션 할 수 있다는 것이다.

서버 편집기에서 Bundle Overview 페이지를 제공한다. 이 페이지에서는 OSGi 런타임에서 접근할 수 있는 모든 연결 정보와 MANIFEST의 번들의 메타 데이터에 접근을 제공하며 설치된 모든 번들을 보여준다.

사용자 삽입 이미지

번들 의존성 그래프를 제공한다. 패키지 또는 서비스 의존성을 보여줄 수 있다. 그래프에서 의존성을 몇 단계까지 보여줄 지 설정할 수 있다.

사용자 삽입 이미지

이퀴녹스 콘솔과 거의 같은 서버 콘솔을 제공한다. 명령 완성과 명령 히스토리 기능을 제공한다.

사용자 삽입 이미지

실행하기

어느덧 다운로드가 끝나고 이제 실행볼 시간이네요. 캬~~ 따끈따끈한 개발 도구를 어디 열어 볼까요~

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

음~ dm 서버가 잘 들어있군요.  자 일단 서버 만들고 바로 가동시켜 봅니다. 그리고 서버 콘솔에서 ss를 입력해 봤습니다.

사용자 삽입 이미지
다음은 Bundle Information 탭입니다. 와우..

사용자 삽입 이미지
마지막으로 번들 그래프를 보죠.. 캬오~~~~
사용자 삽입 이미지
그림에서 패키지를 더블클릭하면 그래프가 샤샥 바뀌는데 아주 재밌습니다.

이상으로 STS 2.0 리뷰를 마칩니다.
top

  1. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.03.05 20:50 신고 PERM. MOD/DEL REPLY

    홋;; 빨라 빨라 ~~ ~~ ㅋ
    전 Groovy 1.6 보면서 후덜덜덜 .. 이러고 있는데;;ㅋ
    굳 ! 맨 !

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.03.05 21:20 신고 PERM MOD/DEL

    ㅇㅇ그루비 나도 봐야지~

Write a comment.


스프링 3.0 m2 빌드 삽질 중

Spring/etc : 2009. 3. 4. 02:21


http://blog.springsource.com/2009/03/03/building-spring-3/ 윗 글을 보며 삽질 중입니다.

사용자 삽입 이미지

컴파일 에러가 난다며 두 번째 단계에서 막히네요. 자바 1.5라서 그런가 싶어서 kenu 형 블로그보고 1.6으로 바꾼 담에 해봤지만... 그래도 안 되네요. 흠~ 왜 컴파일이 안 되는걸까나.. @_@

readme.txt를 읽어봤더니 javac 1.6 이상, ant 1.7 이상이라길래 다시 한 번 버전을 확인해 봤습니다
사용자 삽입 이미지
흠~~ @_@ 두 시가 넘었네.. 낼 다시 해보자.


top

  1. Favicon of http://toby.epril.com BlogIcon 토비 2009.03.04 07:26 PERM. MOD/DEL REPLY

    바보

    Favicon of http://whiteship.me BlogIcon 기선 2009.03.04 10:41 PERM MOD/DEL

    그런가봐요. 흑...

  2. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.03.04 09:27 신고 PERM. MOD/DEL REPLY

    나도 어제 새벽에 블로그 올라 왔길래 해봣는데;; 자바 1.6.10버전으로 했구 ant 1.7.1 버전.. ;; 컴파일 하는데는 오류는 안났지만.. ant 실행시 outofmemory 가 나서 .. ㅋ 시간이 좀 걸렸다는;;
    블로그에 보면;; 빌드를 위해선 java6 버전이 필요하다고 나와 있잖아요 ;;ㅋ
    한번 다하고 다시 한번 다했는데;; 40분 15초 걸리던데요;; ㅡㅡ; 새벽 3시까지 돌렸다는거;; ㅜ

    Favicon of http://whiteship.me BlogIcon 기선 2009.03.04 10:41 PERM MOD/DEL

    염장이지?! 난 컴파일이 안 된다고! ㅠ.ㅠ

Write a comment.


Petclinic을 통해 스프링 3.0 주요기능 살펴보기

Spring/etc : 2009. 2. 26. 10:09


Spring Framework 3.0 M2 released

스프링 3.0 m2가 배포됐습니다. 유겐 휄러가 주요 기능을 잘 정리해 뒀네요. 아쉬운건 아직도 레퍼런스 업데이트가 되지 않았다는 겁니다. 어쩔 수 없이 아쉬운 사람이 우물 판다고 예제 코드를 뒤적거릴 수밖에 없더군요.

EL 지원에 관한 예제는 petclinic-servlet.xml에서 볼 수 있습니다.

    <bean id="visits" class="org.springframework.samples.petclinic.web.VisitsAtomView"/>

    <bean id="vets" class="org.springframework.web.servlet.view.xml.MarshallingView">
        <property name="contentType" value="application/vnd.springsource.samples.petclinic+xml"/>
        <property name="marshaller" ref="marshaller"/>
    </bean>

    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="mediaTypes">
            <map>
                <entry key="xml" value="#{vets.contentType}"/>
                <entry key="atom" value="#{visits.contentType}"/>
            </map>
        </property>
        <property name="order" value="0"/>
    </bean>

이렇게 visits와 vets 빈의 contentType 속성에 들어있는 값을 #{vets.contentType}, #{visits.contentType} 이런식으로 참조하여 다른 빈에 주입할수 있습니다. visits에는 contentType속성이 없는 것 같지만 이 속성은 AbstractView에 있는 속성이고 VisitsAtomView 클래스가 그것을 상속했기 때문에 기본값을 가지게 될 겁니다.

다음으로 RestTemplate 기능은 컨트롤러에서 볼 수 있습니다.

@Controller
@RequestMapping("/owners/{ownerId}/pets/new")
@SessionAttributes("pet")
public class AddPetForm {
...
    @RequestMapping(method = RequestMethod.GET)
    public String setupForm(@PathVariable("ownerId") int ownerId, Model model) {
        Owner owner = this.clinic.loadOwner(ownerId);
        Pet pet = new Pet();
        owner.addPet(pet);
        model.addAttribute("pet", pet);
        return "pets/form";
    }
...
}

이런 식으로 URL의 일부를 매서드 매개변수로 바인딩 해줍니다. 바인딩 할 필요가 없는 경우 와일드 카드를 이용할 수도 있습니다.

@Controller
@RequestMapping("/owners/*/pets/{petId}/visits/new")
@SessionAttributes("visit")
public class AddVisitForm {
...
    @RequestMapping(method = RequestMethod.GET)
    public String setupForm(@PathVariable("petId") int petId, Model model) {
        Pet pet = this.clinic.loadPet(petId);
        Visit visit = new Visit();
        pet.addVisit(visit);
        model.addAttribute("visit", visit);
        return "pets/visitForm";
    }
...
}

이런 식으로 말이죠. 간단해 보이네요~

다음으로는 AtomView 지원 기능도 살펴봤습니다. 3.0에 추가된 AbstractAtomFeedView 이 클래스를 상속해서 구현하면 되더군요.

public class VisitsAtomView extends AbstractAtomFeedView {
...
    @Override
    protected void buildFeedMetadata(Map<String, Object> model, Feed feed, HttpServletRequest request) {
...
    }

    @Override
    protected List<Entry> buildFeedEntries(Map<String, Object> model,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
...
    }
   
}

구현은 이런 식이며 피드 메타 데이터는 Feed 객체에 Id와 Title을 그리고 Updated에 날짜를 채워줍니다. 코드에 에러가 있어서 Feed 라는 클래스를 자세히 보지 못해서 아쉽네요. 그 아래 매서드에서는 Entry List를 만들어서 반환해줍니다. Entry도 역시 자세히 보고 싶은데 못봤습니다. id, title, updated, summary 정보를 설정하는 코드로 대충 어떤 속성이 있는지 예상할 순 있었습니다.

마지막으로 OXM 기능을 살펴봤는데 끝내주더군요. @_@

    <bean id="vets" class="org.springframework.web.servlet.view.xml.MarshallingView">
        <property name="contentType" value="application/vnd.springsource.samples.petclinic+xml"/>
        <property name="marshaller" ref="marshaller"/>
    </bean>

    <oxm:jaxb2-marshaller id="marshaller">
        <oxm:class-to-be-bound name="org.springframework.samples.petclinic.Vets"/>
    </oxm:jaxb2-marshaller>

보시다시피 MarshallingView는 스프링 3.0에서 제공하는 클래스고 Vets는 도메인 클래스입니다. OXM을 지원하는 스키마까지 제공하는군요. 저렇게만 설정하면 객체를 알아서 XML로 변환해주느냐???... 아니요 한가지 더 필요합니다.

 @XmlRootElement
public class Vets {

    private List<Vet> vets;

    @XmlElement
    public List<Vet> getVetList() {
        if (vets == null) {
            vets = new ArrayList<Vet>();
        }
        return vets;
    }

}

캬... 뭐 대충 눈으로 보면 뭐하는건지 알 수 있게해주는 직관적인 코드입니다.

자 이정도면 대충 주요 기능은 거의다 조금 살펴본 것 같습니다. 예제 코드좀 돌려보면 좋겠는데 그건 나중에 해봐야겠습니다. 지금은 번역 땜시..-_-;;



top

  1. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.02.26 13:18 신고 PERM. MOD/DEL REPLY

    큭; OXM 멋찐데요;;ㅋ 확 땡기는데 3.0이요;ㅋ

    Favicon of http://whiteship.me BlogIcon 기선 2009.02.27 09:16 PERM MOD/DEL

    ㅇㅇ 귿이네~
    역시 스프링소스야

  2. 권남 2009.02.26 18:12 PERM. MOD/DEL REPLY

    잘봤습니다~
    3.0을 확질러버려... ^^

    Favicon of http://whiteship.me BlogIcon 기선 2009.02.27 09:17 PERM MOD/DEL

    ㅋㅋ2.5부터 마무리 하구요.

  3. Favicon of http://igooo,org/tc BlogIcon igooo 2009.02.27 10:04 PERM. MOD/DEL REPLY

    [질문]예제는 어디에서 볼 수 있나요?

    Favicon of http://whiteship.me BlogIcon 기선 2009.02.27 11:01 PERM MOD/DEL

    스프링 3.0 m2 소스코드를 다운 받으시면 볼 수 있습니다.

Write a comment.


스프링 트랜잭션 주의할 것

Spring/etc : 2009. 2. 7. 20:46


Transaction strategies: Understanding transaction pitfalls

@Transactional(readOnly = true, propagation=Propagation.REQUIRED)
public long insertTrade(TradeData trade) throws Exception {
   // 어떤 코드
}

위 코드에 있는 insertTrade를 실행행하면 어떤 결과가 발생할까요?

A. read-only connection 예외가 발생한다.
B. 데이터를 추가하고 커밋한다.
C. read-only가 true라서 아무것도 하지 않는다.

당연히 A일 것 같은데... // 어떤 코드 부분이 JDBC 코드일 경우이고 JPA나 하이버네이트 같은 ORM 코드면 propagation 설정 REQUIRED가 모든 것을 재정의해서 새로운 트랜잭션을 시작하고 read-only 플래그가 없는 것 처럼 동작하게 된다네요... @_@

지금은 넘 졸려서 낼 자세히 읽어봐야겠습니다.

따라서 읽기 전용 매서드의 경우 다음과 같이 SUPPORTS 프로퍼게이션 모드를 사용하는게 타당하다고 합니다. 왜냐면 보통 다음과 같이 읽기 전용 매서드를 설정하는데..

@Transactional(readOnly = true)
public TradeData getTrade(long tradeId) throws Exception {
   return em.find(TradeData.class, tradeId);
}

이 때 기본 프로퍼게이션이 REQUIRED 모드기 때문에 매번 새로운 트랜잭션을 만들어 사용하고 사용하는 DB에 따라서는 불필요한 읽기 롹까지 사용해서 데드락을 발생시킬 수도 있다고 하기 때문입니다. 따라서..

@Transactional(readOnly = true, propagation=Propagation.SUPPORTS)
public TradeData getTrade(long tradeId) throws Exception {
   return em.find(TradeData.class, tradeId);
}

이렇게 SUPPORTS로 변경하여 기존 트랜잭션이 있으면 사용하고 없으면 사용하지 않도록 하거나..

public TradeData getTrade(long tradeId) throws Exception {
   return em.find(TradeData.class, tradeId);
}

요렇게 읽기 전용인 경우에는 아예 @Transactional 애노테이션을 아예 사용하지 않는게 나아보입니다. 굳이 원자화 할 것도 없고~ Isolation level만 적당선에서 타협한다면 롹을 걸 일도 없고~


REQUIRES_NEW  사용시 주의 할 것.

@Transactional(propagation=Propagation.REQUIRES_NEW)
public long insertTrade(TradeData trade) throws Exception {...}

@Transactional(propagation=Propagation.REQUIRES_NEW)
public void updateAcct(TradeData trade) throws Exception {...}

이런 매서드와 트랜잭션 설정이 있을 때

@Transactional(propagation=Propagation.REQUIRES_NEW)
public long insertTrade(TradeData trade) throws Exception {
   em.persist(trade);
   updateAcct(trade);
   //exception occurs here! Trade rolled back but account update is not!
   ...
}

이런 식으로 코딩하면... updateAcct() 이후에 에러가 발생하면 updateAcct는 쿼리가 날아가는데 나머지 내용은 롤백 되는 현상이 발생할 수 있죠. 왜냐면 매번 새로운 트랜잭션을 만들기 때문에 insertTrade를 실행하는 트랜잭션과 updateAcct를 실행하는 트랜잭션이 별개기 때문입니다.

뭐~ 이건 쉽네요. 걍 REQUIRED로 쓰거나 MANDATORY를 쓰면 됩니다.

롤백과 관련해서는 checked exception에 대비해야 한다.

@Transactional(propagation=Propagation.REQUIRED)
public TradeData placeTrade(TradeData trade) throws Exception {
   try {
      insertTrade(trade);
      updateAcct(trade);
      return trade;
   } catch (Exception up) {
      //log the error
      throw up;
   }
}

이런 코드가 과연 안전할까? 아니요. 왜냐면 저 코드에서 만약 updateAcct() 매서드 처리 도중에  checked exception이 발생하면 insertTrade() 매서드는 그대로 실행하고 예외도 그냥 던지고 말기 때문에 데이터가 불안전한 상태가 될 것입니다. 따라서 checked exception에 대비해서..

@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
public TradeData placeTrade(TradeData trade) throws Exception {
   try {
      insertTrade(trade);
      updateAcct(trade);
      return trade;
   } catch (Exception up) {
      //log the error
      throw up;
   }
}

이런 식으로 하는게 좋겠습니다.



top

  1. 권남 2009.03.09 16:19 PERM. MOD/DEL REPLY

    Spring 2.5, Hibernate 3.3, @Transactional(readOnly = true, propagation=Propagation.REQUIRED) 이 상태에서 insert를 할경우, 왜 난 readOnly니까 쓰기 작업을 할 수 없다는 오류가 날까요?
    원문을 봐도 마찬가지던데.. 내가 뭔가를 잘못이해하고 있나봐요.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.03.09 16:48 신고 PERM MOD/DEL

    그 매서드 안에 코드는 하이버네이트 Session을 사용하신거겠죠?

    음.. 아마도 트랜잭션을 저 매서드를 만날 때 새로 만든게 아니라 기존에 있던 트랜잭션을 사용하는거라 그렇게 잘 동작한게 아닐까 싶네요.

    OSIV 필터 같은 것을 쓰신다면 요청이 들어왔을 때 쓰레드로컬에 미리 만들어 두니까요.

  2. Favicon of http://kwon37xi.egloos.com BlogIcon 권남 2009.03.09 20:14 PERM. MOD/DEL REPLY

    -- 수정: 이 댓글은 오류를 포함하고 있습니다.

    문제점을 확인하였습니다.
    문서를 자세히 보면

    For some vendors, such as Hibernate, the flush mode will be set to MANUAL, and no insert will occur for inserts with non-generated keys

    이 부분이 있는데, 이런 현상은 non-generated key(auto_increment를 사용하지 않고, 키 값이 객체에 직접 지정되는 방식)이고, Flush 모드가 Manual(기본 모드죠?) 이면서, insert/update 등을 할 때 발생합니다.
    내생각엔 generated key 일 경우일지라도, 시퀀스를 사용해서 키를 생성하는 DB에서는 insert가 될 것으로 보입니다. sequence에서 키값 가져오는 것은 read 작업이라서 그냥 해버리고 말 수도 있으니까(이건 단순 가정임).

    그 경우, 트랜잭션 안에서 insert가 일어나지 않고, 스프링의 트랜잭션 영역을 빠져 나간뒤에 한꺼번에 insert가 일어나기 때문에 스프링의 트랜잭션 설정의 영향을 받지 않게 됩니다.

    실제로 트랜잭션 종료 직후 시점에서 로그를 찍어보니, 트랜잭션이 종료된 이후에 insert statement가 실행되었습니다.

    아무때나 이런 현상이 일어나는 것은 아니었던 것이죠.

  3. Favicon of http://kwon37xi.egloos.com BlogIcon 권남 2009.03.09 20:16 PERM. MOD/DEL REPLY

    위 세번째 댓글은 저의 착각이었습니다. 다른 readOnly=false 트랜잭션이 걸린 서비스로 감싼 상태에서 안쪽 서비스 메소드의 readOnly=true 만 보고서 읽기 전용에서 호출했다고 착각했네요.

    제가 찾은 결론은, 위와 같은 readOnly=true 상태에서, insert,update 되는 현상은 나타나지 않는 다는 것입니다.

    스프링의 hibernateTemplate을 통해 save 메소드를 타게 되면 스프링 내부에서 checkWriteOperationAllowed(session) 메소드로 무조건 트랜잭션이 writable한지 여부를 검사합니다.
    따라서 HibernateTemplate을 사용하면 위 문서에서 말한 현상은 발생할 수 없습니다.
    update,delete도 마찬가지더군요.

    하지만 예외적으로, Spring HibernateTemplate을 사용하지 않고, Hibernate Session의 save 메소드를 직접 호출하면 readOnly=true인데 insert/update가 되는 현상이 발생합니다.
    트랜잭션의 writable 여부를 체크하는 것은 스프링이지 하이버네이트가 아니기 때문입니다. 스프링을 거치지 않고 Hibernate의 메소드를 바로 호출하면, 원문에 나온 트랜잭션의 writable여부와 무관하게 save되는 오류가 발생하게 됩니다.(그것도 non-generated id를 가진 엔티티의 경우에 한합니다).

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.03.09 20:43 PERM MOD/DEL

    넹 위 본문에서도 스프링의 템플릿 클래스들이 아니라 JPA의 EntityManager나 하이버네이트의 Session을 사용할 때 발생할 수 있는 문제를 말해준 듯 합니다.

    저는 스프링의 템플릿 클래스들을 사용하지 않고 하이버네이트 API를 직접 이용해서 DAO를 구현하는게 더 깔끔해서 그렇게 사용하고 있습니다.

    따라서 결론을 약간 보완하여.. 스프링의 XXXTemplate 클래스를 사용하면 readOnly=true 상태에서 insert, update되는 현상은 나타나지 않는다. 라고 하는게 좋을 듯해 보이네요. ^^

  4. 권남 2009.03.09 23:53 PERM. MOD/DEL REPLY

    내가 HibernateTemplate 쓴다고 남들도 다 그렇겠거니 하는 생각에, EntityManager 를 못봤군요. --;
    암턴 올만에 소스 뒤져봤어요.. ^^

    Favicon of http://whiteship.me BlogIcon 기선 2009.03.10 09:52 PERM MOD/DEL

    캬~~ 멋지세요.
    하이버네이트 번역도 같이 하실래요. ㅋㅋ

Write a comment.


빈 속성에 값 설정 했는지 확인하기

Spring/etc : 2009. 2. 4. 21:22


null 체크가 될 수도 있겠고 어떤 값이든 주입 됐는지 확인하는 것일 수도 있겠습니다. 예전에 대충 정리해둔 적은 있는데 잊어버렸던 거라서 다시 정리해 둡니다.

<bean> 엘리먼트에 dependency-check라는 속성이 이 속성을 설정하지 않으면(기본값) 빈 속성에 어떤 값이나 빈이 주입 되었는지 확인하지 않습니다.

simple 값을 주면 기본 타입과 컬렉션 타입만 검사합니다.

object 값을 주면 simple이 검사하는 것을 제외한 레퍼런스 타입을 검사합니다.

all 값을 주면 모든 속성을 검사합니다.

요즘은 @Autowired로 주로 DI를 하기 때문에 점점 예전 빈 설정 내용들은 잊혀져 가는 것 같습니다. @Autowired는 기본 값이 필수로 되어있죠. 그래서 오히려 반대로 없어도 괜찮다고 설정 하려면 애노테이션에 required=false 속성을 추가해 줘야 합니다.

...
    private MovieFinder movieFinder;

    @Autowired(required=false)
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
...

이런 식으로..
top

Write a comment.


싱글톤, 비싱글톤 언제 써야 할까?

Spring/etc : 2009. 2. 4. 21:10


참고:  Pro Spring 2.5 3장

요즘 이 책을 재벌 작업을 하고 있는데 공부한지 오래되서 잊었거나 미쳐 보지 못했던 내용들이 등장하면 피로가 조금 줄어드는 느낌을 받곤 합니다.

그 중 하나가 바로 이 글의 제목과 관련된 내용이었습니다. 스프링을 가지고 웹 애플리케이션을 몇 번 만들어 봤지만 singleton 스코프 빼곤 별로 써본 기억이 나질 않을 정도인데 새삼 생각해보게 하는 내용들이 있었습니다.

싱글톤이 적절한 경우
- 상태가 없는 공유 객체
- 읽기 전용 상태를 가지고 있는 공유 객체
- 상태를 공유하는 공유 객체
- 쓰기가 가능한 상태를 약간 가지고 있으면서 매우 빈번하게 사용하는 객체

비싱글톤이 적절한 경우
- 쓰기가 가능한 상태를 가진 객체
- private 상태를 가지고 있는 객체

여기서 주목해야 할 것은 같은 쓰기 가능한 상태를 가진 객체인데 어느것은 싱글톤 어느 것은 비싱글톤이 적절하다는 부분인데 동기화 비용과 객체 생성 비용을 가지고 나누더군요.

자세한 내용은 프로 스프링 2.5 번역서를 참고하세요~ ㅋㅋㅋ
top

  1. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.02.04 23:31 신고 PERM. MOD/DEL REPLY

    글만 봐선 딱히 잘 모르겠네욥..ㅋ
    어여 빨리 3장 궈궈쓍~;;

    Favicon of http://whiteship.me BlogIcon 기선 2009.02.05 09:19 PERM MOD/DEL

    오늘 베타리딩에 올린다~

  2. 신난다 2009.02.05 01:17 PERM. MOD/DEL REPLY

    싱글턴은 장점보다 단점이 훨씬 큰데,
    싱글턴을 쓰지 말자는게 아니라
    적절한 경우를 나열한 책이 있다니 사실에 움찔했습니다.

    적절하다고 예로든 경우에도 MonoState 패턴이 더 적절하다고 생각합니다.

    Favicon of http://whiteship.me BlogIcon 기선 2009.02.05 09:19 PERM MOD/DEL

    넹.. 글쿤요!

    토비 2009.02.05 13:26 PERM MOD/DEL

    스프링의 싱글톤 스코프와 디자인패턴에서 말하는 싱글톤 패턴을 같은 것이라고 오해하신 것 같군요.
    스프링은 기존 싱글톤 패턴의 문제를 극복하기 위해서 싱글론 레지스트리라는 방식으로 싱글톤 개념을 적용합니다. 이를 이용하면 싱글톤 패턴과 같은 방식을 사용하지 않은 단순한 자바 클래스를 싱글톤 "개념"으로 사용할 수 있습니다.

    Favicon of http://whiteship.me BlogIcon 기선 2009.02.05 14:13 PERM MOD/DEL

    싱글톤 패턴의 문제라 함은?
    - 인터페이스를 사용하지 못 함.
    - 구현체 교체하기 힘듬
    - 따라서 테스트 하기도 힘듬.
    이런 것일듯..

    Kevin 2009.03.02 01:28 PERM MOD/DEL

    싱글톤도 인터페이스 사용할 수 있습니다.
    그러니 구현체 교체도 힘들지 않구요.

    다만 싱글톤 자체를 상속하여
    Subtyping 하는것에 문제가 생겨서
    재사용성과 확장성을 보장하기 힘들다는것이
    문제가 아닐까 싶습니다.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.03.02 09:20 신고 PERM MOD/DEL

    넹.. 찾아보니 조금 복잡해 보이지만 Singleton Interface를 사용하는 방법도 있었네요.

    http://radio.weblogs.com/0122027/stories/2003/10/20/implementingTheSingletonPatternInJava.html

    감사합니다~

  3. 신난다 2009.02.05 15:28 PERM. MOD/DEL REPLY

    오~ 알겠습니다.
    움찔하지 않아도 되서 다행이네요. ^^

Write a comment.




: 1 : 2 : 3 : 4 : 5 : ··· : 12 :