[Info]Tags categorized posts and contents patterns..

[AJAX] Ajax Code E xamples.. [Book] About the book.. [CSS] CSS Code E xamples.. [DB] Sql Code E xamples.. [DEV] All development stor...

2016년 4월 12일 화요일

[JAVA]1장 스프링 프레임워크 소개 #2..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

이 포스팅은 다음의 스프링소스 라이센스를 따릅니다.

이 문서는 개인적인 목적이나 배포하기 위해서 복사할 수 있다. 출력물이든 디지털 문서든 각 복사본에 어떤 비용도 청구할 수 없고 모든 복사본에는 이 카피라이트 문구가 있어야 한다.

1.3 사용 시나리오
앞에서 설정한 블락을 만드는 것은 많은 시나리오에서 스프링이 논리적인 선택을 하도록 한다. 여기서 많은 시나리오는 애플릿부터 스프링의 트랜잭션 관리 기능과 웹 프레임워크 통합을 사용하는 완전한 엔터프라이즈 어플리케이션까지를 포함한다.

대표적인 완전한 형태의 스프링 웹 어플리케이션
대표적인 완전한 형태의 스프링 웹 어플리케이션

스프링의 선언적 트랜잭션 관리 기능은 웹 어플리케이션이 EJB 컨테이너가 관리하는 트랜잭션처럼 완전한 트랙잭션 기능을 가지게 한다. 모든 커스텀 비즈니스 로직은 간단한 POJO로 구현할 수 있고 스프링의 IoC 컨테이너로 관리할 수 있다. 추가적인 서비스는 이메일을 보내는 기능을 지원하고 어디서 유효성 확인 규칙을 실행할 것인지 선택하는 웹 계층과는 독립적인 유효성 확인에 대한 지원을 포함한다. 스프링의 ORM 지원은 JPA, Hibernate, JDO, iBatis와 통합되었다. 예를 들면 하이버네이트를 사용할 때 이미 존재하는 매핑 파일과 표준 하이버네이트 SessionFactory 설정을 계속 사용할 수 있다. 폼(Form) 컨트롤러는 도메인 모델에 대한 값으로 HTTP 파라미터를 전달하는 ActionForms나 다른 클래스에 대한 필요성을 제거함으로써 도메인 모델과 웹 계층을 자연스럽게 통합한다.

서드파티 웹 프레임워크를 사용하는 스프링 미들-티어
서드파티 웹 프레임워크를 사용하는 스프링 미들-티어

종종 다른 프레임워크로 완전히 전환하는 것이 어려울 수 있다. 스프링 프레임워크는 스프링 프레임워크안에서만 모든 일을 하도록 강제하지 않는다. 스프링 프레임워크는 스프링 프레임워크만 쓰던가 아예 쓰지 않던가 해야 하는 솔루션이 아니다. 이미 만들어진 프레임워크가 WebWork, Struts, Tapestry나 다른 UI 프레임워크로 만들어졌더라도 스프링의 트랜잭션 기능을 사용하는 스프링 기반의 미들-티어와 통합할 수 있다. 간단하게 ApplicationContext를 사용하는 비즈니스 로직을 연결하고 웹 계층과 통합하기 위해 WebApplicationContext 를 사용하면 된다.

원격 사용 시나리오
원격 사용 시나리오

이미 존재하는 코드에 웹서비스로 접근할 필요가 있으면 스프링의 Hessian-, Burlap-, Rmi-나 JaxRpcProxyFactory 클래스를 사용할 수 있다. 존재하는 어플리케이션으로의 원격접근을 허용하는 것은 어렵지 않다.

EJB - 존재하는 POJO의 랩핑(Wrapping)
EJB - 존재하는 POJO의 랩핑(Wrapping)

또 한, 스프링 프레임워크는 엔터프라이즈 자바빈, 존재하는 POJO의 재사용 허용, 선언적인 보안이 필요한 확장성 있고 안전한(fail-safe) 웹 어플리케이션에서 사용하는 무상태 세션빈을 감싸기 위해 접근과 추상화 계층을 제공한다.

1.3.1 의존성 관리와 작명 관례
의존성 관리과 의존성 주입은 다르다. 스프링의 좋은 기능(의존성 주입 같은)을 어플리케이션에서 사용하려면 필요한 모든 라이브러리(jar 파일)를 조립하고 런타임시에, 혹은 가능하다면 컴파일할 클래스패스에 둘 필요가 있다. 이러한 의존성은 주입되는 가상 컴포넌트가 아니라 (전통적으로) 파일시스템에 존재하는 물리적 리소스이다. 의존성 관리의 프로세스는 이러한 리소스를 필요한 위치에 두고 저장하고 클래스 패스에 추가하는 작업이 포함한다. 의존성은 직접적일 수도(예를 들어 런타임시에 스프링에 의존하는 어플리케이션) 간적접일 수도(예를 들어 commons-pool기반의 commons-dbcp에 의존하는 어플리케이션) 있다. 간적인 의존성은 보통 과도기적이라고 부르기도 하는데 이러한 의존성은 구별하고 관리하기가 몹시 어렵다.

