[출처] http://www.hanb.co.kr/network/view.html?bi_id=1343



내가 Spring을 사랑하는 다섯 가지 이유

                                

제공 : 한빛 네트워크
저자 : Bruce A. Tate
역자 : 박찬욱
원문 : Five Things I Love About Spring

15년 전 보다 더 더운 6월 아침에 나는 오래된 fiberglass(섬유 유리로 된) 카약을 타고 있었다. 너무 오래돼 내 손에서 조각들이 떨어져나가곤 했고, 노는 전통적인 whitewater paddle보다 약 2배 정도 길었다. 나는 내 보트보다 수영을 더 많이 해야 했지만, 그리 큰 문제는 아니었다. 15년 후에도 나는 여전히 열중(hooked)하고 있을 것이다. 대략 이 년 전에 하이버네이트 사이트에서 급격히 중요하게 언급된 Spring 프로젝트를 사용해 봤다. 이것은 오래 된 카약과 같은 느낌이었다. 나에게는 완벽하게 잘 맞았다. 가망이 없는 엔터프라이즈 개발에서 Spring은 나의 네 번째 자바 책, Spring : A Developer's Notebook, 의 주제로 만들었던 것처럼 나의 프로그래밍으로 매우 깊이 들어왔다. 이번 글에서 나는 이 이유에 대해서 당신에게 설명하려 한다.

1. Spring은 매우 좋은 수단을 제공한다.

강에서 나는 팔 근육이 강에서 노를 젓는 동안에 힘을 유지할 수가 없어서, 허리와 등을 조금 더 이용해서 노를 젓는 것을 배웠다. 더 좋은 수단을 얻게 된 것이다. Spring에서는 조금 더 코드의 각 라인에 집중해 일할 수 있다. 당신은 Spring의 많은 코드에서 훌륭한 수단을 찾을 수 있지만, 가장 큰 점은 영속성에 관련된 부분이다. 다음은 하이버네이트 데이터 접근 객체의 메소드에 대한 예이다.
public List getReservations( ) {
  return getHibernateTemplate( ).find("from Reservation");
}
당신이 찾지 못한 것을 말해봐라. 트랜잭션 처리 과정이 없다. Spring은 트랜잭션 관리를 위한 환경 구성 코드를 구축할 수 있게 해준다. 세션을 막아 놓으면서 자원을 관리하지 않는다. 당신만을 위한 환경 설정을 할 필요도 없다. 트랜잭션 레벨에서는 예외가 unchecked이기 때문에, 예외 관리도 할 필요가 없다. 대부분의 상황에서 트랜잭션에 대한 관리에서 자유로워진다. Spring을 사용하지 않고 어떻게 구현했는지 다른 하이버네이트 메소드를 보면 알 수 있다.
public List getBikesOldWay( ) throws Exception {
  List bikes = null;
  Session s = null;
  try {
    s = mySessionFactory.openSession( );
    bikes = s.find("from Bike");
  }catch (Exception ex) {
    //handle exception gracefully
  }finally {
    s.close( );
  }
  return bikes;
}
Spring은 나에게 수단을 제공한다. 나는 더 빨리 코드를 작성할 수 있으며, 유지를 위한 수고도 적다.

2. Spring은 POJO 프로그래밍을 가능하게 해준다.

EJB 2.x가 완패한 후에, 모두들 침략적이지 않고 성가신 모델로 된 모든 빈들 없이 엔터프라이즈 서비스를 구현할 수 있는 방법을 찾았다. EJB를 사용하면 확장 API와 새로운 툴과 개발 과정에 대해 배워야만 한다. Spring을 사용하면, 내가 나의 서비스와 영속성 프레임워크를 선택할 수 있다. POJO로 프로그램을 짜고 환경 설정 파일을 통해서 그 프로그램에 엔터프라이즈 서비스를 추가한다.

Spring: A Developer's Notebook에서, RentaBike 어플리케이션을 구축했다. 세션 빈과 엔티티 빈 대신에, 나는 데이터 접근 객체로 제공되는 POJO hibRentaBike를 호출했었다. 나는 어디서나 이 서비스를 추가할 수 있다. 컨텍스트(context)를 호출하는 Spring 환경설정 파일은 컨테이너에서 제공되는 모든 빈에 대한 내용과 빈이 필요로 하는 속성들(properties)과 서비스를 함께 담고 있는 XML 파일이다. 여기서 코드를 보자.
대상(the target) :
<bean id="rentaBikeTarget" class="com.springbook.HibRentABike">
  <property name="storeName">
    <value>Bruce's Bikes</value>
  </property>
  <property name="sessionFactory">
    <ref local="sessionFactory"/>
  </property>
  <property name="transactionManager">
    <ref local="transactionManager"/>
  </property>
