레퍼런스 Spring프레임워크 소개문서 (1)

황제낙엽 2007.03.22 06:54 조회 수 : 107 추천:70

sitelink1  
sitelink2  
sitelink3  
extra_vars6  
출처따위 없슴

http://www.theserverside.com/articles/article.tss?l=SpringFramework

이 문서는 Spring프레임워크 소개문서입니다. 기존에 1.0버전을 기준으로 작성된 소개문서가 있으나 많은 부분이 업데이트되어 새로운 페이지에 번역작업을 수행합니다. 기존 소개문서와 비교해 보시면 처음 로드맵과 1.2버전에 들어와서 로드맵이 어떻게 번경이 되었는지 살펴보는것도 굉장히 큰 도움이 되리라 생각합니다.

 

2005년 5월

이 글은

2003년 10월 이 글의 첫번째 버전이 나간후 Spring프레임워크는 대중적으로 꾸준한 성장을 하고 있다. 이것은 1.0버전을 통해 현재 1.2버전까지 다루고 있으며 산업적 프로젝트의 넓은 범위에서 채택되고 있다. 이 글에서 나는 Spring이 달성한 것과 당신이 J2EE애플리케이션을 개발하는데 도움을 준다고 믿는 이유에 대해서 이야기를 할것이다.

아직도 다른 프레임워크를 사용하는가?

당신은 "다른 프레임워크 없이" 라는 생각을 할지도 모른다. 당신은 왜 이 글을 읽거나 Spring프레임워크를 다운로드 받는가.? 언제 많은 J2EE프레임워크가 있었고 언제 당신 자신만의 프레임워크를 빌드할수 있었는가.? 커뮤니티내 지속적인 높은 레벨의 관심사항은 Spring이 뭔가 가치있는 것을 제공해야만 한다는 하나의 표시이다. 여기엔 수많은 기술적 이유가 있다.

나는 여러가지 이유에서 Spring이 유일하다고 믿는다.

  • 이것은 다른 유명한 프레임워크가 하지 않는 중요한 위치를 차지한다. Spring은 당신의 비지니스 객체를 관리하기 위한 방법을 제공하는데 집중한다.
  • Spring은 포괄적이고 모듈적이다. Spring은 다른 부분에는 상관없이 특정부분만을 선택해서 사용할수 있고 내부적으로는 일관적인 계층화된 구조를 가지고 있다. 그래서 당신은 학습과정을 통해 최대한의 잇점을 얻을수 있다. 당신은 예를 들면 JDBC의 사용을 단순화하거나 당신의 모든 비지니스 객체를 관리하가 위해서 Spring을 사용할수도 있다. 그리고 현재 존재하는 프로젝트로 Spring을 새로 도입하는것은 쉽다.
  • Spring은 테스트되기 쉽게 코드를 작성하도록 당신을 돕기 위해 디자인되었다. Spring은 테스트지향 프로젝트에는 이상적인 프레임워크이다.
  • Spring은 증가하는 중요한 통합 기술이다. 이것의 역활은 다양한 큰 업체로 부터 인정받았다.

Spring은 당신의 프로젝트를 위한 하나 이상의 프레임워크의 의존성을 필요로 하지 않는다. Spring은 전형적인 애플리케이션의 가장 중요한 기반관계를 차지하는 잠재적인 one-stop가게이다. 이것은 또한 다른 프레임워크가 하지 않는 분야를 담당한다.

2003년 2월 이후 오프소스 프로젝트는 오랜기간동안 지속되어 왔다. 오픈소스 프로젝트는 내 책인 Expert One-on-One J2EE Design and Development에서 나온 기반코드로부터 시작되었다. 늦은 2002년 Expert One-on-One J2EE는 Spring의 배후의 기본적인 구조적 생각을 표현한다. 어쨌든 구조적 개념은 이른 2000년 으로 돌아간다. 그리고 많은 성공적이었던 상업적 프로젝트를 위한 기반구조를 개발하면서 생긴 나의 경험을 반영한다.

2003년 1월 이후 Spring은 소스포지에 호스팅되었다. 현재 Spring개발과 지원에 모든 시간을 할애하는 20명의 개발자가 있다. 크게 발전한 오픈소스 커뮤니티는 그들이 개별적으로 달성할수 있는 것보다 더 많은것을 달성하도록 돕고 있다.

Spring 의 구조적 이득