스프링을 사용할 계획이라면 필요한 스프링 일부를 포함하는 jar 라이브러리의 복사본이 필요하다. 스프링은 의존성이 최대한 분리되도록 모듈이 패키징되어 있으므로 이 작업을 쉽게 할 수 있다. 예를 들어 웹 어플리케이션을 작성할 것이 아니라면 스프링-웹 모듈은 필요 없다. 이 가이드의 스프링 라이브러리 모듈을 참조하기 위해 spring-*나 spring-*.jar같은 짧은 작명 컨벤션을 사용한다. *은 모듈의 약칭을 의미한다. (예를 들어 spring-core, spring-webmvc, spring-jms등이다.) 실제 jar 파일명은 이 형식일 수도 있고(아래에서 볼 것이다) 아닐 수도 있으며 보통 파일명에 버전번호가 포함되어 있다.(예를 들면 spring-core-3.0.0.RELEASE.jar 와 같은 방식이다.)

보통 스프링은 결과물(Artifact)을 다음 네 곳에 배포한다.

  • 커뮤니티 다운로드 사이트 http://www.springsource.org/downloads/community 다운로드받기 쉽도록 zip 파일로 묶인 모든 스프링 jar파일이 있다. 3.0 버전부터 이곳의 jar파일명은 org.springframework.*-<version>.jar 의 형식을 따른다.
  • 메이븐 센트럴(Maven Central). 메이븐 센트럴은 메이븐의 기본 저장소이므로 사용하기 위해서 특별한 설정을 할 필요는 없다. 스프링이 의존하는 공통 라이브러리 중 다수는 메이븐 센트럴에서 이용할 수 있고 스프링 커뮤니티의 많은 부분은 의존성 관리에 메이븐을 사용하므로 편리하다. 메이븐 센트럴의 jar 파일명은 spring-*-<version>.jar의 형식을 따르고 메이븐 groupId는 org.springframework이다.
  • SpringSource에서 운영하는 Enterprise Bundle Repository (EBR). EBR는 스프링에 통합하는 모든 라이브러리를 제공한다. 모든 스프링 jar와 의존성 라이브러리를 포함해서 그 외 스프링으로 어플리케이션을 개발할 때 사용하는 공통 라이브러리에 대한 메이븐 저장소와 아이비(Iby) 저장소를 모두 이용할 수 있다. 릴리즈 버전과 마일스톤을 포함해서 개발 스냅샷까지 이곳에 배포된다. jar 파일명은 커뮤니티 다운로드와 같은 형식(org.springframework.*-<version>.jar )을 사용하고 외부 라이브러리(스프링소스가 만들지 않은)는 com.springsource 접두사가 있는 긴 형식이다. 더 자세한 정보는 FAQ를 참고해라.
  • 개발 스냅샵과 마일스톤 릴리즈를 위해 아마존 S2에서 운영되는 공개 메이븐 저장소를 사용한다.(최종 릴리즈의 복사본도 배포된다.) jar 파일명은 메이븐 센트럴과 같은 형식이므로 메이븐 센트럴에 배포된 다른 라이브러리와 함께 스프링의 개발 버전을 사용할 때 유용하다.

그래서 어떻게 의존성을 관리할 것인지를 먼저 결정해야 한다. 대부분은 메이븐이나 아이비같은 자동화된 시스템을 사용한다. 하지만 수동으로 모든 jar를 다운받아서 관리할 수도 있다. 메이븐이나 아이비로 스프링을 다운받으려면 어디서 다운받을 지를 결정해야 한다. 보통 OSGi를 고려한다면 Hibernate나 Freemarker같은 스프링 의존성의 OSGi 호환 결과물이 제공되는 EBR을 사용한다. OSGi를 쓸 계획이 없다면 저장소마다 장단점이 있지만, 어느 곳을 사용하던 큰 문제는 없다. 대신 섞어서 사용하지는 마라. EBR은 메이븐 센트럴과는 작명 관례를 사용하므로 특히 주의해야 한다.

Table 1.1. 메이븐 센트럴과 스프링소스 EBR 저장소의 비교

기능Maven CentralEBR
OSGi 호환명확하지 않음호환
Artifact의 수모든 종류로 수천 가지스프링 통합과 관련된 것들로 수백 가지
작명 관례의 일관성일관성 없음일관성 있음
GroupId의 작명 관례다양함. 새로운 artifact는 종종 도메인 명을 사용한다. 예를 들면 org.slf4j. 오래된 것들은 그냥 artifact명을 사용한다. 예를 들면 log4j출처나 메인 패키지 루트의 도메인명. 예를 들어 org.springframework
ArtifactId의 작명 관례다양함. 보통 프로젝트나 모듈명으로 구분자로 하이픈("-")을 사용한다. 예를 들면 spring-core, logj4메 인 패키지 루트에서 유래된 번들 심볼릭명. 예를 들면 org.springframework.beans. jar가 OSGi 호환성 패치가 되었다면 com.springsource가 추가된다. 예를 들면 com.springsource.org.apache.log4j
버전의 작명관례다 양함. 새로운 artifact는 m.m.m이나 m.m.m.X를 사용한다. (m은 숫자고 X는 문자다.) 오래된 artifact는 m.m을 사용하거나 아예 다른 방식을 사용한다. 순서는 정의되어 있지만, 종종 따르지 않는 경우도 있으므로 너무 신뢰하지 않는 것이 좋다.OSGi 버전번호인 m.m.m.X를 사용한다. 예를 들면 3.0.0.RC3. 텍스트는 숫처럼 버전의 순서가 지켜지는 알파벳만 사용할 수 있다.
배포보통 rsync나 소스제어 업데이트를 통해 자동으로 이루어진다. 프로젝트 저자는 JIRA로 각 jar를 업로드 할 수 있다.수동 (스프링소스가 처리하는 JIRA)
품질 보증정책에 의해서 이루어짐. 정확도에 대한 책임은 프로젝트 저자한테 있다.상세한 OSGi manifest, 메이븐 POM, 아이비 metadata를 따름. QA는 스프링 팀이 진행한다.
호스팅Contegix. Sonatyle이 여러 미러사이트를 함께 펀딩함.스프링 소스가 펀딩하는 S3.
검색 유틸리티다양함http://www.springsource.com/repository
스프링소스 도구의 통합메이븐 의존성 관리로 STS에 통합됨메이븐, Roo, 클라우드 파운드리와 함께 STS로 광범위하게 통합됨

