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

황제낙엽 2007.03.22 06:59 조회 수 : 123 추천:86

sitelink1  
sitelink2  
sitelink3  
extra_vars6  
출처따위 없슴

 

Spring JDBC추상화는 굉장히 큰 결과들을 포함하는 애플리케이션의 경우에도 표준 JDBC보다 낮은 성능상의 오버헤드를 가진다.

좀더 높은 레벨의 JDBC추상화는 org.springframework.jdbc.object패키지내에 있다. 이것은 핵심 JDBC콜백 기능에 내장되지만 자바 객체처럼 모델화된 쿼리, update또는 저장 프로시저등의 RDBMS작동내 API를 제공한다. 이 API는 내가 직관적이고 크게 유용하게 본 JDO쿼리 API에 의해 부분적으로 영감을 받았다.

사용자 객체를 반환하는 쿼리 객체는 이것처럼 보일것이다.

 

class UserQuery extends MappingSqlQuery {

  public UserQuery(DataSource datasource) {
    super(datasource, "SELECT * FROM PUB_USER_ADDRESS WHERE USER_ID = ?");
    declareParameter(new SqlParameter(Types.NUMERIC));
    compile();
  }

  // Map a result set row to a Java object
  protected Object mapRow(ResultSet rs, int rownumthrows SQLException {
    User user = new User();
    user.setId(rs.getLong("USER_ID"));
    user.setForename(rs.getString("FORENAME"));
    return user;
  }

  public User findUser(long id) {
    // Use superclass convenience method to provide strong typing
    return (UserfindObject(id);
  }
}

 

 

이 클래스는 다음처럼 사용될수 있다.

 

User user = userQuery.findUser(25);

 

 

그러한 객체는 종종 DAO내부의 내부(inner)클래스이다. 그것들은 하위클래스가 일반적이지 않은 어떤것이 아니라면 threadsafe한 상태이다.

org.springframework.jdbc.object패키지내 다른 중요한 클래스는 StoredProcedure클래스이다. Spring은 하나의 비지니스 메소드와 함께 자바 클래스에 의해 프록시된 저장된 프로시저를 가능하게 한다. 만약 당신이 좋아한다면 저장 프로시저의 사용에 의존적인 것으로 부터 당신의 애플리케이션 코드에 자유로울수 있도록 하는것을 의미하도록 저장 프로시저를 구현하는 인터페이스를 정의할수 있다.

Spring 데이터접근 예외구조는 체크되지(런타임) 않은 예외에 기반하고 있다. 다른 프로젝트에서 Spring을 이용한 작업이 나는 올바른 선택이라고 확신을 한다.

데이터접근 예외는 언제나 복구가능한것은 아니다. 예를 들어 만약 우리가 데이터베이스에 연결을 할 수 없다면 특정 비지니스 객체는 문제점들 가운데 작업을 가능하게 할것 같지 않다. 잠재적인 예외는 낙관적인 락위반이지만 모든 애플리케이션이 낙관적인 락을 사용하는것은 아니다. 현명하게 다룰수 없는 치명적인 예외를 잡기 위한 코드를 작성하는데 집중하는것은 언제나 나쁘다. 서블릿또는 EJB와 같은 가장 높은 수준의 핸들러에 그것들을 전하는것은 언제나 좀더 선호된다. 모든 Spring데이터접근 예외는 DataAccessException의 하위클래스이다. 그래서 우리가 모든 Spring 데이터접근 예외들을 잡도록 선택한다면 우리는 다음처럼 쉽게 할수 있다.

만약에 우리가 체크되지 않은 데이터접근 예외로부터 복구하기를 원한다면 우리는 여전히 그렇게 할수 있다. 우리는 단지 복구가능한 상황만을 다루기 위해서 코드를 작성할수도 있다. 예를 들면 우리가 낙관적인 락위반만이 복구가능하다고 생각할때 우리는 다음처럼 Spring DAO내 코드를 작성할수 있다.

 

try {
  // do work
}
catch (OptimisticLockingFailureException ex) {
  // I'm interested in this
}

 

 

Spring 데이터접근 예외가 체크된다면 우리는 다음의 코드를 작성할 필요가 있을것이다. 우리는 어떻든 이것을 작성하는것을 선택할수 있다는 것을 알라.

 

try {
  // do work
}
catch (OptimisticLockingFailureException ex) {
  // I'm interested in this
}
catch (DataAccessException ex) {
  // Fatal; just rethrow it
}

 

 

첫번째 예제를 위한 하나의 잠재적인 객체화는 컴파일러가 두번째또한 적용한 잠재적인 복구가능한 예외를 강제적으로 다룰수 없다. 우리가 기본적인 예외(DataAccessException)를 잡기위해서 강요하기 때문에 컴파일러는 하위클래스(OptimisticLockingFailureException)를 위해 체크를 강요할수 없을것이다. 그래서 컴파일러는 복구가능하지 않은 문제를 다루기 위한 코드를 작성하도록 우리에게 강요할것이지만 복구가능한 문제를 다루기 위해 우리에게 강요하는것은 도움을 주지 못한다.

Spring의 체크되지 않은 데이터접근 예외 사용은 많은면에서 일관적이다. JDBC는 체크된 예외를 사용하는 몇몇 데이터접근 API중 하나이다. 예를 들면 TopLink와 JDO가 체크되지 않은 예외를 사용한다. Hibernate는 3.x버전에서 체크된 예외를 체크되지 않는 예외로 교체한다.

Spring JDBC는 여러가지 방법으로 당신을 도울수 있다.

  • 당신은 JDBC를 사용하기 위해 finally블럭을 다시 사용할 필요가 결코 없다.
  • Connection누설은 지난일이 될것이다.
  • 당신은 전체적으로 좀더 적은 양의 코드를 작성할 필요가 있을것이고 그 코드는 필요한 SQL에 집중을 하게 될것이다.
  • 당신은 분명하지 않은 에러코드를 가지고 작업을 수행하기 위해 당신의 RDBMS문서를 통해 조사할 필요가 없을것이다. 당신의 애플리케이션은 RDBMS정의 에러 핸들링 코드의 의존적일 필요가 없을것이다.
  • 어떠한 persistence기술을 사용하든지 당신은 특정 데이터접근 API에 의존하는 비지니스 로직없이 DAO패턴을 구현하는것이 쉽다는 것을 알게 될것이다.
  • 당신은 BLOB핸들링과 결과를 반환하는 저장프로시저를 호출하는것과 같은 향상된 점에서 향상된 이식가능성으로 부터 이득을 얻을수 있을것이다.

여기서 우리는 실질적인 생산성 획득과 적은 수의 버그를 보게 될것이다. 나는 JDBC코드를 쓰는것을 몹시 싫어한다. 지금 나는 부수적인 JDBC자원 관리보다 내가 수행하고자 하는 SQL문에 집중할수 있다는 것을 안다.

Spring의 JDBC추상화는 당신이 Spring의 다른 부분을 사용하길 강요하지 않는다면 당신이 바랄때 독자적으로 사용될수도 있다.

O/R 맵핑 통합

물론 종종 당신은 관계적인 데이터접근보다 O/R맵핑을 사용하길 원할것이다. 당신의 전체 애플리케이션 프레임워크는 이것또한 지원해야만 한다. 게다가 Spring은 Hibernate(2.x와 3.x버전)와 JDO(1.x와 2.x버전), TopLink와 다른 ORM제품들을 통합한다. 이것의 데이터접근 구조는 어떠한 데이터접근 기술과도 통합이 되도록 한다. Spring과 Hibernate는 특별히 인기 있는 조합이다.

당신은 왜 직접적으로 ORM만 사용하지 않고 ORM제품에 Spring을 같이 사용하는가.? Spring은 다음과 같은 중요한 가치를 추가한다.

  • 세션 관리. Spring은 효과적이고 쉬우며 Hibernate또는 TopLink세션과 같은 작업의 안전한 핸들링을 제공한다. ORM툴을 사용한 관련 코드는 대개 효과적이고 적절한 트랜잭션 핸들링을 위해 같은 "Session"객체를 사용할 필요가 있다. Spring은 선언적인 방법이나 AOP메소드 인터셉터 접근법 또는 자바코드 레벨에서 "template"래퍼 클래스의 명시적인 방법을 사용해서 투명한 생성과 현재 쓰레드에 세션을 바인딩할수 있다. 게다가 Spring은 ORM기술의 많은 사용자에게 영향을 받은 이슈들에 대한 문제를 해결했다.
  • 자원 관리. Spring애플리케이션 컨텍스트는 경로와 Hibernate SessionFactories, JDBC 데이터소스 그리고 다른 관련 자원의 설정을 다룰수 있다. 이것은 관리와 변경을 쉽도록 만들어준다.
  • 통합된 트랜잭션 관리. Spring은 선언적인 방법이나 AOP메소드 인터셉터 또는 자바코드 레벨에서 "template"래퍼 클래스의 명시적인 방법을 사용해서 당신의 ORM코드를 랩핑하도록 한다. 이런 경우에 트랜잭션 의미는 당신을 위해서 다루어지고 예외의 경우에 적당한 트랜잭션 핸들링이 처리된다. 밑에서 논의되는 것처럼 당신의 ORM관련코드에 영향을 미치는 것 없이 다양한 트랜잭션 관리자를 사용하고 바꿀수 있는 이익을 가진다. 추가된 이익처럼 JDBC관련 코드는 ORM코드와 함께 트랜잭션적으로 완전히 통합될수 있다. 이것은 ORM내에서 구현하지 않더라도 기능적으로 매우 유용하다.
  • 위에서 서술된 예외 랩핑. Spring은 ORM레이어로부터 예외들을 포장할수 있고 선호하는 예외를 추상화된 런타임 예외들로 변환을 할수 있다. 이것은 복구할수 없고 지겨운 반복적 catches/throws코드와 예외 선언 없이 선호하는 레이어에서만 대부분의 퍼시스턴스 예외를 다룰수 있도록 한다. 당신은 여전히 필요한 어느곳이든지 예외들을 잡고 다룰수 있다. JDBC예외들은 같은 구조로 변환하고 일관적인 프로그램 모델내에서 JDBC와 함께 같은 작업을 수행할수 있다는 것을 의미한다.
  • 업체 락(lock-in)을 피하기. ORM솔루션은 다른 특징에 다른 성능을 가진다. 그리고 모든 솔루션에 완벽하게 적합한 하나의 값은 없다. 대안으로 당신은 당신의 ORM툴을 사용해서 구현하기 위해 적합하지 않은 어떠한 기능을 발견하게 될것이다. 게다가 이것은 당신의 데이터접근 객체 인터페이스의 툴 기반의 구현으로 부터 당신의 구조를 분리한다. 만약 당신이 기능, 성능 또는 다른 어떠한 사항의 이유로 다른 구현물로 교체를 해야 할 필요가 있다면 Spring은 다른것과 쉽게 교체하도록 해준다.Spring의 ORM툴의 트랜잭션과 예외의 추상화는 IoC접근법으로 당신에게 매퍼/DAO객체가 데이터접근 기능을 구현하는것에서 쉽게 교체를 하게 해준다. 이것은 ORM툴의 어떠한 능력의 감소없이 당신의 애플리케이션의 어떤 범위에서 모든 ORM기반 코드를 격리하기 쉽게 해준다. PetClinic샘플 애플리케이션은 JDBC, Hibernate, TopLink 그리고 Apache OJB를 통해 Spring이 제공하는 이식가능성 이득을 설명한다.
  • 테스팅의 쉬움. Spring의 Inversion of Control접근법은 Hibernate세션 factory, 데이터소스, 트랜잭션 관리자 그리고 매퍼 객체 구현물 같은 자원의 구현과 위치를 교체하는것을 쉽게 만든다. 이것은 퍼시스턴스 관련 코드의 각각의 일부분을 분리하거나 테스트를 좀더 쉽게 만든다.

Spring은 데이터접근을 위한 혼합-대응(mix-and-match)접근법을 돕는다. 몇몇 ORM업체의 목적에도 불구하고 ORM이 많은 경우에 가치있는 제품이라고 하더라도 모든 문제를 위한 솔루션이 아니다. Spring은 JTA사용없이 퍼시스턴스 접근법과 혼합하고 대응하더라도 일관적인 구조, 트랜잭션 전략을 가능하게 한다.

ORM이 이론적으로 적합하지 않는 경우에 Spring의 단순화된 JDBC만이 선택할수 있는 것이 아니다. iBATIS SQL Maps에 의해 제공되는 "mapped statement"접근법도 가치가 있어보인다. 이것은 쿼리 결과로부터 맵핑된 객체의 생성을 자동으로 하는 동안 SQL에서 높은 레벨의 제어를 제공한다. Spring은 SQLMaps와 통합된다. Spring의 PetStore샘플 애플리케이션은 iBATIS통합을 설명한다.

트랜잭션 관리

데이터접근 API를 추상화는것은 충분하지 않다. 우리는 트랜잭션 관리에 대해서 생각해 볼 필요가 있다. JTA는 명백한 해결법이지만 이것은 직접적으로 사용하기에는 성가신 API이다. 그리고 EJB CMT가 트랜잭션 관리를 위한 단지 이론적인 옵션이라고 많은 J2EE개발자들이 느끼고 있다. Spring은 이것을 바꿨다.

Spring은 트랜잭션 관리를 위해 자신만의 추상화를 제공한다. Spring은 이전을 위해 다음의 사항들을 사용한다.

  • 콜백 템플릿을 통한 프로그램 트랜잭션 관리는 직접적으로 JTA를 사용하는 것보다 좀더 쉬운 JdbcTemplate과 유사하다.
  • 선언적인 트랜잭션 관리는 EJB CMT와 유사하지만 EJB컨테이너는 필요없다. 실제로 우리는 Spring의 선언적인 트랜잭션 관리능력이 EJB CMT의 몇몇 유일하고 중요한 이득과 함께 호환가능한 수퍼셋(superset)이다.

Spring의 트랜잭션 추상화는 JTA나 다른 어떠한 트랜잭션 관리 기술에 묶이지 않는 유일한 것이다. Spring은 트랜잭션 내부구조를 참조하여 애플리케이션 코드를 분리하는 트랜잭션 전략의 개념을 사용한다.

왜 당신은 이것에 대해서 주의해야 하는가.? 모든 트랜잭션 관리를 위해 JTA가 가장 좋은 답이 아닌가.? 만약 당신이 하나의 데이터베이스를 사용하는 애플리케이션을 작성한다면 당신은 JTA의 복잡함을 사용할 필요가 없다. 당신은 XA트랜잭션이나 두 단계의 커밋에 흥미롭지는 않을것이다. 당신은 이러한 것들을 제공하는 높은 성능의 애플리케이션 서버 조차도 필요하지 않을것이다. 하지만 반면에 당신은 다중 데이터소스로 작업을 수행해야 할때 당신의 코드를 다시 쓰고 싶지는 않을것이다.

JDBC나 Hibernate트랜잭션을 직접적으로 사용함으로써 JTA의 오버헤드를 피할 결심을 했다고 생각해보라. 만약 당신이 다중 데이터소스와 작업할 필요가 있다면 당신은 트랜잭션 관리 코드를 쪼개야만 하고 그것을 JTA트랜잭션으로 교체해야만 한다. 이것은 그다지 매력적이지 않고 대부분의 J2EE에 전역적인 JTA트랜잭션을 사용하길 추천한다. Spring트랜잭션 추상화를 사용하는 것은 어쨌든 당신은 JDBC나 Hibernate보다 JTA를 사용하기 위해 Spring을 다시 설정해야만 한다. 이것은 코드상의 변경이 아닌 설정상의 변경이다. 게다가 Spring은 당신에게 애플리케이션 규모를 크게 하는것만큼 작게 하는 것도 가능하게 한다.

AOP

2003년 이후 엔터프라이즈 관련 사항에 EJB에 의해 할당된 트랜잭션 관리와 같은 AOP솔루션을 적용하는 것이 굉장히 큰 관심사항이 되었다.

Spring의 AOP지원의 첫번째 목표는 POJO를 위해 J2EE서비스를 제공하는 것이다. 어쨌든 Spring AOP는 벤더 락(lock in)의 위험 없이 애플리케이션 서버사이에 이식가능한 장점을 가진다. 이것은 웹이나 EJB컨테이너와 잘 작동한다. 그리고 WebLogic, Tomcat, JBoss, Resin, Jetty, Orion 그리고 많은 다른 애플리케이션 서버와 웹 컨테이너에서 성공적으로 사용되었다.

Spring AOP는 메소드 인터셉션(interception)을 지원한다. 제공되는 AOP의 핵심적인 개념은 다음과 같다.

  • 인터셉션(Interception) : 사용자 정의 행위는 어떠한 인터페이스나 클래스에 대해서 메소드 호출전이나 후에 추가된다. 이것은 AspectJ 용어에서 "around advice"와 유사하다.
  • 소개(Introduction) : advice는 추가적인 인터페이스를 구현하기 위한 객체를 야기한다는 것을 명시한다. 이것은 복잡한 상속상태에 이르게 될수 있다.

역자주 : AOP개념을 모두 설명할수는 없지만 기본적으로 AOP에 의해 해당 메소드가 호출되는 부분을 joinpoints라고 하고 joinpoints에서 호출되는 코드들을 advice라고 부른다. joinpoints들의 묶음을 pointcuts라고 부른다. 그리고 advice와 pointcuts를 모아 Aspects라고 지칭한다.

  • 정적이고 동적인 pointcuts : 인터셉터가 위치해야만 하는 곳에 프로그램 수행내 point를 정의하라. 정적 pointcuts는 메소드 시그너처를 의미하고 동적 pointcuts는 그들이 값을 구하는 지점에 메소드 인자로 간주될수 있다. pointcuts는 다른 애플리케이션과 코드 컨텍스트내 적용될 표준적인 인터셉터를 가능하게 하는 인터셉터로 부터 개별로 정의된다.

Spring은 상태유지(adviced객체당 하나의 인스턴스)와 비상태유지(모든 advice를 위한 하나의 인스턴스) 인터셉터 모두 지원한다.

Spring은 필드 인터셉터를 지원하지 않는다. 이것은 신중한 디자인 결정이다. 나는 언제나 필드 인터셉터가 encapsulation을 어긴다고 느낀다. 나는 OOP와 충돌이 나는것보다 보완물처럼 AOP를 생각하는것을 선호한다. 나는 만약 5년이나 10년안에 우리가 AOP가 애플리케이션 디자인의 가장 상위부분을 차지한다 하더라도 놀라지 않을것이다.

Spring은 런타임시 동적 프록시(인터페이스가 존재하는 곳에)나 CGLIB바이트 코드 생성자(클래스의 프록시를 가능하게 하는)를 사용해서 AOP를 구현한다. 둘다 애플리케이션 서버나 단독환경에서 잘 작동한다.

Spring은 AOP친화 인터페이스(http://www.sourceforge.net/projects/aopalliance)를 구현한 첫번째 AOP프레임워크이다. AOP프레임워크 사이의 인터셉터의 상호작용을 허락하는 인터페이스를 정의하기 위해 표현된다.

TheServerSide에서 진행중이고 논쟁된 이러한 종류의 가로채기(interception)은 "true AOP"이다. 나는 이것이 이렇게 불리는 것에 대해 특별히 걱정하지 않는다. 단지 실제로 유용할수 있다. 나는 이것을 declarative middleware" 라고 부르고 싶다. Spring AOP의 생각은 간단하고 local비상태유지 세션빈에 가벼운 대안이다. 획일적인 EJB컨테이너의 필요가 없어지고 당신이 필요한 서비스와 함께 당신 자신만의 컨테이너를 빌드하도록 한다. 우리는 어떠한 충고(advising)와 모든 POJO를 추천하지 않는다. 그래서 추천되는 것을 분명하게 하기 위해 local SLSBs로 유추한다. (어쨌든 EJB와는 달리 당신은 선호하는 지점에 드문 시나리오내 훌륭하게 얻어진 객체를 위해 Sping AOP을 적용하는것이 자유로울 것이다.)

Spring은 클래스로더보다 인스턴스에서 객체를 통지하기 때문에 이것은 다른 advice로 같은 클래스의 다중 인스턴스를 사용하거나 통지된 인스턴스와 함께 통지되지 않은 인스턴스를 사용하는 것이 가능하다.

아마도 Spring AOP의 가장 공통적인 사용은 선언적인 트랜잭션 관리이다. 이것은 위에서 서술된 TransactionTemplate추상화위에서 빌드되고 어떠한 POJO위에서 선언적인 트랜잭션 관리를 전달할수 있다. 트랜잭션 전략에 의존적으로 기법을 이해하는것은 JTA, JDBC, Hibernate 또는 다른 어떠한 트랜잭션 관리를 제공하는 API가 될수 있다.

Spring은 Spring애플리케이션으로 AspectJ의 aspect를 포함하는 것처럼 하기 위한 기능을 제공하는 AspectJ와 통합한다. Spring 1.1이후로 Spring IoC컨테이너를 사용해서 AspectJ 의 aspect의 의존성 삽입이 가능해졌다. 게다가 AspectJ의 aspect는 Spring관리 객체에 의존될수 있다. 곧 나오는 AspectJ 5와의 통합은 annotation기반 pointcut에 기반으로 하여 Spring을 사용하는 어떠한 POJO에 의존성을 삽입하는 능력을 제공하기 위한 AspectJ로 좀더 놀랍다.

Spring은 클래스로더보다 인스턴스에서 객체를 통지하기 때문에 이것은 다른 advice로 같은 클래스의 다중 인스턴스를 사용하거나 통지된 인스턴스와 함께 통지되지 않은 인스턴스를 사용하는 것이 가능하다.

아마도 Spring AOP의 가장 공통적인 사용은 선언적인 트랜잭션 관리이다. 이것은 위에서 서술된 트랜잭션 추상화를 빌드하고 어떠한 POJO위에서 선언적인 트랜잭션 관리를 전달할수 있다. 트랜잭션 전략에 의존적으로 기법을 이해하는것은 JTA, JDBC, Hibernate 또는 다른 어떠한 트랜잭션 관리를 제공하는 API가 될수 있다.

Spring의 선언적 트랜잭션 관리는 EJB CMT와 다음과 같은 차이점이 있다.

  • 트랜잭션 관리는 어떠한 POJO에 적용될수 있다. 우리는 비지니스 객체가 인터페이스를 구현하는것을 추천하지만 이것은 프로그래밍 실제상황의 문제이고 프레임워크에 의해 강요되지 않는다.
  • 프로그램적인 롤백은 Spring트랜잭션 API을 사용해서 전통적인 POJO내 달성될수 있다. 우리는 이것을 위해 ThreadLocal변수들을 사용해서 정적 메소드를 제공한다. 그리고 당신은 롤백을 확실히 하기 위해 EJBContext와 같은 컨텍스트 객체를 상속할 필요가 없다.
  • 당신은 선언적으로 "롤백 규칙들"을 정의할수 있다. EJB가 잡히지 않은 애플리케이션 예외(체크되지 않은 예외와 다른 Throwables에 대해서만)에서 트랜잭션을 자동적으로 롤백하는것에 반하여 애플리케이션 개발자는 어떠한 특정 예외에서 트랜잭션을 롤백하기를 원한다. Spring트랜잭션 관리는 당신에게 예외와 하위 클래스가 자동 롤백을 야기하는 것을 선언적으로 정의하도록 허락한다. 디폴트 행위는 EJB와 같지만 당신은 체크되지 않은 예외처럼 체크된 예외에서도 자동적으로 롤백을 수행할수 있다. 이것은 Spring트랜잭션 API에서 의존성(EJB프로그램적인 롤백은 EJBContext에서 수행되는 것처럼)을 생성하는 프로그램적인 롤백을 위한 필요성을 최소화하는 중요한 이익을 가진다.
  • 만약 그들이 트랜잭션 기반구조를 참조함으로써 제공된다면 Spring트랜잭션 추상화 지원 savepoints을 참조하기 때문에 Spring의 선언적인 트랜잭션 관리는 EJB CMT에 의해 명시된 전달 모델에 추가적으로 내포된 트랜잭션을 지원할수 있다. 예를 들면 만약 당신이 오라클에서 JDBC작업을 수행한다면 당신은 Spring을 사용해서 선언적인 내포된 트랜잭션을 사용할수 있을것이다.
  • 트랜잭션 관리는 JTA에 묶여있지 않다. 위에서 설명된 것처럼 Spring트랜잭션 관리는 다른 트랜잭션 전략과도 작동할수 있다.

물론 이것은 Spring AOP의 사용으로 애플리케이션 정의 aspect를 구현하는것이 가능하다. Spring의 기능보다 AOP개념으로 당신의 안정적인 레벨에 의존적으로 이것을 하는것을 선택할수 있다. 하지만 이것은 매우 유용하다. 성공적인 예제는 우리가 볼때 다음을 포함한다.

  • 사용자 정의 보안 인터셉션, 요구되는 보안 체크의 복잡함은 표준적인 J2EE보안 구조의 능력을 넘어선다.
  • 개발 기간동안 사용을 위해 aspect를 디버깅하고 프로파일링하기
  • 한 지점에서 일관적인 예외 핸들링 정책을 적용하는 Aspects
  • 유별난 시나리오에서 관리자나 사용자들에게 경고하기 위해 이메일을 보내는 인터셉션

애플리케이션정의 aspect는 많은 메소드를 통해 반복적인 코드를 위한 필요성을 제거하는 강력한 방법이 될수 있다.

Spring AOP는 Spring BeanFactory개념과 함께 투명하게 통합된다. Spring BeanFactory에서 나온 객체를 얻는 코드는 이것이 통지되든지 되지 않든지 알 필요가 없다. 어떤 객체처럼 계약은 인터페이스 객체 구현을 함으로써 정의될 것이다.

다음의 XML은 AOP프록시를 정의하는 방법을 그리고 있다.

 

<bean id="myTest"
  class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="proxyInterfaces">
    <value>org.springframework.beans.ITestBean</value>
  </property>
  <property name="interceptorNames">
    <list>
      <value>txInterceptor</value>
      <value>target</value>
    </list>
  </property>
</bean>

 

 

참조내 사용되거나 BeanFactory의 getBean()메소드에 의해 반환되는것처럼 bean의 타입이 proxy인터페이스에 의존할지라도 bean정의의 클래스는 항상 AOP프레임워크의 ProxyFactoryBean이라는것에 주의하라. ProxyFactoryBean의 "interceptorNames"프라퍼티가 문자열의 리스트를 가져온다.(bean이름이 bean참조보다 더 사용되어야만 한다. 만약 프록시가 "프로토타입"이라면 싱글톤 bean정의보다 상태유지 인터셉터의 새로운 인스턴스가 생성될 필요가 있다.). 위 리스트내 이름은 인터셉터나 pointcuts가 될수 있다. 리스트내 "target"값은 자동적으로 "호출 인터셉터"를 생성한다. 이것은 프록시 인터페이스를 구현하는 factory내 bean의 이름이다. 이 예제내 myTest빈은 bean factory내에서 다른 bean처럼 사용될수 있다. 예를 들면 다른 객체는 >ref<요소와 Spring IoC에 의해 셋팅될 참조들을 통해 참조될수 있다.

만약 당신이 XML메타데이터없이 트랜잭션적인 프록시를 조정하기 위해 Java5.0 annotations를 사용하거나 Spring factory내 정의된 많은 빈즈들을 위한 일관적인 프록시 전략을 적용하기 위한 XML의 일부를 사용하는 능력을 사용하는것과 같은 AOP프레임워크의 강력한 능력이 필요하지 않다면 좀더 간결하게 프록시를 셋업하는 많은 방법이 있다.

BeanFactory사용없이 프로그램적으로 AOP프록시를 생성하는 것은 가능하다. 비록 이것이 좀더 드물게 사용이 되더라도.

 

TestBean target = new TestBean();
DebugInterceptor di = new DebugInterceptor();
MyInterceptor mi = new MyInterceptor();
ProxyFactory factory = new ProxyFactory(target);
factory.addInterceptor(0, di);
factory.addInterceptor(1, mi);
// An "invoker interceptor" is automatically added to wrap the target
ITestBean tb = (ITestBeanfactory.getProxy();

 

 

우리는 이것이 자바코드로 부터 애플리케이션을 묶는 작업을 구체화하는 가장 좋은 방법이고 AOP는 예외가 아니라고 믿는다.

나는 기업용 서비스를 달성하기 위해 EJB를 사용하는 것의 대안으로 AOP의 사용이 유력하게 증가할 것이라고 믿는다. 이것은 Spring의 중요한 중심점이 될것이다.

MVC 웹 프레임워크

Spring은 강력하고 설정가능한 MVC웹 프레임워크를 포함한다.

Sprign의 MVC모델은 Struts로부터 가져온것은 아니지만 Struts의 그것과 상당히 유사하다. Spring컨트롤러는 모든 클라이언트에 대해 한개의 인스턴스만이 수행되는 멀티쓰레드방식의 서비스 객체인 Struts Action과 유사하다. 어쨌든 우리는 Spring MVC가 Struts를 뛰어 넘어서 몇몇 중대한 장점을 가진다고 믿는다. 예를 들면

  • Spring은 컨트롤러와 자바빈 모델 그리고 뷰들 사이에 매우 분명한 분리를 제공한다.
  • Spring MVC는 당신의 액션과 폼객체를 견고한 상속을 강요하는 Struts와는 달리 매우 유연하다. Spring MVC는 전체적으로 인터페이스에 기초를 둔다. 게다가 Spring MVC프레임워크의 모든 부분에 대해서 당신 자신의 인터페이스내 플러깅(plugging)을 통해 설정가능하다. 물론 우리는 구현 옵션처럼 편리한 클래스를 제공하기도 한다.
  • WebWork처럼 Spring은 많은 요청의 핸들링으로 공통적으로 행위를 분배하기 쉽도록 만드는 컨트롤러 만큼 인터셉터를 제공한다.
  • Spring MVC는 진실로 뷰에 관용적이다. 당신이 Velocity, XLST또는 다른 뷰관련 기술들을 사용하길 원하지 않는다면 당신은 JSP를 사용하도록 강요하지 않는다. 만약 사용자 정의 뷰 기법 즉 예를 들어 당신 자신만의 템플릿 언어를 사용하길 원한다면 당신은 그것과 통합하기 위해 Spring View인터페이스를 쉽게 구현할수 있다.
  • Spring컨트롤러는 다른 객체처럼 IoC를 통해 설정가능하다. 이것은 테스트를 쉽게 만들고 Spring에 의해 관리되는 다른 객체들과 함께 멋지게 통합된다.
  • Spring MVC웹티어는 디스패처 서블릿의 컨트롤러의 명시적인 의존성과 강요된 견고한 상속을 피함으로써 Struts 웹티어보다 전형적으로 테스트하기 더 쉽다.
  • 웹 티어는 비지니스 객체 레이어의 가장 상위의 작은(thin)레이어가 된다. 이것은 좋은 실제상황을 만들어준다. Struts와 다른 전용 웹프레임워크는 당신을 당신의 비지니스 객체의 구현을 하도록 만든다. Spring은 당신의 애플리케이션의 모든 티어(tier)를 위해 통합된 프레임워크를 제공한다.

Struts 1.1에서 처럼 당신은 당신이 Spring MVC애플리케이션내 필요한만큼의 많은 디스패치(dispatcher)서블릿을 가질수 있다.

다음의 예제는 간단한 Spring컨트롤러가 같은 애플리케이션 컨텍스트내 정의된 비지니스 객체에 접근하는 방법을 보여준다. 이 컨트롤러는 handleRequest()메소드내에서 구글(google)검색을 수행한다.

 

public class GoogleSearchController implements Controller {

  private IGoogleSearchPort google;

  private String googleKey;

  public void setGoogle(IGoogleSearchPort google) {
    this.google = google;
  }

  public void setGoogleKey(String googleKey) {
    this.googleKey = googleKey;
  }

  public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    String query = request.getParameter("query");
    GoogleSearchResult result =
      // Google property definitions omitted...

      // Use google business object
      google.doGoogleSearch(this.googleKey, query,
        start, maxResults, filter, restrict,
        safeSearch, lr, ie, oe);

    return new ModelAndView("googleResults""result", result);
  }
}

 

 

프로토타입내에서 이 코드는 Spring FactoryBean에 의해 반환되는 IGoogleSearchPort(이것은 GLUE웹서비스 프록시이다)로 부터 얻어진다. 어쨌든 Spring IoC는 웹서비스 라이브러리에 기초를 둠으로써 이 컨트롤러를 분리시킨다. 인터페이스는 밑에서 논의되는 일반적인 자바객체, 테스트 스텁(stub), 모의(mock) 객체 또는 EJB프록시에 의해 동등하게 구현될수 있다. 이 컨트롤러는 어떠한 리소스 룩업(검색)을 포함하지 않는다. 코드를 제외하곤 어떠한 것도 이것의 웹 통합을 지원하기 위해 필요하지 않다.

Spring은 데이터바인딩, 폼, 마법사 그리고 다른 복잡한 워크플로우를 위한 지원도 제공한다.

만약 당신의 요구사항이 정말 복잡하다면 당신은 다른 어떠한 전통적인 웹 MVC프레임워크보다 웹흐름을 위한 높은 수준의 추상화를 제공하는 강력한 프레임워크인 Spring Web Flow를 고려해봐야 할것이다.

Spring MVC프레임워크에 대한 좋은 소개는 Thomas Risberg의 Spring MVC튜토리얼(http://www.springframework.org/docs/MVC-step-by-step/Spring-MVC-step-by-step.html)이다. 또한 "Spring프레임워크를 사용한 웹 MVC(http://www.springframework.org/docs/web_mvc.html)."도 보라.

만약 당신이 좋아하는 MVC프레임워크를 사용하는게 좋다면 Spring의 레이어화된 하부구조가 당신이 당신의 MVC레이어 없이 Spring의 나머지를 사용하도록 허락할 것이다. 우리는 Struts, WebWork 또는 웹티어내 Tapestry나 JSF를 사용하지만 미들티어 관리와 데이터접근을 위해 Spring을 사용하는 Spring 사용자들이 있다.

EJB들을 구현하기

만약 당신이 EJB를 사용하기로 선택한다면 Spring은 EJB구현과 EJB에 대한 클라이언트측 접근의 중요한 이익을 제공할수 있다.

이것은 지금 비지니스 로직을 EJB외관 뒤 POJO로 리팩터하기 위한 가장 좋은 상황처럼 간주된다. (EJB가 컨테이너에 크게 의존적인것과 격리수준내에서 테스트가 어려운것처럼 다른 것 사이에 이것은 비지니스 로직의 단위 테스팅을 쉽게 만든다.) Spring은 EJB jar파일내 포함된 XML문서에 기반하여 자동적으로 BeanFactory를 로드함으로써 이것을 쉽게 만드는 세션빈과 메시지빈을 위해 편리한 슈퍼클래스들을 제공한다.

이것은 비상태유지 세션 EJB가 획득되고 협력자(collaborator)를 사용하는것을 의미한다.

 

import org.springframework.ejb.support.AbstractStatelessSessionBean;

public class MyEJB extends AbstractStatelessSessionBean
      implements MyBusinessInterface {
  private MyPOJO myPOJO;

  protected void onEjbCreate() {
    this.myPOJO = getBeanFactory().getBean("myPOJO");
  }

  public void myBusinessMethod() {
    this.myPOJO.invokeMethod();
  }
}

 

 

MyPOJO가 인터페이스라고 가정하자. 구현클래스와 원시프라퍼티와 협력자와 같은 어떠한 설정을 요구한다. 이것은 XML bean factory정의내 숨겨진다.

우리는 Spring에게 표준적인 ejb-jar.xml 배치서술자내 ejb/BeanFactoryPath라고 명명된 환경변수정의를 통해 XML문서를 로드하는 곳을 알린다. 마치 다음처럼:

 

<session>
  <ejb-name>myComponent</ejb-name>
  <local-home>com.test.ejb.myEjbBeanLocalHome</local-home>
  <local>com.mycom.MyComponentLocal</local>
  <ejb-class>com.mycom.MyComponentEJB</ejb-class>
  <session-type>Stateless</session-type>
  <transaction-type>Container</transaction-type>

  <env-entry>
    <env-entry-name>ejb/BeanFactoryPath</env-entry-name>
    <env-entry-type>java.lang.String</env-entry-type>
    <env-entry-value>/myComponent-ejb-beans.xml</env-entry-value></env-entry>
  </env-entry>
</session>

 

 

myComponent-ejb-beans.xml파일은 클래스패스로부터 로드될것이다. 이 경우에는 EJB jar파일의 가장 상위에서 각각의 EJB는 자신만의 XML문서를 정의할수 있다. 그래서 이 기법은 각각의 EJB jar파일마다 여러번 사용이 될수 있다.

Spring 슈퍼클래스는 setSessionContext() 와 ejbCreate()와 같은 EJB생명주기 메소드를 구현하고 Spring onEjbCreate메소드의 구현을 개발자에게 남겨주었다.

EJB3.0이 공개초안(public draft)상태에서 유효할때 우리는 그러한 환경내에서 좀더 다양한 DI를 제공하기 위한 Spring IoC 컨테이너의 사용을 위한 지원을 제공한다. 우리는 데이터접근 API처럼 Spring과 함께 JSR-220 O/R맵핑 API를 통합할것이다.

EJB 사용하기

Spring은 또한 EJB를 구현하는 것 만큼 그것을 사용하기 쉽도록 만든다. 많은 EJB애플리케이션은 서블릿 로케이터(locator)와 비지니스 위임(delegate)패턴을 사용한다. 클라이언트 코드 도처에 JNDI룩업을 써대는 것보다 훨씬 좋다. 하지만 그들의 일반적인 구현은 분명한 단점을 가진다. 예를 들면 :

  • EJB를 사용하는 전형적인 코드는 서블릿 로케이터와 비지니스 위임 싱글톤에 의존한다. 이것은 테스트를 힘들게 한다.
  • 서비스 로케이터 패턴의 경우에 비지니스 위임없이 사용된다. 애플리케이션 코드는 여전히 EJB home에서 create()메소드를 호출함으로써 종료되고 결과 예외를 처리한다. 게다가 이것은 EJB API에 묶이고 EJB프로그래밍 모델의 복잡함을 남긴다.
  • 비지니스 위임 패턴의 구현은 EJB에서 같은 메소드를 간단히 호출하는 수많은 메소드를 써야만 하는 명백한 코드중복의 결과를 야기한다.

이러한 그리고 다른 이유로 전통적인 EJB접근은 생산성을 제거하고 암시적인 복잡함이라는 결과를 만든다.

Spring은 코드가 없는 비지니스 위임을 소개함으로써 나가보겠다. Spring으로 당신은 실제값을 추가하지 않는 한 다른 서비스 로케이터, 다른 JNDI룩업 또는 손으로 직접 코딩한 비지니스 위임내 중복된 메소드를 쓸 필요가 결코 없을것이다.

예를 들면 우리가 로컬 EJB를 사용하는 웹 컨트롤러를 가지고 있다고 생각을 하자. 우리는 가장 좋은 상황을 끄집어 내고 EJB비지니스 메소드 인터페이스 패턴을 사용할 것이다. 그래서 EJB의 local 인터페이스는 비 EJB스펙 비지니스 메소드 인터페이스를 확장한다. (이것을 수행하기 위해 가장 중요한 이유중에 하나가 local인터페이스와 bean구현클래스내 메소드 시그너처사이 동기화를 확실하게 하는것이다.). 이 비지니스 메소드 인터페이스를 MyComponent라고 부르자. 물론 우리는 local home인터페이스를 구현하고 SessionBean과 MyComponent비지니스 메소드 인터페이스를 구현할 bean구현 클래스를 제공할 필요가 있을것이다.

Spring EJB접근으로 EJB구현물로 우리의 웹티어 컨트롤러를 걸 필요가 있는 자바코딩은 우리의 컨트롤러에 MyComponent타입의 setter메소드를 보이는 것이다. 이것은 다음처럼 인스턴스 변수처럼 참조를 저장할 것이다.

 

private MyComponent myComponent;

public void setMyComponent(MyComponent myComponent) {
  this.myComponent = myComponent;
}

 

 

우리는 어떠한 비지니스 메소드내 인스턴스 변수를 계속적으로 사용할수 있다.

Spring은 이것처럼 XML bean정의 엔트리를 통해 자동적으로 나머지 작업을 수행한다. LocalStatelessSessionProxyFactoryBean은 어떠한 EJB를 위해 사용될수 있는 일반적인 factory bean이다. 이것은 Spring에 의해 자동적으로 MyComponent타입으로 형변환 될수 있다.

 

<bean id="myComponent"
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">

  <property name="jndiName" value="myComponent" />
  <property name="businessInterface" value="com.mycom.MyComponent" />
</bean>

<bean id="myController"
  class "com.mycom.myController"
>
  <property name="myComponent" ref="myComponent" />
</bean>

 

 

이 장면뒤에 많은 마법같은 것들이 있다. Spring AOP프레임워크의 특별함, 비록 당신이 결과를 즐기기 위해 AOP개념과 함께 강요하지 않는다. "myComponent" bean정의는 EJB를 위해 비지니스 메소드 인터페이스를 구현하는 프록시를 생성한다. EJB local home은 시작시 캐시된다. 그래서 단지 하나의 JNDI룩업만 있을 뿐이다. 각각의 EJB호출은 프록시가 local EJB에서 create()메소드를 호출하고 EJB에서 관련된 비지니스 메소드를 호출한다.

myController bean정의는 프록시를 위해 컨트롤러 클래스의 myController프라퍼티를 셋팅한다.

EJB접근 기법은 대량의 명백한 애플리케이션 코드를 만든다.

  • 웹 티어 코드는 EJB사용에서 어떠한 의존성도 가지지 않는다. 만약 우리가 POJO나 모의객체 또는 다른 테스트 스텁으로 EJB참조를 대체하길 원한다면 우리는 간단히 자바코드의 변경없이 myComponent bean정의를 변경할수 있다.
  • 우리는 JNDI룩업의 한줄의 코드나 우리의 애플리케이션의 일부처럼 다른 EJB연관 코드를 쓰지 않아도 된다.

우리는 단지 org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean factory bean을 통해 remote EJB에 같은 접근법을 적용할수 있다. 어쨌든 우리는 remote EJB의 비지니스 메소드 인터페이스에 RemoteExceptions을 숨길수는 없다. 


번호 제목 글쓴이 날짜 조회 수
공지 (확인전) [2021.03.12] Eclipse에서 Spring Boot로 JSP사용하기(Gradle) 황제낙엽 2023.12.23 0
공지 [작성중/인프런] 스프링부트 시큐리티 & JWT 강의 황제낙엽 2023.12.20 6
» Spring프레임워크 소개문서 (2) 황제낙엽 2007.03.22 123
22 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