우리가 밑에서 설명을 하기 전에 Spring이 프로젝트로 가져올수 잇는 몇가지 이득을 알아보자.

  • Spring은 당신이 EJB를 사용하든지 말든지 당신의 미들티어 객체를 효과적으로 구성할수 있다. Spring은 특정 J2EE API를 연동하기 위해서 Struts또는 다른 프레임워크를 사용한다면 당신을 도와줄것이다. 그리고 이것이 미들티어내 대부분 가치있는 것처럼 Spring의 설정관리서비스는 어떠한 실행환경내에서 구조적 레이어내에서 사용될수 있다.
  • Spring은 많은 프로젝트에서 보여지는 싱글톤의 증식을 제거할수 있다. 나의 경험으로 볼때 이것은 테스트기능과 객체지향을 줄이는 심각한 문제다.
  • Spring은 애플리케이션과 프로젝트 도처에 일관적인 방법으로 설정을 다룸으로써 사용자정의 프라퍼티 파일 형식을 사용해야 하는 필요성을 제거할수 있다. 특정 클래스를 찾고 Javadoc이나 소스코드를 읽기 위한 마법같은 프라퍼티키나 시스템 프라퍼티를 걱정하지 말라. Spring을 사용하면 당신은 간단히 클래스의 자바빈즈 프라퍼티나 생성자 인자를 찾는다. Inversion of Control(이하 IoC)과 Dependency Injection(이하 DI)의 사용은 이러한 간단함을 달성하도록 도와준다.
  • Spring은 클래스보다 인터페이스를 사용하여 프로그래밍의 비용을 줄임으로써 좋은 프로그래밍 상황을 촉진할수 있다.
  • Spring은 가능한한 이 API의 최소한에만 의존하도록 빌드된 애플리케이션을 디자인한다. Spring애플리케이션내 대부분의 비지니스 객체는 Spring에 의존성을 가지지 않는다.
  • Spring을 사용하여 빌드된 애플리케이션은 단위 테스트하기 매우 쉽다.
  • Spring은 애플리케이션 구조의 결정보다 EJB구현 선택을 사용하도록 만들수 있다. 당신은 호출 코드의 영향없이 POJO나 로컬 EJB처럼 비지니스 인터페이스 구현을 선택할수 있다.
  • Spring은 EJB없이 많은 문제를 해결하도록 당신을 도와준다. Spring은 많은 애플리케이션을 위해 선호되는 EJB의 대안을 제공할수 있다. 만약 당신이 하나의 데이터베이스와 작업을 할 필요가 있다면 Spring은 EJEB컨테이너의 사용없이(JTA구현조차도 없는 상태에서) 선언적인 트랜잭션 관리를 달성하기 위한 AOP를 사용할수 있다.
  • Spring은 JDBC또는 TopLink, Hibernate또는 JDO구현과 같은 O/R맵핑을 사용하여 데이터접근을 위한 일관적인 프레임워크를 제공한다.
  • Spring은 많은 면에서 일관적이고 간단한 프로그래밍 모델을 제공한다. 이것은 이상적인 구조인 "glue"를 만든다. 당신은 JDBC, JMS, JavaMail, JNDI 그리고 많은 다른 중요한 API를 위해 Spring접근법내에 일관성을 보여줄수 있다.

Spring은 본질적으로 POJO를 사용하여 애플리케이션을 빌드하는 것을 가능하도록 하는 전용 기술이다. 이것은 개발자로부터 복잡한것을 숨기는 정교한 프레임워크를 요구하는 매력적인 목표이다.

게다가 Spring은 당신의 문제를 위한 가장 간단한 가능성있는 솔루션을 구현하도록 해준다.

Spring 은 무엇을 하는가?

Spring은 많은 기능을 제공한다. 그래서 나는 순서대로 빨리 중요한 기능을 리뷰할것이다.

Mission statement

첫번째로 Spring의 범위에 대해서 알아보자. 비록 Spring이 많은 부분을 담당한다고 하더라도, 우리는 이것이 위치하고 위치하지 않는 것에 대해서 분명한 것을 제시할것이다.

Spring의 가장 중요한 목표는 J2EE를 좀더 사용하기 쉽도록 하고 좋은 프로그래밍 형태를 촉진하는 것이다. 이것은 넓은 범위의 환경내 적용가능한 POJO기반의 프로그래밍 모델을 가능하게 함으로써 이것을 수행한다.

Spring은 외형적인 어떤것을 고치지 않는다. 게다가 당신은 Spring내에서 로깅, 커넥션 풀링, 분산 트랜잭션 코디네이터 패키지를 찾을수 없을것이다. 이런 모든것은 오픈소스 프로젝트(Commons Logging나 Commons DBCP와 같은)나 당신의 애플리케이션 서버에 의해서 제공된다. 이러한 이유로 우리는 O/R 맵핑 레이어를 제공하지 않는다. 여기엔 TopLink, Hibernate와 JDO와 같은 좋은 솔루션이 있다.

Spring은 존재하고 있는 기술들을 좀더 사용하기 쉽도록 하는데에도 목적이 있다. 예를 들면 비록 우리가 하위 레벨 트랜잭션 코디네이터의 비지니스내에서가 아니더라도 우리는 JTA나 다른 트랜잭션 전략위의 추상적 레이어를 제공한다.

Spring은 우리가 어떤 새로운것을 제공할수 있다는 느낌을 받지 않는다면 다른 오픈소스 프로젝트와 직접적으로 경쟁하지 않는다. 예를 들면 많은 개발자들처럼 우리는 Struts와 결코 행복하지 않고 MVC웹 프레임워크내 진보된 형태의 패지키을 가진다(Spring MVC채용이 빠르게 증가하고 있다 이것은 우리의 의도에 많은 이들이 동의를 하는것처럼 보인다.). 가벼운 IoC컨테이너와 AOP프레임워크같은 몇가지 점에서 Spring은 직접적인 경쟁을 가지지만 좀더 보편화된 솔루션은 없다.

Spring은 내부적인 일관성으로 부터 이익을 가진다. 모든 개발자는 같은 점에서 노래를 부른다. 우리는 다양한 범위에서 Inversion of Control같은 몇몇 중심이 되는 개념을 사용할수 있다.

Spring은 애플리케이션 서버 사이에 이식가능하다. 물론 이식가능성은 언제나 변한다. 하지만 우리는 개발자의 시각에서 플랫폼에 종속적이거나 표준이 아닌것 그리고 WebLogic, Tomcat, Resin, JBoss, WebSphere 그리고 다른 애플리케이션 서버에서 사용자를 지원하는 부분은 피한다. Spring은 침략적이지 않고 POJO이며 이식가능성의 희생없이 환경특유의 장점을 우리에게 얻도록 도와주는 접근법이다. Spring 1.2내 Weblogic의 향상된 트랜잭션 관리 기능의 경우에 이 사항아래 BEA특성의 API를 사용한다.

Inversion of control 컨테이너