1.3.1.1 스프링 의존성과 스프링에 기반하는 의존성
스프링이 엔터프라이즈와 다른 외부 도구들에 대한 광범위한 통합과 지원을 제공하더라도 의도적으로 의존성을 최소한으로 유지해야 한다. 간단한 사용을 위해서라면 많은 jar 라이브러리를 다운받아 설치하지 말아야 한다.(자동으로 한다고 하더라도) 기본적인 의존성 주입을 사용하려면 오직 하나의 외부 의존성만 필요하고 이는 로깅을 위한 것이다.(로깅 옵션에 대한 더 자세한 내용은 아래를 봐라.)

다음은 스프링에 의존하는 애플리케이션 설정하는 필요한 기본적인 과정을 설명할 차례다. 먼저 메이븐과 아이비를 사용한다. 모든 경우에서 명확한 것이 없다면 의존성 관리 시스템의 문서를 참고하거나 예제코드를 봐라. - 스프링은 개발과정에는 의존성 관리를 위해 아이비를 사용하고 예제는 대부분 메이븐을 사용한다.

1.3.1.2 메이븐 의존성 관리
메이븐으로 의존성을 관리한다면 로깅 의존성을 명시할 필요도 없다. 예를 들어 어플리케이션 컨텍스트을 생성하고 어플리케이션 설정에 의존성 주입을 사용하려면 메이븐 의존성은 다음과 같을 것이다.



Xml
1
2
3
4
5
6
7
8
<dependencies>
  <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
     <version>3.0.0.RELEASE</version>
     <scope>runtime</scope>
  </dependency>
</dependencies>

이것이 전부다. 스프링 API를 거슬러서 컴파일할 필요가 없다면 scope를 런타임으로 선언할 수 있다. 이는 기본적인 의존성 주입의 유즈케이스다.

위의 예제에서 메이븐 센트럴의 작명 관례를 사용했으므로 메이븐 센트럴이나 스프링소스의 S3 메이븐 저장소에서 동작한다. S3 메이븐 저장소를 사용하려면(예를 들어 마일스톤이나 개발 스냅샷을 사용하기 위해) 메이븐 설정에 저장소의 위치를 명시해야 한다. 전체 릴리즈를 사용하려면 다음과 같이 작성한다.



Xml
1
2
3
4
5
6
7
<repositories>
  <repository>
     <id>com.springsource.repository.maven.release</id>
     <url>http://maven.springframework.org/release/</url>
     <snapshots><enabled>false</enabled></snapshots>
  </repository>
</repositories>

마일스톤을 사용하려면 다음과 같이 작성한다.

Xml
1
2
3
4
5
6
7
<repositories>
  <repository>
     <id>com.springsource.repository.maven.milestone</id>
     <url>http://maven.springframework.org/milestone/</url>
     <snapshots><enabled>false</enabled></snapshots>
  </repository>
</repositories>

개발 스냅샷을 사용하려면 다음과 같이 작성한다.

Xml
1
2
3
4
5
6
7
<repositories>
  <repository>
     <id>com.springsource.repository.maven.snapshot</id>
     <url>http://maven.springframework.org/snapshot/</url>
     <snapshots><enabled>true</enabled></snapshots>
  </repository>
</repositories>

스프링소스의 EBR을 사용하려면 의존성에 대해서 앞에서와는 다른 작명 관례를 사용해야 한다. 이름은 예하기 쉽다. 예를 들면 다음과 같다.

Xml
1
2
3
4
5
6
7
8
<dependencies>
  <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>org.springframework.context</artifactId>
     <version>3.0.0.RELEASE</version>
     <scope>runtime</scope>
  </dependency>
</dependencies>

저장소의 위치도 명시적으로 선언해야 한다.(URL부분만 중요하다)

Xml
1
2
3
4
5
6
<repositories>
  <repository>
     <id>com.springsource.repository.bundles.release</id>
     <url>http://repository.springsource.com/maven/bundles/release/</url>
  </repository>
</repositories>

직접 의존성을 관리한다면 위에서 선언한 저장소 URL은 검색하기에 좋지 않다. 하지만 http://www.springsource.com/repository에서 의존성을 검색하고 다운로드 받을 수 있는 화면을 제공한다. 메이븐이나 아이비를 사용한다면 쉽게 복사해서 붙일 수 있도록 메이븐과 아이비 설정 스니펫을 제공한다.

1.3.1.3 아이비(Ivy) 의존성 관리
의존성 관리를 Ivy로 하길 좋아하더라도 라이브러리 이름과 설정옵션은 비슷하다.

아이비를 설정하려면 ivysettings.xml에 스프링소스 EBR을 나타내는 다음 resolver를 추가한다.



Xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<resolvers>
  
  <url name="com.springsource.repository.bundles.release">

   <ivy pattern="http://repository.springsource.com/ivy/bundles/release/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
   <artifact pattern="http://repository.springsource.com/ivy/bundles/release/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />

  </url>

  <url name="com.springsource.repository.bundles.external">

   <ivy pattern="http://repository.springsource.com/ivy/bundles/external/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
   <artifact pattern="http://repository.springsource.com/ivy/bundles/external/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" /> 

  </url>

</resolvers>

위의 XML은 라인이 너무 길어서 유효한 XML이 아니다. - 복사해서 붙다면 URL 가운데 줄 바꿈을 삭제해라

아이비가 EBR로 설정되면 의존성 추가는 쉽다. 저장소 검색페이지에서 원하는 라이브러리의 상세페이지에 들어가서 의존성 부분에 추가할 아이비 스니펫을 찾을 수 있다. 예를 들어 ivy.xml에 다음과 같이 추가한다.



Xml
<dependency org="org.springframework" 
name="org.springframework.core" rev="3.0.0.RELEASE" 
conf="compile->runtime"/>

1.3.2 로깅
스프링에서 로깅은 아주 중요한 의존성이다. 


그 이유는
a) 로깅은 유일하게 강제적인 외부 의존성이고, 
b) 개발자는 사용하는 도구에서 어떤 출력을 보기 원하고 
c) 스프링은 로깅 의존성의 선택이 있는 다른 많은 툴과 통합되기 때문이다. 

어플리케이션 개발자의 목표 중 하나는 외부 컴포넌트를 포함한 전체 어플리케이션의 중심에서 통일된 로깅을 설정하는 것이다. 이는 로깅 프레임워크가 많이 존재하기 때문에 쉽지 않다.

스프링의 강제적인 로깅 의존성은 Jakarta Commons Logging API (JCL)이다. JCL을 컴파일하고 스프링 프레임워크를 상속받은 클래스에서 사용할 수 있는 Log객체로 만든다. 이는 같은 로깅 라이브러리를 사용하는 모든 버전의 스프링 사용자에게 중요하다. 스프링은 스프링을 상속받은 어플리케이션에서조차 하위호환성이 유지되므로 마이그레이션이 쉽다. 마이그레이션을 하는 방법은 스프링의 모듈 중 하나를 명시적으로 commons-logging(JCL의 정식 구현체)에 의존하게 하고 다른 모듈은 컴파일 시에 의존하게 하는 것이다. 예를 들어 메이븐을 사용하는데 commons-logging의 의존성이 어디에 있는지 모른다면 스프링의 핵심모듈인 spring-core에 있다.

commons-logging의 좋은 점은 당신이 어플리케이션을 동작하게 하는 것에만 신경 쓰면 된다는 것이다. commons-logging에는 잘 알려진 클래스패스나 적절한 위치(필요하다면 지적할 수 있다.)에서 다른 로깅 프레임워크를 찾는 런타임 디스커버리 알고리즘이 있다. 이용할 수 있는 로깅 프레임워크가 없다면 JDK(정확히는 java.util.logging이나 JUL이다.)로 꽤 괜찮은 로그를 남긴다. 대부분 상황에서 로그가 잘 나오는 것을 확인해서 스프링이 잘 동작한다는 것을 알 수 있다. 이는 중요하다.

1.3.2.1 Commons Logging 사용하지 않기
안타깝게도 commons-logging의 런타임 디스커버리 알고리즘은 엔드유저에게는 편리하지만, 문제의 소지가 있다. 시간을 거꾸로 돌릴 수 있거나 스프링을 새로운 프로젝트로 다시 시작한다면 런타임 디스커버리 알고리즘은 다른 로깅 의존성을 사용할 것이다. 첫 번째 선택은 아마 Simple Logging Facade for Java (SLF4J)일 것이다. 어플리케이션에서 스프링과 함께 사용하는 많은 툴은 SLF4J를 사용한다.

commons-logging는 쉽게 사용하지 않게 할 수 있다. 그냥 런타임시에 클래스패스에 존재하지 않으면 된다. 스프링 의존성이 선언되어 있으므로 메이븐에서 의존성을 제외 처리하면 된다.



Xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<dependencies>
  <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
     <version>3.0.0.RELEASE</version>
     <scope>runtime</scope>
     <exclusions>
        <exclusion>
           <groupId>commons-logging</groupId>
           <artifactId>commons-logging</artifactId>
        </exclusion>
     </exclusions>
  </dependency>
</dependencies>

위 코드를 추가하면 어플리케이션의 빌드가 깨질 것이다. 클래스패스에 JCL API의 구현체가 없기 때문이다. 새로운 구현체를 추가하면 이 문제를 해결할 수 있다. 다음 섹션에서 예제를 통해 SLF4J를 사용하는 JCL 구현체를 새로 추가하는 방법을 살펴볼 것이다.

1.3.2.2 SLF4J의 사용
SLF4J는 의존성이 깔끔하고 commons-logging보다 런타임에서 더 효율적이다. 다른 로깅 프레임워크의 런타임 디스커버리 대신 컴파일할 때 바인딩하기 때문이다. 이는 런타임에서 벌어질 일을 더 명시적으로 지정해야 한다는 의미이다. 따라서 의존성을 선언하고 적절하게 설정해야 한다. SLF4J는 대부분의 로깅 프레임워크에 대한 바인딩을 지원하므로 기존에 사용하던 로깅 프레임워크를 계속 사용할 수 있다. 사용하는 로깅 프레임워크를 설정과 관리에 바인딩하면 된다.

SLF4J는 JCL을 포함한 많은 로깅 프레임워크에 대한 바인딩을 지원한다. 반대로 다른 로깅 프레임워크가 SLF4J로 바인딩할 수도 있다. 즉 다른 로깅프레임워크와 SLF4J사이에 브릿지로 사용할 수도 있다. 그래서 스프링과 SLF4J를 함께 사용하려면 commons-logging의존성을 SLF4J-JCL 브릿지로 바꿔야 한다. 설정을 바꾸었으면 스프링에서 호출된 로깅은 SLF4J API를 호출하는 로깅으로 전환된다. 그래서 어플리케이션의 다른 라이브러리가 같은 API의 로깅을 사용한다면 한 곳에서 로깅을 설정하고 관리할 수 있다.

스프링을 SLF4J로 브릿지하고 명시적으로 SLF4J를 Log4J로 바인딩하는 것이 가장 일반적이다. 브릿지, SLF4J API, Log4J로의 바인딩, Log4J구현체의 4가지 의존성을 추가해야 한다.(commons-logging는 제외 처리해야 한다.) 메이븐이라면 다음과 같이 추가한다.



Xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<dependencies>
  <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
     <version>3.0.0.RELEASE</version>
     <scope>runtime</scope>
     <exclusions>
        <exclusion>
           <groupId>commons-logging</groupId>
           <artifactId>commons-logging</artifactId>
        </exclusion>
     </exclusions>
  </dependency>
  <dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>jcl-over-slf4j</artifactId>
     <version>1.5.8</version>
     <scope>runtime</scope>
  </dependency>
  <dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-api</artifactId>
     <version>1.5.8</version>
     <scope>runtime</scope>
  </dependency>
  <dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-log4j12</artifactId>
     <version>1.5.8</version>
     <scope>runtime</scope>
  </dependency>
  <dependency>
     <groupId>log4j</groupId>
     <artifactId>log4j</artifactId>
     <version>1.2.14</version>
     <scope>runtime</scope>
  </dependency>
</dependencies>

단순히 로깅을 사용하기 위해 너무 많은 의존성을 추가한 것처럼 보일 수 있다. 하지만 이는 선택사항이고 평범한 commons-logging보다 나은 동작을 한다. 특히 commons-logging는 OSGi 플랫폼 같은 엄격한 컨테이너를 사용한다면 클래스로더 이슈도 고려해야 한다. 또한, 바인딩이 런타임이 아닌 컴파일타임에 이뤄지기 때문에 성능적인 이점도 있다고 알려졌다.

더 적은 과정과 의존성을 사용하는 SLF4J 사용자들은 보통 Logback로 직접 바인딩한다. Logback은 SLF4J를 직접 구현했기 때문에 추가적인 바인딩 과정을 줄여준다. 그래서 4개가 아닌 2개의 라이브러리에만 의존할 수 있다.(jcl-over-slf4j와 logback) Logback으로 직접 바인딩하는 방법을 사용했다면 (스프링이 아닌) 다른 외부 의존성에서 slf4j-api에 대한 의존성을 제외처리 해야 한다. 이는 클래스패스에 오직 한가지 버전의 API만 존재하기를 바라기 때문이다.

1.3.2.3 Log4J의 사용
많은 사람들이 설정과 관리 때문에 로깅 프레임워크로 Log4j를 사용한다. Log4j는 사용하기 편하고 잘 구성되어 있다. 사실 스프링을 만들고 테스트할 때 런타임에서 Log4j를 사용했다. 스프링은 Log4j의 설정과 초기화를 위한 몇 가지 유틸리티도 제공한다. 그래서 스프링의 몇몇 모듈에는 Log4j에 대한 의존성이 컴파일타임에 선택적으로 의존성이 존재한다.

기본 JCL 의존성(commons-logging)과 함께 Log4j가 동작하게 하려면 클래스패스에 Log4j를 두고 클래스패스의 루트에 설정파일 (log4j.properties나 log4j.xml)을 두면 된다. 메이븐 사용자라면 의존성 선언에 추가한다.



Xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<dependencies>
  <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
     <version>3.0.0.RELEASE</version>
     <scope>runtime</scope>
  </dependency>
  <dependency>
     <groupId>log4j</groupId>
     <artifactId>log4j</artifactId>
     <version>1.2.14</version>
     <scope>runtime</scope>
  </dependency>
</dependencies> 

다음은 콘솔에 로그를 출력하는 log4j.properties의 예제이다.

Xml
log4j.rootCategory=INFO, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2}:%L - %m%n

log4j.category.org.springframework.beans.factory=DEBUG

네이티브 JCL를 사용하는 런타임 컨테이너
많은 사람들이 JCL의 구현체를 제공하는 컨테이너에서 스프링 어플리케이션을 구동한다. IBM 웹스피어(Websphere) 어플리케이션 서버(WAS)가 대표적이다. 웹스피어는 종종 문제를 일으키는데 불행히도 거기에는 완벽한 해결책이 없다. 대부분의 상황에서 단순히 어플리케이션에서 commons-logging를 제외 처리하는 것으로는 해결되지 않는다.

이 문제를 좀 더 명확히 보자. 알려진 문제점은 JCL이나 commons-logging자체의 문제는 아니다. 더 정확히 말하면 commons-logging를 다른 프레임워크(대개 Log4J)로 바인딩해서 발생한 문제다. 바인딩이 실패하는 이유는 몇몇 컨테이너가 사용하는 commons-logging의 과거 버전(1.0)과 대부분이 사용하는 최신 버전(1.1)사이에서 런타임 디스커버리 방법이 달라졌기 때문이다. 스프링은 JCL API에서 특이한 API는 전혀 사용하지 않으므로 문제가 발생하지 않는다. 하지만 스프링이나 어플리케이션이 로깅을 시도하자마자 Log4J로의 바인딩이 동작하지 않는 것을 발견할 수 있을 것이다.

WAS에서 이러한 상황을 겪을 가장 쉬운 해결책은 컨테이너 대신 어플리케이션이 JCL 의존성을 제어하도록 클래스 로더의 계층을 거꾸로 하는 것이다.(IBM은 이를 "parent last"라고 부른다.) 이 옵션은 항상 열려 있는 것은 아니지만, 대안적인 방법을 위한 공개된 영역에서 다수의 다른 제안이 존재한다. 아마 컨테이너의 정확한 버전과 기능에 의존하도록 바꿀 것이다. 


[JAVA]1장 스프링 프레임워크 소개 #1..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

오랫동안 자바와 스프링에 대해서 공부해야지 하면서도 사실 다른 기술들에 비해서 많은 시간은 투자하지 못했습니다. 어쨌든 작년부터는 스프링으로 업무를 하고 있기 때문에 올해는 맘먹고 스프링을 공부하기로 했습니다. 어떻게 스프링을 공부하는게 좋을까 고민을 많이 했습니다. 그래도 수많은 기술들을 만져봤지만 스프링 프레임워크자체가 꽤 크기 때문인지 전체적인 감을 잡기가 좀 어려웠습니다. 아무래도 시간을 많이 투자하지 못했기 때문이라고 생각합니다.

예전과는 다르게 이제는 토비의 스프링 3라는 좋은 책이 생겼기 때문에 공부하기는 훨씬 용이해 졌다고 생각합니다. 토비의 스프링 3를 한번 보기는 했지만 제대로 스프링을 써보기 전에 공부했기 때문에 제대로 이해못한 부분도 있었는데 그래도 6개월 이상 스프링을 사용하고 있기 때문에 올해 스프링을 공부하면 이해도가 좀 더 높아질 꺼라 생각하고 있습니다. 토비님이 토비의 스프링 3에서 계속 러닝테스트를 강조하셨기 때문에 코딩량도 부족한 저에게는 좋은 학습방법이 될꺼라고 생각했습니다. 하지만 러닝테스트는 공부를 하면서 설명에 나온 기능을 직접 테스트로 구현하면서 파악해 보는 것이기 때문에 러닝테스트 작성외에 기능의 설명이 나열된 어떤 교재가 필요했습니다. 처음에는 토비의 스프링 3을 생각했지만 책도 아는 만큼 보이기 때문에 좀 더 스프링을 이해하고 보면 더 이해도가 높을꺼라고 생각해서 한번 더 보기전에 좀 더 스프링에 대한 감을 잡고 싶었습니다.

그래서 스프링 프레임워크 레퍼런스 가이드를 선택했습니다.  레퍼런스 가이드는 모든 기술에서 기본이 된다고 생각하고 있었기 때문에 조급해하지 말고 기본부터 다져가자는 생각으로 레퍼런스 가이드를 보기로 했습니다. 사실 700 페이지나 되는 분량에 좀 압도되기는 했지만 끝까지 다 보지 못한다고 하더라도 일단 해보기로 했습니다. 저는 영어문서를 읽을 때 가능하면 번역을 하면서 보기 때문에 번역한 내용을 블로그에 올립니다. 이 내용은 스프링을 공부하려는 목적으로 하는 번역이기 때문에 번역의 품질은 그다지 좋지 못합니다. 왠만한 기술 용어는 영문 용어를 그대로 사용했고 문장은 내용을 이해할 수 있는 정도 수준이면 크게 다듬지 않았기 때문에 상당수 번역문제가 존재할 수 있습니다. 그리고 스프링에 대한 이해도가 높지 않기 때문에 오역이 있을 수도 있습니다.
이 문서는 Github 저장소에서 관리합니다. 현재 레퍼런스 가이드는 3.1버전이지만 3.1의 내용이 전부 적용되어 있지는 않은것 같습니다. 나중에 레퍼런스 가이드가 업데이트되었을 때 비교해서 적용도 해야하기 때문에(가능하다면) 저장소로 관리하기로 했습니다. 이왕 하는거 저장소로 관리하기 시작했지만 레퍼런스 가이드의 분량이 엄청나기 때문에 끝까지 할 수 있을지 어느정도까지 하다가 멈출지는 저도 알 수 없습니다. 하다가 지쳐서 그만 둘 수도 있고 스프링 학습이 목적이기 때문에 학습에 별로 도움이 안된다고 느껴지거나 더 좋은 학습방법을 깨닫게 되면 언제든지 멈출 수 있습니다. 저는 git-flow의 브랜칭 모델을 따르기로 했기 때문에 번역한 내용은 master브랜치가 아닌 develop브랜치에 존재합니다. master 브랜치를 사용합니다.

Spring Framework Reference Documentation

이 문서는 개인적인 목적이나 배포하기 위해서 복사할 수 있다. 출력물이든 디지털 문서든 각 복사본에 어떤 비용도 청구할 수 없고 모든 복사본에는 이 카피라이트 문구가 있어야 한다.

Part I. Spring Framework 개요

스프링 프레임워크는 엔터프라이즈급 애플리케이션을 만들기 위한 경량솔루션이며 많은 기능을 제공하고 있다. 하지만 스프링은 필요한 부분만 가져다 사용할 수 있도록 모듈화되어 있다. Struts를 IoC 컨테이너와 함께 사용할 수 있고 하이버네이트 통합 코드나 JDBC 추상화 계층만 사용할 수도 있다. 스프링 프레임워크는 RMI나 웹서비스로 로직에 원격접근하는 선언적 트랜잭션 관리와 데이터를 유지하는 다양한 옵션을 지원한다. 모든 기능을 갖춘 MVC 프레임워크를 제공하고 소프트웨어에 투명하게 AOP를 합할 수 있다.

스프링은 비침투적이다. 이 말은 도메인 로직 코드가 일반적으로 프레임워크에 의존적이지 않다는 의미이다. (데이터 접근 계층 같은) 통합 계층에서 데이터 접근 기술과 스프링 라이브러리에 대한 의존성이 존재한다. 하지만 당신의 다른 코드들로부터 이러한 의존성을 쉽게 제거할 수 있을 것이다.

이 문서는 스프링 프레임워크에 대한 레퍼런스 가이드이다. 이 문서에 대한 어떤 요청이나 의견, 질문이 있다면 사용자 메일링 리스트나 http://forum.springsource.org/의 지원 포럼에 글을 올리면 된다.

1. 스프링 프레임워크 소개
스프링 프레임워크는 자바 애플리케이션 개발을 위한 포괄적인 인프라스트럭쳐를 제공하는 자바 플랫폼이다. 스프링은 당신이 애플리케이션에 집중할 수 있도록 인프라스트럭쳐를 다룬다.

스프링을 사용하면 "plain old Java objects"(POJOs)로 어플리케이션을 만들고 엔터프라이즈 서비스를 비침투적으로 POJO에 적용할 수 있다. 이 능력은 Java SE 프로그래밍에 적용되고 전제 혹은 부분적으로 Java EE에 적용된다.

어플리케이션 개발자인 당신이 어떻게 스프링 플랫폼의 이점을 사용할 수 있는가에 대한 예제가 있다.

  • 트랜잭션 API를 사용하지 않고도 데이터베이스 트랜잭션에서 자바메서드를 실행하도록 만든다.
  • 원격 API를 사용하지 않고도 로컬 자바메서드를 원격 프로시저로 만든다.
  • JMX API를 사용하지 않고도 로컬 자바메서드를 관리작업으로 만든다.
  • JMS API를 사용하지 않고도 로컬 자바메서드를 메시지 핸들러로 만든다.

1.1 의존성 주입(Dependency Injection)과 제어의 역전(Inversion of Control)
자바 어플리케이션은 -- 제한적인 에플릿부터 n티어 서버사이드 엔터프라이즈 어플리케이션까지 포함하는 의미다 -- 보통 어플리케이션에 적합한 형식으로 협력하는 객체로 이루어져 있다. 그래서 어플리케이션의 객체는 서로 의존성이 있다.

자바 플랫폼이 어플리케이션 개발에 관련된 풍부한 기능을 제공하더라도 기본적으로 구축된 블락들을 서로 밀착된 하나의 큰 구조로 만드는 기능은 부족하다. 아키텍처와 개발자가 이 작업을 해야 한다. 사실, 애플리케이션을 만드는 여러 가지 클래스와 오브젝트 인스턴스를 구성하기 위해 팩토리, 추상 팩토리, 빌더, 데코레이터, 서비스 로케이터같은 디자인 패턴을 사용할 수 있다. 하지만 이러한 디자인 패턴은 단순히 베스트 프티스에 이름을 주어 패턴이 무슨 일을 하고 어디에 적용할 수 있고 어떤 문제에 대한 것인지 등을 설명한 것뿐이다. 패턴은 어플리케이션에서 스스로 구현해야 하는 베스트 프렉티스를 형식화한 것이다.

스프링 프레임워크 제어의 역전 (IoC) 컴포넌트는 이러한 관심사에 접근한다. 즉, 서로 다른 컴포넌트들을 사용할 준비가 된 완전히 동작하는 애플리케이션을 구성하는 형식적인 의미를 제공한다.스프링 프레임워크는 자신의 어플리케이션으로 통합할 수 있는 퍼스트 클래스 객체를 형식화된 디자인 패턴으로 만들었다.수많은 조직과 협회는 신뢰할 수 있고 유지보수 가능한 어플리케이션을 만들려고 이 방법으로 스프링 프레임워크를 사용한다.

배경

“제어의 어떤 관점이 역전되었는가?” 마틴 파울러(Martin Fowler)는 2004년 자신의 사이트에서 제어의 역전(IoC)에 대한 의견을 말했다. 파울러는 원리가 더 명확하게 드러나도록 이름을 의존성 주입(Dependency Injection)으로 바꾸어야 한다고 제한했다.

IoC와 DI를 더 알고 싶다면 http://martinfowler.com/articles/injection.html에 올라온 파울러의 글을 참고해라.

1.2 모듈
스프링 프레임워크는 약 20개의 모듈로 구조화된 특징으로 이루어져 있다. 이러한 모듈들은 다음 다이어그램에 보이듯 코어 컨테이너, 데이터 접근/통합, 웹, AOP(관점지향 프로그래밍), 인스트루멘테이션(Instrumentation), 테스트로 그룹을 나눌 수 있다.

스프링 프로그램의 개요
스프링 프로그램의 개요


1.2.1 코어 컨테이너
코어 컨테이너 는 코어(Core), 빈즈(Beans), 컨텍스트(Context), 표현언어 (Expression Language) 모듈로 이루어졌다.

코어와 빈즈 모듈은 IoC와 의존성 주입을 포함하는 프레임워크의 기본이 되는 부분을 제공한다. BeanFactory는 팩토리 패턴을 세련되게 구현했다. BeanFactory을 사용하면 프로그래밍 적으로 싱글톤을 구현할 필요가 없고 실제 프로그램 로직에서 의존성에 대한 설정과 명세를 분리할 수 있다.