</bean>

인터셉터(the interceptor) :
<bean name="transactionInterceptor" 
    class="org.springframework.transaction.interceptor.TransactionInterceptor">
  <property name="transactionManager">
    <ref local="transactionManager"/>
  </property>
  <property name="transactionAttributeSource">
    <value>
      com.springbook.RentABike.transferReservation=
      PROPAGATION_REQUIRED,-ReservationTransferException
      com.springbook.RentABike.save*=PROPAGATION_REQUIRED
      com.springbook.RentABike.*=PROPAGATION_REQUIRED,readOnly
    </value>
  </property>
</bean>

프록시(the proxy) :
<bean id="rentaBike" class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="proxyInterfaces">
    <value>com.springbook.RentABike</value>
  </property>
  <property name="interceptorNames">
    <value>transactionInterceptor,rentaBikeTarget</value>
  </property>
</bean>

세 개의 다른 빈-프록시, 대상 객체(the target), 인터셉터-이 있다는 것을 알아두자. 프록시는 POJO를 호출 할 것이고, POJO에 의해 필요한 서비스들이 있을 것이다. 인터셉터는 서비스를 호출하는데 반드시 필요한 서비스 코드를 포함한다. 또한 프록시와 인터셉터에는 대상 객체(the target)에 있는 각 메소드를 어떻게 처리할지에 대해 정의한다. 프록시를 호출해서 RentaBike에 접근을 필요로 하는 어느 누구든지 트랜잭션을 처리하는 인터셉터를 호출하고, 트랜잭션을 시작한 다음 대상 객체(the target : 여기서는 POJO가 됨)를 호출할 수 있다. 대상 객체는 자신의 임무를 수행하고, (트랜잭션을 커밋하는) 인터셉터에게 리턴 한 다음, 다시 프록시에게 리턴하고, 마지막으로 프록시를 호출한 대상에 결과를 리턴 한다. 

 

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com


c01.1173749077@spring_fig1.gif
 [그림 1. POJO programming in action]

그림에 나온 것처럼 POJO로 프로그램을 구축할 수 있고, Spring은 당신에게서 나머지 부분을 숨겨준다. 나는 POJO 프로그래머다.

3. 테스트 용이성을 도와주는 의존성 삽입(Dependency Injection)

Spring은 의존성 삽입(DI : Dependency Injection)으로 불리는 디자인 패턴을 통해서 테스트 용이성을 개선했다. 사용자가 한 의존성에 의존할 경우(우리가 서비스라 부르는), 우리는 이 사용자 위한 단일 속성을 만들어야 한다. Spring은 사용자와 서비스를 만들고, 사용자의 속성을 서비스의 값으로 할당한다. 다른 말로 해보면, Spring은 컨텍스트 내에서 빈의 생명주기를 관리하고, 의존성을 결정한다. Spring을 사용하지 않은 의존성 삽입의 한 예를 들어보자. 어플리케이션을 위한 주요한 뷰를 제공하는 사용자(consumer)를 정의했다.

public class CommandLineView {

  private RentABike rentaBike;

  public CommandLineView( ) {
	rentaBike = new ArrayListRentABike("Bruce's Bikes"); 
  }

  public void setRentABike(RentABike rentABike){
  	this.rentABike = rentABike;
  }

  public void printAllBikes( ) {
    	System.out.println(rentaBike.toString( ));
	Iterator iter = rentaBike.getBikes().iterator( );
	while(iter.hasNext( )) {
	Bike bike = (Bike)iter.next( );
        System.out.println(bike.toString( ));
  }
}

  public static final void main(String[] args) {
    CommandLineView clv = new CommandLineView( );
    clv.printAllBikes( );
  }

}
다음으로 모델 역할을 하는 서비스를 보자. 배열 리스트를 사용한 간단한 구현이다. 이 구현 클래스는 모델(RentaBike)에 대한 의존성을 가지고 있다.
interface RentABike {
List getBikes( );
Bike getBike(String serialNo);
}

public class ArrayListRentABike implements RentABike {
   private String storeName;
   final List bikes = new ArrayList();
   public ArrayListRentABike(String storeName) {
      this.storeName = storeName;
      bikes.add(new Bike("Shimano", "Roadmaster", 20, "11111", 15, "Fair"));
      bikes.add(new Bike("Cannondale", "F2000 XTR", 18, "22222",12,"Excellent"));
      bikes.add(new Bike("Trek","6000", 19, "33333", 12.4, "Fair"));
   }