Spring디자인의 핵심은 자바빈즈와 함께 작동하도록 디자인된 org.springframework.beans패키지이다. 이 패키지는 사용자에 의해서 직접적으로 사용되지는 않는다. 하지만 다른 수많은 기능을 지원하는 것처럼 제공한다.

추상화의 다음으로 높은 레이어는 "Bean Factory"이다. Spring bean factory은 객체가 이름에 의해서 가져올수 있고 객체들 사이에 관계를 관리할수 있는 일반적인 factory이다.

bean factory은 두가지의 객체 모델을 제공한다.

  • "싱클톤" : 이 경우에는 특정 이름으로 룩업을 통해 가져올수 있는 객체의 공유 인스턴스가 하나 있다. 이것은 디폴트이다 그리고 매우 자주 사용된다. 이것은 비상태유지 서비스 객체들에게 이상적이다.
  • "프로토타입 또는 싱글톤이 아닌것(non-singleton)" : 이 경우에는 각각의 검색이 독립적인 객체의 생성한다. 예를 들면 이것은 그들 자신의 구별되는 객체 참조를 가지기 위해 각각의 호출자를 사용할수 있다.

Spring컨테이너가 객체들 사이의 관계를 관리하기 때문에 이것은 관리되는 POJO와 핫스와핑(hot swapping)지원을 위해 투명한 풀링과 같은 서비스를 통해 필요한 곳에 값을 추가할수 있다. 컨테이너는 호출자에 대한 영향과 안전한 쓰레드의 특성의 손실없이 수행시간에 교환되기 위한 참조의 목표를 허락하는 간접적인 방법을 소개한다. DI의 아름다움중 하나는 API의 포함없이 가능한 명료함이라는 것이다.

org.springframework.beans.factory.BeanFactory은 간단한 인터페이스이기 때문에 이것은 다른 방법으로 구현될수 있다. BeanDefinitionReader인터페이스는 그들 스스로 BeanFactory구현으로부터 메터데이터 형태를 구분한다. 그래서 일반적인 BeanFactory구현은 Spring이 메터데이터의 다른 타입과 함께 사용될수 있다. 당신은 몇몇의 사용자만이 필요성을 알게 되더라도 당신 자신의 BeanFactory나 BeanDefinitionReader를 쉽게 구현할수 있다. 대부분 공통적으로 사용되는 BeanFactory정의는

  • XmlBeanFactory. 이것 파서는 간단하다. 직관적인 XML구조는 명명된 객체의 클래스와 프라퍼티를 정의한다. 우리는 좀더 쉽게 사용하도록 DTD를 제공한다.
  • ListableBeanFactoryImpl: 이것은 프라퍼티 파일내에 bean 정의들을 파싱하고 프로그램적으로 BeanFactory들을 생성하기 위한 능력을 제공한다.

각각의 bean 정의는 POJO(클래스명과 자바빈즈 초기화 프라퍼티에 의해 정의되는)나 FactoryBean이 될수 있다. FactoryBean인터페이스는 우회의 단계를 추가한다. 전형적으로 이것은 AOP나 다른 접근법을 사용해서 프록시 객체를 생성하는데 사용된다. 선언적인 트랜잭션 관리를 추가하는 프록시(이것은 개념적으로 EJB인터셉터와 유사하지만 실제로는 좀더 간단하다)가 그 예이다. 이것은 기본적으로 EJB인터셉션과 유사하다. 하지만 실제상황에서는 좀더 간단하고 강력하게 작동한다. .

BeanFactory는 상위로 부터 "상속" 정의처럼 계층적으로 관계한다. 이것은 전체 애플리케이션을 통해 컨트롤러 서블릿과 같은 개별적인 자원들이 그들 자신만의 독립적인 객체집합을 가지는 동안 공통적인 설정의 공유를 가능하게 한다.

자바빈즈의 사용을 위한 동기는 ServerSide에서 얻을수 있는 Expert One-on-One J2EE Design and Development의 4장을 설명하는 무료 free PDF(/articles/article.tss?l=RodJohnsonInterview) 에서 설명된다.

bean factory개념을 통해 Spring은 Inversion of Control컨테이너이다.(EJB컨테이너와 같은 무거운 컨테이너를 좋아하지 않는다. Spring BeanFactory는 한줄의 코드로 생성될수 있는 컨테이너이고 어떠한 특정 배치단계를 요구하지 않는다.)

Inversion of Control의 개념은 종종 할리우드 원리(나를 호출하지 말라. 내가 당신을 호출할것이다.)내에서 종종 표현된다. IoC는 프레임워크내부로 어떤것이 생성되도록 책임을 넘기고 애플리케이션 코드내에서 빠져나온다. EJB와 같은 전통적인 컨테이너 구조내에서 컴포넌트는 컨테이너에게 "객체 X가 있는 곳, 내가 나의 작업을 수행할 필요가 있는 것"이라고 말한다. IoC는 컨테이너에게 객체 X가 필요할때 런타임시 그것을 제공한다. 컨테이너는 메소드 시그너처에 기반해서 이 것을 생성하지 않고 가능한한 XML과 같은 설정 데이터를 사용한다.

나의 경험과 Spring사용자의 경험에서 이것은 IoC가 애플리케이션 코드로 가져다 주는 이익을 지나치게 강조하는것은 힘들다.

DI는 컨테이너 API(공동으로 사용되는 객체나 애플리케이션 객체 인스턴스로 설정값을 넣어주는것과 같은 의존성 삽입을 위해 사용되는 통상적인 자바 메소드들)에 명시적인 의존성을 제거하는 IoC의 형태이다. 설정이 EJB와 같은 전통적인 컨테이너 구조내 있는 동안 이러한 방법에 관여하는 곳에서 컴포넌트는 "객체 X가 있는곳이 내가 작업할 필요가 있는 것이다."라고 컨테이너에게 알릴것이다. DI를 사용하면 컨테이너는 객체 X에 의해서 필요한 컴포넌트를 찾고 실행시 이것을 제공한다. 컨테이너는 메소드 시그너처(자바빈즈 프라퍼티또는 생성자)와 XML과 같은 설정 데이터에 기반해서 이것을 찾는다.

DI의 두가지 방식은 Setter Injection(자바빈즈 setter메소드에 의한)과 Constructor Injection(생성자메소드의 인자를 통한)이다. Spring은 두가지 방식에 대한 정교한 지원을 제공한다. 또한 객체를 설정할때 두가지를 섞어서 사용할수 있도록 한다.

DI의 모든 형태를 지원하는 것만큼 Spring은 콜백이벤트의 범위와 필요할때 전통적인 룩업을 위한 API 제공한다. 어쨌든 우리는 일반적으로는 순수한 DI를 추천한다.

DI는 여러가지 중요한 이득을 가진다. 예를 들면

  • 컴포넌트는 런타임시 협력자(collaborators)를 룩업할 필요가 없다. 그들은 쓰고 관리하는데 좀더 간단하다. Spring의 IoC버전내에서 컴포넌트는 자바빈즈 setter메소드를 표시하거나 생성자 인자를 통해 다른 컴포넌트의 의존성을 표현한다. EJB와 같은 부분은 개발자가 코드를 써야만 하는 JNDI룩업일것이다.
  • 같은 이유로 애플리케이션 코드는 테스트하기가 좀더 쉽다. 자바빈즈 프라퍼티는 간단하고 핵심자바이며 테스트하기 쉽다. 객체를 생성하고 관련 프라퍼티를 셋팅하는 스스로 포함된 JUnit테스트 메소드를 쓴다.
  • 좋은 IoC구현은 강력한 타이핑을 유지한다. 만약 당신이 협력자(collaborators)를 룩업하기 위한 일반적인 factory을 사용할 필요가 있다면 당신은 기대하는 타입으로 결과를 변환할 것이다. 이것은 중요한 문제가 아니다. 하지만 이것은 세련되지 않았다. IoC와 함께 당신은 당신의 코드에 강력하게 쓰여진 의존성을 표시하고 프레임워크는 타입변환을 책임질수 있다. 이것은 프레임워크가 애플리케이션을 설정할때 에러처럼 나타날수 있는 타입 미스매치(mismatch)를 의미한다. 당신은 당신의 코드에서 클래스 형변환 예외에 대한 걱정을 할필요가 없다.
  • 의존성은 명시적이다. 예를 들면 만약 애플리케이션 클래스가 프라퍼티 파일을 로드하거나 데이터베이스에 접근한다면 환경적인 가정은 코드를 읽지 않고 명백하지는 않을것이다(테스트를 복잡하게 하고 배치 유연서을 감소시킨다.) DI접근법으로 의존성은 명시적이고 생성자나 자바빈즈 프라퍼티내에서 분명하다.
  • 대부분의 비지니스 객체는 IoC컨테이너 API에 의존하지 않는다. 이것은 기존 코드를 사용하기 쉽도록 만들고 IoC컨테이너 내부나 외부의 객체를 사용하기 쉽도록 만든다. 예를 들면 Spring사용자는 종종 Spring bean처럼 Jakarta Commons DBCP데이터소스를 설정한다. 여기엔 이것을 하기 위해서 사용자정의 코드를 쓸 필요가 없다. 우리는 IoC컨테이너가 침략적(이것을 사용해서 API에 의존적인 것을 당신의 코드에 넣는)이지 않다고 말한다. 대부분의 POJO는 Spring bean factory에서 컴포넌트가 될수 있다. 다중 인자를 가진 생성자를 가진 자바빈즈나 객체들은 특별히 잘 작동한다. 하지만 Spring은 정적인 factory메소드나 IoC컨테이너에 의해 관리되는 다른 객체들 위의 메소드로 부터 객체를 인스턴스화하기 위한 유일한 지원을 제공한다.

이 마지막 이익은 강조할만하다. DI는 컨테이너의 애플리케이션 코드의 의존성 최소화라는 점에서 EJB와 같은 전통적인 컨테이너 구조와는 다르다. 이것은 당신의 비지니스 객체가 다른 DI프레임워크내에서 또는 어떤 프레임워크 밖에서 어떠한 코드변경없이 잠재적으로 실행가능하다는것을 의미한다.

나의 경험과 Spring사용자의 경험에서 이것은 IoC그리고 특별히 DI가 애플리케이션 코드로 가져다 주는 이익을 지나치게 강조하는것은 힘들다.

DI는 J2EE커뮤니티에서 최초의 일이지만 새로운 개념이 아니다. 대안적인 DI컨테이너(PicoContainer 그리고 HiveMind)가 있다. PicoContainer는 가볍고 자바빈즈 프라퍼티보다 생성자를 통해 의존성의 표현을 강조한다. 이것은 자바코드 밖에서 Spring내에서 비교적 기능을 제한하는 메타데이터를 사용하지 않는다. HiveMind는 비록 Spring프로젝트의 포괄적인 범위나 사용자 커뮤니티의 부족에도 불구하고 Spring과 개념적으로 좀더 유사(심지어는 IoC를 사용하는것 또한)하다. EJB3.0은 기본적인 DI능력을 제공한다.

Spring BeanFactory는 매우 가볍다. 사용자는 단독으로 작동하는 스윙 애플리케이션만큼 애플릿내에서 그것들을 성공적으로 사용한다(그들은 EJB컨테이너내에서도 잘 작동한다.). 특별한 배치단계와 발견될만한 시작시간이 없다. 컨테이너를 애플리케이션의 어느 티어에서 인스턴스화 할수 있도록 구체화하는 능력은 매우 가치있다.

Spring BeanFactory개념은 Spring도처에서 사용된다. Spring이 내부적으로 일관적일수 있는 핵심적인 이유이다. Spring은 또한 전체 기능의 프레임워크 도처에 기본적인 개념으로 IoC를 사용하는 면에서 IoC컨테이너 사이에서는 유일하다.

애플리케이션 개발자를 위해 가장 중요한 것은 하나 이상의 BeanFactory가 잘 정의된 비지니스 객체의 레이어를 제공하는 것이다. 이것은 유사하지만 로컬 세션빈즈의 레이어보다는 훨씬 더 간단하다. EJB와는 다르게 레이어내의 객체는 서로 밀접한 관계일수 있고 그들의 관계는 자신의 factory에 의해서 관리된다. 비지니스 객체의 잘 정의된 레이어는 성공적인 구조를 위해서 매우 중요하다.

Spring ApplicationContext는 다음의 사항들을 지원하는 BeanFactory의 하위 인터페이스이다.

  • 메시지 룩업, 국제화 지원
  • 이벤트 기법, 이벤트를 통지하기 위해 표시되거나 등록하는 애플리케이션 객체를 허락한다.
  • 컨테이너 행위를 커스터마이징하는 특정 애플리케이션에 특정적이거나이나 일반적인 bean 정의의 자동 인식
  • 이식가능한 파일과 자원 접근

XmlBeanFactory 예제

Spring사용자는 대개 XML "bean definition"파일내에 그들의 애플리케이션을 설정한다. Spring XML bean 정의 문서의 가장 상위는 <bean> 요소이다. <bean> 요소는 하나 이상의 <bean>정의를 포함한다. 우리는 대개 각각의 bean정의의 클래스와 프라퍼티를 명시한다. 우리는 우리의 코드내에 이 bean을 사용할 이름이 될 id를 명시해야만 한다.

J2EE애플리케이션내에서 공통적으로 보여지는 관계를 가진 3개의 애플리케이션 객체를 설정한 간단한 예제를 보자.

  • J2EE 데이터소스
  • 데이터소스를 사용하는 DAO
  • 이 작업의 과정내의 DAO를 사용하는 비지니스 객체

 

다음의 예제에서 우리는 Jakarta Commons DBCP프로젝트로 부터 BasicDataSource를 사용한다(C3PO프로젝트의 ComboPooledDataSource또한 굉장히 멋진 옵션이다.). 다른 많은 클래스들처럼 BasicDataSource는 Spring bean factory내에서 자바빈즈 스타일의 설정을 제공하는것처럼 쉽게 사용될수 있다. shutdown시 호출될 필요가 있는 close메소드는 어떤 Spring인터페이스를 구현하기 위한 BasicDataSource의 필요성을 피하기 위해 spring의 "destroy-method"속성을 통해 등록될수 있다.

역자주 : Spring XML설정파일에서 destroy-method의 값을 대체하는 방법은 DisposableBean인터페이스를 구현해서 사용하면 된다. Spring의 개념에 좀더 들어가면 나오겠지만 destroy-method에 반대되는 값은 init-method이고 이 값은 InitializingBean인터페이스를 구현해서 사용하면 된다.

 

<beans>
  <bean id="myDataSource"  class="org.apache.commons.dbcp.BasicDataSource"  destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/mydb" />
    <property name="username" value="someone" />
  </bean>

 

 

우리가 관심을 가지는 BasicDataSource의 모든 프라퍼티는 문자열이다. 그래서 우리는 value 속성과 함께 그 값을 명시한다(이것은 Spring 1.2에서 새로 추가된 사항이다. 이것은 기존에 <value>요소를 사용하던 방식에 대한 편리한 대안으로 사용된다.).

역자주 : 기존에 1.2버전 이전에는 다음의 소스코드처럼 value라는 하위 xml요소를 둬서 셋팅했다. 물론 이와같은 방법도 계속적으로 사용가능하다.

 

<beans>

  <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
    <property name="url"><value>jdbc:mysql://localhost:3306/mydb</value></property>
    <property name="username"><value>root</value></property>
  </bean>

Spring은 문자열표현을 필요한 다른 어떠한 타입으로 변환하기 위한 표준적인 자바빈즈 PropertyEditor기법을 사용한다.

 

지금 우리는 데이터소스에 대한 bean 참조를 가지는 DAO를 정의한다. bean들 사이의 관계는 "ref"속성이나 <ref>요소를 사용해서 명시한다.

 

  <bean id="exampleDataAccessObject" class="example.ExampleDataAccessObject">
    <property name="dataSource" ref="myDataSource" />
  </bean>

 

 

비지니스 객체는 DAO에 대한 참조와 int형 프라퍼티를 가진다. 이 경우에 나는 Spring 1.2의 이전버전에 친숙한 사용자를 위해 하위요소 문법을 사용했다.

 

<bean id="exampleBusinessObject" class="example.ExampleBusinessObject">
    <property name="dataAccessObject"><ref bean="exampleDataAccessObject"/></property>
    <property name="exampleParam"><value>10</value></property>
  </bean>

</beans>

 

 

객체간의 관계는 예제처럼 설정내에 명시적으로 셋팅한다. 우리는 대부분의 경우에 좋은 것이 되기 위해 이것을 고려한다. 어쨌든 Spring은 bean사이에 의존성을 발견하는 곳에 우리가 "autowire" 지원이라고 부르는것을 제공한다. PicoContainer과 같은 이 제한은 만약 특정 타입의 다중 bean들이 있다면 해석되어야만 하는 타입의 인스턴스 의존성을 해결하는것은 불가능하다. 긍정적인 면에서 만족하지 않는 의존성은 factory가 초기화될때 잡힐수 있다.(Spring은 명시적 설정을 위해 옵션적인 의존성 체크를 제공한다.)

우리는 위 예제에서 설명된 autowire기능을 사용할수 있다. 만약 우리가 명시적인 관계를 작성하길 원하지 않는다면.

 

<bean id="exampleBusinessObject" class="example.ExampleBusinessObject" autowire="byType">
    <property name="exampleParam" value="10" />
 </bean>

 

 

이 사용법으로 Spring은 exampleBusinessObject의 데이터소스 프라퍼티가 현재의 BeanFactory내에 발견되는 데이터소스의 구현이 되기 위해 셋팅되어야만 하는것이라는것을 해결할것이다. 만약에 현재의 BeanFactory내에 요구되는 타입의 bean이 없거나 하나보다 많다면 에러이다. 우리는 여전히 레퍼런스가 아닌것처럼 exampleParam프라퍼티를 셋팅할 필요가 있다.

Autowire지원은 설정양을 줄이는 장점을 가진다. 이것은 리플렉션(reflection)을 사용해서 애플리케이션 구조에 대한 것을 알수 있게 해준다는것을 의미한다. 그래서 만약 당신이 자바빈즈 프라퍼티의 추가적인 생성자 인자를 추가한다면 이것은 설정변경이 필요없이 성공적으로 활성화될것이다. autowiring의 교환은 주의깊게 평가될 필요가 있다.

자바코드로부터 관계를 구체화하는것은 그것을 하드코딩하는것보다 막대한 이익을 가진다. 이것은 자바코드내 어떤 라인의 변경도 없이 XML파일을 변경하는것으로 가능하다. 예를 들면 우리는 대안적인 커넥션풀이나 테스트 데이터소스를 사용하기 위해 다른 bean클래스를 참조하기 위한 myDataSource bean정의를 간단히 변경할수 있다. 우리는 대안적인 하나의 XML내에서 애플리케이션 서버로부터 데이터소스를 얻기 위해 Spring JNDI위치의 FactoryBean을 사용할수 있다. 자바코드나 다른 bean정의에는 어떠한 영향도 없을것이다.

 

<bean id="myDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="jdbc/myDataSource" />
  </bean>

 

 

지금 비지니스 객체의 예제를 위한 자바코드를 보자. 밑의 코드리스트에서 Spring의존적인것들은 없다. EJB컨테이너와는 달리 Spring BeanFactory는 침략적이지 않다. 당신은 애플리케이션 객체로 코드를 인식하도록 할 필요는 없다.

 

public class ExampleBusinessObject implements MyBusinessObject {

  private ExampleDataAccessObject dao;
  private int exampleParam;

  public void setDataAccessObject(ExampleDataAccessObject dao) {
    this.dao = dao;
  }

  public void setExampleParam(int exampleParam) {
    this.exampleParam = exampleParam;
  }

  public void myBusinessMethod() {
    // do stuff using dao
  }
}

 

 

프라퍼티 setter는 bean정의 문서내에서 XML참조에 대응된다는 것에 주의하라. 객체가 사용되기 전에 Spring에 의해 호출된다.

그러한 애플리케이션 bean은 Spring에 의존할 필요가 없다. 그들은 어떠한 Spring인터페이스를 구현하거나 Spring클래스를 확장할 필요가 없다. 그들은 단지 자바빈즈 명명 형태를 관찰할 필요는 있다. Spring애플리케이션 컨텍스트 밖에서 재사용은 쉽다. 디폴트 생성자를 사용해서 그것을 인스턴스화하고 그것의 프라퍼티를 setDataSource() 와 setExampleParam() 호출을 통해 수동으로 셋팅한다. 당신이 인자없는 생성자를 가진만큼 당신은 코드내에 한줄로 프로그램적인 생성작업을 지원하길 원한다면 다중 프라퍼티를 가져오는 다른 생성자를 정의하는데 자유롭다.

자바빈즈 프라퍼티는 함께 작동할 비지니스 인터페이스 호출자위에 선언되지 않는다. 그들은 상세하게 구현한다. 우리는 연결된 객체나 호출 코드에 영향없이 다른 bean프라퍼티를 가지는 다른 구현클래스와 쉽게 "플러그인" 할수 있다.

물론 Spring XML bean factory는 여기서 서술된 것보다 더 많은 능력을 가지고 있다. 하지만 이것은 당신에게 기본적인 접근법에 대한 것만 제시할것이다. 간단한 프라퍼티들과 당신이 자바빈즈 PropertyEditor를 가지기 위한 프라퍼티만큼 Spring은 자동적으로 리스트, 맵 그리고 java.util.Properties를 다룰것이다. 다른 향상된 컨테이너 능력은 다음을 포함한다.

  • (내부빈)Inner bean, 가장 상위 레벨의 범위에서 보여지지 않는 익명 bean정의를 포함하는 프라퍼티 요소내
  • 후 프로세서(Post processors) : 컨테이너 행위를 커스터마이징 하는 특별한 bean정의
  • 메소드 삽입(Method Injection), 컨테이너내 IoC의 형태는 추상메소드나 의존성을 삽입하기 위한 견고한 메소드를 오버라이딩 하는 것을 구현한다. 이것은 Setter Injection이나 Constructor Injection보다는 잘 사용되지 않는 DI의 형태이다. 어쨌든 이것은 각각의 호출을 위해 새로운 객체 인스턴스를 찾을때나 시간을 넘어 다양한 설정을 허락하고자 할때 명시적인 컨테이너 의존성을 피하기 위해 유용하다.

bean factory와 애플리케이션 컨텍스트는 언제나 J2EE서버나 웹컨테이너에 의해 정의된 범위내에 속한다.

  • 서블릿 컨텍스트. Spring MVC프레임워크내에서 애플리케이션 컨텍스트는 공통객체를 포함하는 각각의 웹애플리케이션을 위해 정의된다. Spring은 Spring MVC프레임워크에 의존하는 것 없이 리스너나 서블릿을 통해 그러한 컨텍스트를 인스턴스화하는 기능을 제공한다. 그래서 이것은 Struts, WebWork 또는 다른 웹프레임워크내에서도 사용이 될수 있다.
  • 서블릿 : Spring MVC프레임워크내의 각각의 컨트롤러 서블릿은 가장 상위 애플리케이션에서 파생된 자신만의 애플리케이션 컨텍스트를 가진다. 이것은 또한 Struts나 다른 MVC프레임워크와 함께 완성하기가 쉽다.
  • EJB : Spring은 EJB jar파일내의 XML문서로 부터 로드된 BeanFactory를 제공하고 EJB제작을 간단하게 하는 EJB를 위한 편리한 슈퍼클래스를 제공한다.

J2EE스펙에 의해 제공되는 사항은 일반적으로 bean factory를 시작하기 위해 싱글톤을 사용할 필요를 제거한다.

어쨌든 이것은 우리가 바란다면 BeanFactory를 프로그램으로 인스턴스화하는것은 자명하다. 예를 들면 우리는 다음 2줄의 코드로 위에서 정의된 bean factory를 생성할수 있고 비지니스 객체에 대한 참조를 얻을수 있다.

 

XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("myFile.xml", getClass()));
MyBusinessObject mbo = (MyBusinessObjectbf.getBean("exampleBusinessObject");

 

 

역자 주 : 기존엔 다음과 같은 방식을 사용했다. 사실 큰 차이가 있는건 아니지만 다양한 방법으로 이제 설정이 가능하다는 예이다.

 

InputStream is = getClass().getResourceAsStream("myFile.xml");
XmlBeanFactory bf = new XmlBeanFactory(is);
MyBusinessObject mbo = (MyBusinessObjectbf.getBean("exampleBusinessObject");

 

 

이 코드는 애플리케이션 서버 밖에서 작동할것이다. 이것은 Spring IoC컨테이너가 순수 자바인것처럼 J2EE에 의존하지 않는다. Spring Rich프로젝트(Spring을 사용해서 스윙 애플리케이션의 개발을 단순화하기 위한 프레임워크)는 Spring의 통합테스팅 기능을 사용해서 J2EE환경밖에서 사용될수 있는 방법을 그린다. 이 기능은 이 글 나중에 얘기된다. DI와 관련된 기능은 J2EE또는 서버측 환경에 너무 일반적이고 가치있다.

JDBC 추상화 그리고 데이터접근 예외 구조

데이터접근은 Spring을 부각시키는데 다른 영역이다.

JDBC는 데이터베이스 참조로 부터 상당히 좋은 추상화를 제공한다. 하지만 사용하기 위해서 지겨운 API이다. 몇몇 문제는 다음과 같다.

  • ResultSets, Statements 그리고 (가장 중요한)Connections 보장하기 위해 장황한 에러 핸들링을 위한 필요가 사용 후에 닫힌다. 이것은 JDBC의 정확한 사용이 많은 코드내에서 빨리 결과를 생성한다. 이것은 또한 에러들의 공통적인 원인이다. Connection누설은 애플리케이션을 빨리 다운시켜버릴수 있다.
  • 비교적 정보의 가치가 없는 SQLException. JDBC는 예외구조를 제공하지 않지만 모든 에러에 대해 응답으로 SQLException을 던진다. 정말로 나쁘게 되는것을 찾는건 예를 들면 SQLState와 에러코드를 포함하는 데드락이나 적합하지 않은 SQL의 문제인가.? 그러한 값들의 의미는 데이터베이스마다 다양하다.

Spring은 두가지 방법으로 이러한 문제를 담당한다.

  • API를 제공함으로써 지루하고 에러를 발생시키는 경향이 있는 예외 핸들링을 애플리케이션 코드에서 프레임워크로 이동시킨다. 프레임워크는 모든 예외 핸들링을 처리한다. 애플리케이션 코드는 SQL문과 결과를 추출하는데 집중을 할수 있다.
  • 당신의 애플리케이션 코드를 위한 의미있는 예외 구조를 제공함으로써 SQLException을 대신하여 작동한다. Spring이 데이터베이스로부터 Connection을 처음으로 얻었을 때 이것은 데이터베이스를 확인하기 위해 메터데이터를 시험한다. 이것은 org.springframework.dao.DataAccessException으로 부터 유래된 자신만의 구조로 SQLException을 올바른 예외로 맵핑시키기 위해 이러한 정보를 사용한다. 게다가 당신의 코드는 의미있는 예외와 함께 작동을 할수 있고 선호하는 SQLState나 에러코드에 대해서 걱정할 필요가 없다. Spring의 데이터접근 예외는 JDBC에 특성화되어있지 않다. 그래서 당신의 DAO들은 그들이 던질 예외들 때문에 JDBC에 묶일 필요가 없다.

다음의 UML클래스 다이어그램은 이 데이터접근 예외 구조의 일부를 설명하고 복잡함을 표시한다. 여기에 보여진 예외중 어느것도 JDBC에 특성화된것이 없다. 이러한 예외의 몇몇 JDBC기반 하위 클래스도 있지만 호출하는 코드는 JDBC의 의존성으로 부터 떨어져 대개 추상화된다. 만약 당신이 당신의 퍼시스턴스 전략을 숨기기 위해 진실로 API에 관용적인 DAO인터페이스를 사용하고자 한다면 필수이다.

 

Spring은 두가지 레벨의 JDBC API를 제공한다. 첫번째는 org.springframework.jdbc.core패키지에 있고 애플리케이션 코드에서 부터 프레임워크내부로 컨트롤을 이동시키기 위해 콜백을 사용하고 에러핸들링과 connection취득 그리고 릴리즈를 한다. 이것은 Inversion of Control의 다른 타입이지만 설정 관리를 위해 사용될수 있는 동등한 가치를 가진다.

Spring은 JDO(PersistenceManager를 획득하고 버리는), JTA를 이용한 트랜잭션 관리 그리고 JNDI처럼 자원을 획득하고 없애는 특별한 단계를 포함한 다양한 API를 할당하기 위해 유사한 콜백 접근법을 사용한다. 콜백과 같은 것을 수행하는 Spring 클래스는 템플릿들을 호출한다.

예를 들면, Spring JdbcTemplate객체는 SQL쿼리를 수행하고 다음처럼 리스트로 결과를 저장하기 위해 사용될수 있다.

 

JdbcTemplate template = new JdbcTemplate(dataSource);
List names = template.query("SELECT USER.NAME FROM USER",
  new RowMapper() {
    public Object mapRow(ResultSet rs, int rowNumthrows SQLException;
      return rs.getString(1);
    }
  });

 

 

mapRow콜백 메소드는 ResultSet의 각각의 row를 위해 호출될것이다.

역자 주 : 기존엔 mapRow메소드 대신에 processRow메소드를 사용했다. 소스의 형태는 다음과 같다.

 

JdbcTemplate template = new JdbcTemplate(dataSource);
final List names = new LinkedList();
template.query("SELECT USER.NAME FROM USER",
  new RowCallbackHandler() {
    public void processRow(ResultSet rsthrows SQLException {
      names.add(rs.getString(1));
    }
  });

 

 

콜백내 애플리케이션 코드는 SQLException을 던지는데 자유롭다. Spring은 어떤 예외를 잡을것이고 자신의 구조내에서 그것들을 다시 던진다. 애플리케이션 개발자는 예외를 선택할수 있다.

JdbcTemplate은 prepared statement와 배치형태의 업데이트를 포함한 다른 시나리오를 지원하기 위해 많은 메소드를 제공한다. SQL함수들을 수행하는 것과 같은 간단한 작업은 다음처럼 콜백없이도 달성될수 있다. 예제는 바인드변수의 사용을 설명한다.

 

int youngUserCount = template.queryForInt("SELECT COUNT(0) FROM USER WHERE USER.AGE < ?",
  new Object[] { new Integer(25) });

번호 제목 글쓴이 날짜 조회 수
공지 (확인전) [2021.03.12] Eclipse에서 Spring Boot로 JSP사용하기(Gradle) 황제낙엽 2023.12.23 0
공지 [작성중/인프런] 스프링부트 시큐리티 & JWT 강의 황제낙엽 2023.12.20 6
23 Spring프레임워크 소개문서 (2) 황제낙엽 2007.03.22 123
» Spring프레임워크 소개문서 (1) 황제낙엽 2007.03.22 107
21 Cugain의 샘플프로젝트 jpetstore 분석기 - (1) jpetstore 설치 file 황제낙엽 2007.02.22 123
20 Cugain의 샘플프로젝트 jpetstore 분석기 - (7) PetStoreImpl.java 황제낙엽 2007.05.24 51
19 Cugain의 샘플프로젝트 jpetstore 분석기 - (6) petstore-servlet.xml 분석 황제낙엽 2007.04.27 19
18 Cugain의 샘플프로젝트 jpetstore 분석기 - (5) applicationContext.xml 분석 황제낙엽 2007.04.21 232
17 Cugain의 샘플프로젝트 jpetstore 분석기 - (4) dataAccessContext-jta.xml 분석 황제낙엽 2007.04.21 27
16 Cugain의 샘플프로젝트 jpetstore 분석기 - (3) dataAccessContext-local.xml 분석 황제낙엽 2007.04.21 40
15 Cugain의 샘플프로젝트 jpetstore 분석기 - (2) web.xml 분석 황제낙엽 2007.03.20 92
14 IoC (Inversion of Control) 컨테이너에 대한 정리 황제낙엽 2007.02.21 50
13 자바지기 1차 오픈 소스 스터디 문서모음 file 황제낙엽 2007.01.30 46
12 Spring 프레임워크를 이용한 효율적인 개발 전략 1차 황제낙엽 2007.01.30 47
11 Spring framework jpetstore 샘플 분석기 - (6) jpetstore 예제로 살펴보는 Spring MVC와 iBatis 연동 황제낙엽 2007.01.18 48
10 Spring framework jpetstore 샘플 분석기 - (5) jpetstore 에서의 InternalResourceViewResolver 황제낙엽 2007.01.18 17
9 Spring framework jpetstore 샘플 분석기 - (4) jpetstore 에서의 HandlerMapping 황제낙엽 2007.01.18 36
8 Spring framework jpetstore 샘플 분석기 - (3) jpetstore 에서의 Spring MVC 설정 황제낙엽 2007.01.18 13
7 Spring framework jpetstore 샘플 분석기 - (2) jpetstore 에서의 Spring 초기 설정과 IoC 황제낙엽 2007.01.18 18
6 Spring framework jpetstore 샘플 분석기 - (1) jpetstore 설치하기 황제낙엽 2007.01.18 30
5 Spring WebFlow Introduction (웹개발을 직관적으로) 황제낙엽 2006.12.09 555
4 IoC(Inversion of Control)란 무엇인가? 황제낙엽 2006.12.09 93