컨텍스트 모듈은 코어와 빈즈 모듈에서 제공하는 단단한 기반위에 구성되었다. 이는 JNDI 등록과 유사한 프레임워크 스타일로 객체에 접근한다는 의미다. 컨텐스트 모듈은 빈즈 모듈의 특징을 상속받고 국제화, 이벤트 전파, 리소스-로딩, 서블릿 컨테이너 컨텍스트의 투명한 생성에 대한 지원을 추가한다. 또한 컨텍스트 모듈은 EJB, JMX, 기본적인 원격 같은 Java EE의 기능을 지원한다. ApplicationContext 인터페이스는 컨텍스트 모듈에서 중요하다.

표현언어 모듈은 런타임에서 객체 그래프를 조회하고 조작하는 강령한 표현언어이다. 표현언어 모듈은 JSP 2.1 명세에 명시된 것처럼 통합된 표현언어(unified EL)의 확장이다. 언어는 속성값을 설정하고 가져오는 기능과 속성 할당, 메서드 호출, 배열과 컬렉션과 인덱서의 컨텍스트 접근, 논리적/산술적 오퍼레이터, 이름있는 변수, 스프링의 IoC 컨테이너에서 이름으로 객체를 획득하는 기능을 지원한다. 일반적인 리스트 집합뿐 아니라 리스트의 투영과 선택도 지원한다.

1.2.2 데이터 접근/통합
데이터 접근/통합 계층은 JDBC, ORM, OXM, JMC, 트랜잭션 모듈로 이루어졌다.

JDBC모듈은 JDBC 추상화계층을 제공한다. 그래서 지루한 JDBC 코딩과 데이터베이스 벤더에 따라 다른 오류코드를 파싱할 필요가 없다.

ORM 모듈은 JPA, JDO , Hibernate, iBatis를 포함하는 인기 있는 객체-관계 매핑 API에 대한 통합계층을 제공한다. ORM 패키지를 사용하면 이러한 O/R매핑 프레임워크들을 앞에서 언급했던 선언적 트랜젝션 관리 같은 스프링의 다른 기능들과 함께 사용할 수 있다.

OXM 모듈은 JAXB, Castor, XMLBeans, JiBX, XStream에 대한 객체/XML매핑 구현을 지원하는 계층이다.

자바 메시징 서비스 (JMS) 모듈은 메시지를 생산하고 소비하는 기능을 포함한다.

트랜잭션 모듈은 특별한 인터페이스와 모든 POJO (plain old Java objects)의 클래스에 대한 트랜잭션 관리를 지원한다. 트랜잭션 관리는 프로그래밍 적으로 하거나 선언적으로 할 수 있다.

1.2.3 웹
웹 계층은 웹, 웹-서블릿, 웹-스트러츠, 웹-포틀릿 모듈로 이루어졌다.

스프링의 웹 모듈은 기본적인 웹-지향적인 통합기능을 제공한다. 웹-지향적인 통합기능은 멀티파트 파일 업로드 기능, 서블릿 리스너와 웹 지향적인 애플리케이션 컨텍스트를 사용한 IoC 컨테이너의 초기화를 말한다. 또한, 스프링의 원격기능에서 웹과 관련된 부분을 포함한다.

웹-서블릿 모듈은 웹 어플리케이션을 위한 스프링의 모델-뷰-컨트롤러 (MVC ) 구현을 포함한다. 스프링의 MVC 프레임워크는 도메인 모델코드와 웹 폼을 깔끔하게 분리할 수 있도록 하고 스프링 프레임워크의 다른 모든 기능과 통합할 수 있게 한다.

웹-스트러츠(Web-Struts) 모듈은 스프링 어플리케이션에서 전통적인 스트러츠 웹티어를 통합을 지원하는 클래스를 포함한다. 이 지원은 스프링 3.0에서는 폐기되었다. 어플리케이션을 스트러츠 2.0이나 스트링 통합으로 마이그레이션 하던가 스프링 MVC를 사용하는 것을 고려해라.

웹-포틀릿(Web-Portlet) 모듈은 포틀릿 환경에서 사용되는 MVC 구현과 웹-서블릿 모듈 기능의 미러 기능을 제공한다.

1.2.4 AOP와 인스트루멘테이션(Instrumentation)
스프링의 AOP 모듈은 AOP Alliance를 따르는 관점지향 프로그래밍의 구현체다. 예를 들어 기능적으로 분리되어야 하는 코드를 깔끔하게 분리하는 메서드-인터셉터와 포인트컷을 정의할 수 있다. 소스레벨의 메타데이터 기능을 사용하면 .NET 어트리뷰트와 유사한 방법으로 행동에 관한 정보를 코드로 구현할 수 있다.

분리된 관점(Aspects) 모듈은 AspectJ와의 통합을 제공한다.

인스트루멘테이션(Instrumentation) 모듈은 인스트루멘테이션을 지원하는 클래스와 특정 어플리케이션 서버에서 사용되는 클래스로더 구현체를 제공한다.

1.2.5 테스트
테스트 모듈은 JUnit이나 TestNG로 스프링 컴포넌트의 테스트를 지원한다. 테스트 모듈은 스프링 어플리케이션 컨텍스트의 안정된 로딩과 이러한 컨텍스트의 캐싱을 제공한다. 또한, 코드를 격리된 상태로 테스트하기 위해 사용할 수 있는 모의 객체를 제공한다.