   public String toString() { 
      return "RentABike: " + storeName; 
   }

   public List getBikes() { 
      return bikes; 
   }

   public Bike getBike(String serialNo) {
      Iterator iter = bikes.iterator();
      while(iter.hasNext()) {
         Bike bike = (Bike)iter.next();
         if(serialNo.equals(bike.getSerialNo())) return bike;
      }
      return null;
   }
}
이제 중개자(assembler)에 대해 보자. 이 중개자는 서비스와 사용자를 초기화하고, rentaBike속성에 값을 할당함으로서 의존성을 결정한다.
public class RentABikeAssembler {
  public static final void main(String[] args) {
    CommandLineView clv = new CommandLineView( );
    RentABike rentaBike = new ArrayListRentABike("Bruce's Bikes");
    clv.setRentaBike(rentaBike);
    clv.printAllBikes( );
  }
}
물론 Spring은 결과적으로 중개자 역할에 매우 적합할 것이다. 만약 인터페이스로 서비스를 감싼다면, 이 인터페이스를 구현한 컨테이너에 있는 어떤 클래스도 주입(inject)이 가능할 것이다.

의존성 삽입은 당신의 코드가 의존성을 만들고 테스트하는 것을 가능하게 해준다. 예를 들어, 이 예에서 view를 더 쉽게 해주는 테스트를 만들기 위해 스텁(stub) 객체를 만들 수 있다.(stub과 mock에 대해 더 알고 싶으면 “Mocks Aren't Stubs http://www.martinfowler.com/articles/mocksArentStubs.html ”를 읽어보기 바란다.)

당신이 이미 배열 리스트 버전의 RentaBike의 하이버네이트 구현을 봤다. 나는 완벽한 하이버네이트 구현에서 모든 사용자 인터페이스 테스트를 실행하는 것을 원치 않는다. 대신에 배열 리스트를 사용해서 다른 방법으로 인터페이스를 간단히 구현할 수 있다.

의존성 삽입은 제품 버전(HibRentaBike), 개발 버전(ArrayListRentaBike 리스트)과 테스트 버전(mock 객체)을 묶을 수(wire up)있게 해 준다. 내가 자바로 코딩할 때, mock 객체들을 사용하기 어려운 장소에서 사용을 위해 의존성 삽입을 하기 시작했다.

4. JDBC를 간단하게 만들어버린 제어의 역전(Inversion of Control)

JDBC 어플리케이션은 추악하고, 장황하고, 진저리가 난다. 좋은 추상화 레이어는 이 문제를 해결하는데 도움을 줄 수 있다. Spring은 당신이 쿼리를 사용하는 기본 JDBC 메소드와 단조로운 작업의 많은 부분을 제거해주는 익명 내부 클래스(anonymous inner class)를 커스터마이징이 가능하도록 해준다. 여기서 간단한 예제를 한 번 보자.
JdbcTemplate template = new JdbcTemplate(dataSource); 
final List names = new LinkedList();

template.query("SELECT USER.NAME FROM USER", 
  new RowCallbackHandler() { 
      public void processRow(ResultSet rs) throws SQLException {
        names.add(rs.getString(1));
      }
  }
);
기본 JDBC 메소드로서 사용되는 쿼리 메소드인 템플릿에 대해 생각해보자. Spring은 ResultSet에 있는 각 라인을 위해 익명 내부 클래스에 있는 processRow 메소드를 실행할 것이다. 당신은 컨텍스트에 데이터 소스(data source)를 구성해야 한다. statement를 열거나 닫기, connection, 데이터 소스의 구성, 혹은 트랜잭션 관리에 대한 걱정을 할 필요가 없다. Spring은 SQLException을 일반적인 unchecked 예외 셋으로 감싸주기 때문에 외부 결과 값 셋을 정의하거나 최 하단 수준의 예외를 직접 관리하면 안 된다. 루비나 스몰토크 같은 다른 언어들도 드물게 코드 블록으로 제어의 역전을 사용하지만, 자바에서는 이것이 일반적이지 않다. 제어의 역전은 정말로 나를 동요시킨다.

5. 번창하는 Spring의 커뮤니티

몇몇 오픈소스 프로젝트는 유용하게 사용되기 위해서 커뮤니티의 두드러진 활동이 필요 없는 경우도 있다. 예를 들어보면, JUnit은 대상이 된 작업(job)이 있고, 프로그래밍 모델을 좋아하는 경우 기본적으로 당신이 필요로 하는 모든 것들이 들어 있다. Spring 같은 경량 컨테이너(lightweight container)는 매우 활발한 커뮤니티를 필요로 한다. Spring은 당신이 찾을 수 있는 것 중에서 많은 도움을 받을 수 있는 가장 활발한 커뮤니티 중 하나이다.
  • 서비스 : Spring을 사용하면 보안, 시스템 관리, 작업 흐름 관리에 해당하는 수 백 개의 다른 서비스를 찾을 수 있다. 영속성 관리를 위해서 당신은 JDO, Hibernate, Top Link, JDBC, 혹은 OJB를 붙여서 사용(plug in) 할 수 있다.
  • 지원과 교육 : 상당히 많은 컨설턴트들이 Spring 서비스를 제공하고, 드물지만 세계 각 지에서 교육을 받을 수 있다.
  • 가치 증가 : Spring은 한 해에 몇 개의 주요한 릴리스 버전을 내놓고 있다. 프레임워크 내에서 수행된 매우 훌륭한 테스트와 완벽하게 인자화 된 확장은 각 릴리스의 좋은 품질을 의미한다. Spring은 이미 최근 주요한 릴리스에서 내부적으로 하이버네이트 3를 지원하였고, 새롭고 강력한 web flow 프레임워크를 제공했다.
  • 상업적인 지원 : 필자와 같은 작가는 Spring에 관련된 책을 쓴다. 지금껏 Spring에 관련된 다섯 권의 책을 찾을 수 있고, Spring 컨텐츠들은 더 많이 존재한다. 몇 몇 제품 벤더들은 Spring을 지원한다. Geronimo와 Hibernate와 같은 많은 오픈 소스 프레임워크들이 Spring을 위한 특별한 지원을 하고 있다.
Spring 커뮤니티는 프레임워크를 더욱 쉽게 사용할 수 있도록 해준다. 나는 Spring 개발자를 고용할 수 있고, 그들에게 교육을 받을 수 있다. Spring에 대한 내 지식을 보충하기 위해서 책을 읽을 수 있고, 내가 하고자 원하는 것에 대한 모든 것들에 대해서 컴포넌트를 받을 수 있다. 가까운 시일 내에 어떤 다른 경량 컨테이너를 위한 커뮤니티를 찾을 수 없을 것이다.




본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
24 javac 로 컴파일 시 유니코드(utf-8) 한글 소스 코드 컴파일 문제 졸리운_곰 2015.02.02 932
23 [스프링] 스프링 Java 어노테이션 file 졸리운_곰 2014.06.11 758
22 [스프링] 스프링 MVC 졸리운_곰 2014.06.11 324
21 [스프링] 어노테이션 졸리운_곰 2014.06.11 848
20 인코딩 - 8859_1의 비밀(?) file 졸리운_곰 2014.05.06 487
19 [JNI] 안드로이드 JNI 환경에서 C++과 Java 간의 한글 데이터 전송 문제 졸리운_곰 2014.05.06 493
18 자바 암호화 복호화 file 졸리운_곰 2014.04.08 2384
17 파일 존재 여부 판단, 디렉토리 있는지 확인 함수; File Directory Exist 졸리운_곰 2014.03.03 1078
16 NetStat call and get result text in Java 졸리운_곰 2014.02.25 786
15 [Spring] @Autowired 와 Java Spring 졸리운_곰 2014.01.29 1158
14 Java Static 변수 졸리운_곰 2014.01.28 889
13 Properties 클래스 사용하기. 졸리운_곰 2014.01.28 852
12 Java => Thread 졸리운_곰 2014.01.28 636
» [Spring] 내가 Spring을 사랑하는 다섯 가지 이유 file 가을의 곰을... 2013.12.22 834
10 Java 세마포어(Semaphore) 가을의 곰을... 2013.12.11 2329
9 Java Thread 제어 (Thread Pool) 가을의 곰을... 2013.12.11 830
8 [Spring] VO 객체의 복사 가을의 곰을... 2013.11.26 4123
7 Java Delay (지연실행) 루틴 가을의 곰을... 2013.11.20 1172
6 Java Runtime시 Memory monitoring 가을의 곰을... 2013.11.19 685
5 Java Runtime시 CPU 모니터링 가을의 곰을... 2013.11.19 1069
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED