SpringOne2GX 2010 (4) Spring Roo 관련 발표들

작년 SpringOne에서도 Spring Roo에 대한 발표가 있었고, Google IO 등 다른 컨퍼런스에서도 꾸준히 Spring Roo는 홍보되었지만, 이번 SpringOne에서는 부쩍 그 비중이 높게 느껴졌습니다.

키노트가 있었던 주행사장에는 Spring Roo, Spring, SpringSource, Groovy, Grails의 5개의 로고가 조명으로 비추어져 있었습니다. Groovy-Grais의 관계처럼 Spring-SpringRoo의 관계를 연상시켜서, Spring의 대표 기술로 홍보하려는 전략으로 보였습니다.

_oJrmz3UkGJk/TMi7gUjZNII/AAAAAAAAC0A/hSU3s8E2XCk/s640/PA220055.JPG

_oJrmz3UkGJk/TMi7hDFNR_I/AAAAAAAAC0A/mWjWPk7bMPE/s912/PA220058.JPG

그리고 행사 기념품으로 나온 배찌에서도, Spring,SpringSource, Goorvy, Grails, Tomcat 등과 함께 Spring Roo의 로고가 박힌 것이 포함되었습니다. Security나 Batch같이 이미 현장에서 더 많이 쓰이고 있는 하위 프로젝트들도 있는데, Roo만 특별대우 한다는 느낌까지 들 정도였습니다. 다른 프레임웍 기술만과는 차별된 Spring만의 강점을 강조하기 위해서 Spring Roo가 전면에 나왔다고 생각됩니다. 스프링에서 지원하는 기술이 많아질 수록, API들을 전파하는 것도 쉽지 않을 것인데, Spring Roo를 통해서 사용할 수 있는 방법을 제공하면 코드가 자동생성 되므로 사용법이 더 간편해 보인다는 장점이 있을 것입니다. 그리고 Roo가 그렇게 새로운 API 전파 창구의 역할을 수행한다면 Roo를 직접 사용하지 않는 사람도 Roo가 생성해주는 코드를 샘플로 활용할 수도 있을 것입니다. Spring 3.0.4에 포함된 <mvc:default-servlet-handler/>가 Roo에 바로 반영된 것이나, Neo4j의 Roo addon등이 그 예입니다.

컨퍼런스가 끝나고 몇일 뒤에 바로 Spring Roo 1.1.0 버전이 발표되었는데, 이번 컨퍼런스에서 1.1.0에 포함된 기능을 소개하는 발표가 많았습니다.

OSGi, GWT, GAE-J 지원, 검색서버인 Apache Solr 지원, Database reverse engineering 등 많은 발전을 보여줍니다. 아래 포스트에 있는 지난 1년간의 Roo의 commit 내력을 시각화한 그림에서도 그런 변화가 표현되었습니다.

벤알렉스 아저씨가 열심히 개발을 하는 모습이 보이는군요. 이번 컨퍼런스에 벤알렉스는 참석하지 않았고, 벤알렉스가 진행하기로 한 발표의 일부는 로드존슨이 직접 진행했습니다. 아파서 못 왔다고는 말했는데, 1.1 출시를 얼마 안 앞두고 마무리 작업 때문에 못 온 것이 아닌가 하는 생각도 들었습니다.

저는 Roo 관련 세션 중에 Add-On 개발 관련 세션에 들어갔었습니다. 아래 URL에 있는 toString addon을 샘플소스로 보라고 했는데, toString을 Addon도 크게 쉬워보이지는 않았습니다.

가장 흥미로운 이야기는 Roo에서 앞으로 iBatis, Spring jdbc 같은 JPA 이외의 Persistence 기술도 지원하겠다는 것이였습니다.

그리고 Maven 멀티 프로젝트를 언제 지원할 수 있으냐는 질문이 세션 중에 나왔는데, 명확한 일정을 확답을 하지 못한 것으로 봐서는 가까운 시일 내에 가능해지지는 않을 것 같습니다.

Roo 관련 발표 자료들은 아래에 공개되어 있습니다.

Java에서 XML없이 SQL개발하기

변경 이력
  • 2015/01/21 : Eclipse에서 Groovy를 쓰기위한 plugin과 Maven 선언 부분을 현행화

  • 2013/01/25 : http://www.dpriver.com/pp/sqlformat.htm 의 캡쳐화면 추가 등

  • 2012/11/06 : Eclipse에서 Groovy를 쓰기위한 plugin과 Maven 선언 부분을 더 편한 방식으로 수정

요약하면, Java의 여러 프레임웍은 XML안에 SQL을 넣는 방식을 지원하는데, 줄바꿈이 있는 문자열을 편하게 쓰게 해주는 따옴표 세 개문법 (""")만 Java에 추가된다면 XML을 사용하는 목적을 충족시키면서도 XML로 인한 여러 단점들을 겪지 않아도 된다는 것입니다. 따옴표 세개는 Java에서 추가될 예정이지만, Groovy등에서는 이미 지원합니다. 지금이라도 SQL관리에만 Groovy를 쓰면 쿼리편집이 조금 더 편리해질만도 합니다.

XML로 SQL을 관리할 수 있는 Java framework

많은 Java 프레임웍들이 SQL구문들을 XML파일 안에서 코딩하게 되어 있습니다. 가장 대표적인 것이 iBatis입니다. 아래와 같이 SQL 구문, 파라미터를 운반하는 클래스, 쿼리의 결과가 담길 클래스를 XML안에 선언합니다.

    <select id="findByIsbn13" parameterClass="string" resultClass="book">
    SELECT  title,    author,     isbn13,     isbn10,     pages, content, imageUrl
    FROM book
    WHERE isbn13 = #isbn13#
    </select>
    <select id="findByTitle" parameterClass="string" resultClass="book">
    SELECT  title,    author,     isbn13,     isbn10,     pages, content, imageUrl
    FROM book
    WHERE title = #title#
    </select>

그리고 Hibernate와 JPA에서도 "named query"라는 개념으로, SQL을 따로 XML파일로도 뺄 수 있습니다. 아래는 Hibernate에서 SQL을 XML 파일안에 설정한 예입니다.

<sql-query name="findBookByIsbn13">
    <return alias="book" class="tdd.edu.domain.Book"/>
   SELECT  title,    author,     isbn13,     isbn10,     pages, content,  imageUrl
   FROM book
    WHERE isbn13 = :isbn13
 </sql-query>

Navie SQL과 Hibernate가 쓰는 HQL을 모두 .xml파일 안에 선언하는 것이 가능합니다. JPA를 사용해도 마찬가지로 JPA-QL, Native SQL을 Java에서 String으로 선언할 수도 있지만, XML 파일 안에 넣어도 됩니다.

Spring JDBC에서는 Jdbctemplate.execute 등의 메소드에서 SQL내용을 직접 문자열로 넘기게 되어있지만, Applicaton context 안에 쿼리를 저장해두고, 이를 사용하는 쪽에서 java.util.Properties 같은 객체를 Dependency Injection 받아서 사용하면 iBatis처럼 XML로 쿼리가 관리됩니다.

<util:properties id="bookSqls">
    <prop key="findByIsbn13">
   SELECT  title,    author,     isbn13,     isbn10,     pages, content,  imageUrl
   FROM book
    WHERE isbn13 = :isbn13
    </prop>
</util:properties>

그런데, Spring-jdbc나 Hibernate, JPA에서는 XML에 SQL을 저장하는 방식이 선택일 뿐이지만, iBatis 2.x에서는 반드시 XML안에 쿼리를 넣어야합니다. myBatis라고 이제 이름이 갈라진 iBatis 3.x에서는 Annotation으로 쿼리를 지정할 수 있어서, .java파일 안에 문자열로 SQL에 넣어도 되기는 합니다.

final String PERSIST_INFO =
“INSERT INTO simple_information(info_id, info_content) VALUES (#\{infoId}, #\{infoContent})”;

@Insert(PERSIST_INFO)
public int persistInformation(SimpleInformationEntity simpleInfo) throws Exception;

(예제는 http://java.dzone.com/articles/mybatis-formerly-called-ibatishttp://java.dzone.com/articles/mybatis-formerly-called-ibatis 에서)

그런데, 이런식으로 쿼리까지 Annotation으로 지정하는 것에 대해서는 의견이 분분할 것 같고, 개인적인 생각으로는 Spring jdbc나 Hibernate처럼 필요하면 직접 메소드 시그니처에 직접 SQL을 문자열로 넘기는 방식이 훨씬 더 자연스럽다고 보여집니다.

문제점은?

iBatis에서는 파라미터에 따라서 SQL이 다르게 구성되는 다이나믹 쿼리를 아래와 같이 선언합니다.

<isEqual property="writerSelected" compareValue="false">
  <isNotNull property="writerList">
    <iterate prepend=" AND writer in" property="writerList"
       open="(" close=")" conjunction=",">#writerList[]#
    </iterate>
  </isNotNull>
</isEqual>

if, for문 처럼 조건,반복문들이 XML로 표현되어 있습니다. 이는 절차적 프로그래밍을 SQL로 하게 되어서 아래와 같은 단점이 있습니다.

  • 조건, 반복문에 해당하는 태그 문법을 별도로 배워야함

  • 괄호"\{}"대신 열고 닫는 태그가 단락을 구분하기 때문에, 같은 조건,만복문을 코딩해도 Java 같은 범용언어에서보다 긴 코드가 나오게됨

  • Compile time의 validation범위가 더 줄어들게 됨. getter, setter로 참조하게 될 속성명에 오타가 있어도 직접 실행해봐야지 오타를 알 수 있음.

  • Java파일 밖이므로, Emma와 같은 Coverage 확인 툴로 실제 해당 절이 실행되었는지 확인할 수도 없음.

왜 SQL이 XML에 들어가게 되었을까?

직접 JDBC를 쓰면 Connection 관리와 Exception처리 등이 불편합니다. 그리고 JDBC의 Prepared Statement에서는 파라미터를 "?"를 표시하기 때문에 거기에 넘어가는 변수를 위치의 순서로 파악을 해야 합니다. ":id"와 같이 named parameter를 넣을 수 있다면 훨씬 쿼리의 가독성이 높아집니다. 그래서 그러한 Jdbc의 미흡한 점들을 보완해주는 프레임웍들이 각광을 받았습니다.

그런데, Connection이나 Excpetion처리의 편의성, named parameter의 활용하고 싶다고 해서 반드시 XML로 SQL를 관리해야 하는 것은 아닙니다. XML을 안 써도 되는 Spring의 JdbcTemplate에서도 그런 기능은 다 제공을 합니다.

SQL이 한 파일에 모여있지 않으면 DBA한테 쿼리 검수를 맡기거나, 여러 SQL을 한번에 수정할 일이 있을 때 불편해 지기도 합니다. 그러나 그런 점도 SQL 내용을 상수로 선언하는 .Java 파일을 따로 분리하면 해결할 수 잇습니다. SQL을 보관하는 .java파일에 *SqlMap.java와 같은 명명규칙을 부여하고, SQL 검수를 맡길 때 그 파일만 넘기면 됩니다.

또, 과거에는 .java파일 밖에 SQL이 있으면 SQL만을 수정을 했을 때는 다시 컴파일을 안 해도 된다는 장점이 강조되었습니다. 그러나, 요즘은 개발 PC에서는 Eclipse로, 서버에 배포할 때는 Ant나 Maven으로 빌드과정이 간편해졌고, 설정파일을 수정해도 파일의 복사를 위해 그런 배포과정을 똑같이 거쳐야 하므로, 컴파일이 필요없다는 것도 더이상 장점이 되지 못합니다.

XML에 SQL을 썼던 가장 핵심적인 이유는 .java파일에서는 줄 바꿈이 들어간 문자열을 편집을 하는 것이 불편했기 때문입니다. Java 파일에서는 문자열이 한 줄이 넘어가면 아래와 같이 + 기호를 이용해서 이를 연결해주는 방법 밖에 없습니다.

public static final String SELECT_BY_ISBN13 =
    "SELECT name , id "
    + "FROM user "
    + "WHERE isbn13 = :isbn13 ";

보통 Toad와 같은 DB client 도구에서 SQL을 작성해서 프로그램에 붙여넣기도 하고, 디버깅 중에는 프로그램 내에 있는 SQL을 반대로 DB client 툴에 붙여넣어서 실행해보기도 하는데, 그 때마다 저렇게 줄바꿈마다 "+"가 있다면 쿼리 편집이 많이 번거로워집니다. 그래서 XML파일 안에 SQL이 있으면 줄바꿈이 있는 긴 문자열도 똑같이 붙여넣을 수 있기 때문에, SQL을 개발하는 작업이 훨씬 편해집니다. 이렇게 SQL이 XML안에 들어가다보니 동적쿼리를 만들기 위한 조건,반복문과 각종 파라미터 매핑 클래스등까지 다 XML에 포함되어 버렸고, 앞에서 말한 부작용들이 점점 드러나기시작했습니다.

물론 Eclipse의 설정으로 .java 파일에 붙여넣기를 할 때는 "+"를 넣는 것과 같이 줄을 바꿀 때 필요한 작업들을 자동으로 할 수도 있습니다.

Windows-Preference-Java-Editor-Typing란의 "Escape text When pasting into a string literal"을 선택하고, 큰 따옴표 하나를 연 채 여러줄을 붙여넣으면, 알아서 줄이 바뀔 때는 " + " 기호를 넣어줍니다.

typing.png

그리고 반대로 이런 여러줄의 String을 DB 접속 툴에 붙여 넣을 때도 Sql-Squirrel이나 Toad 같은 툴에서는 그런 "+"와 같은 기호를 제거해 주는 기능이 있기도 합니다. 그리고 웹으로 이런 변환을 해주는 사이트도 있습니다. http://www.dpriver.com/pp/sqlformat.htm는 여러줄로 된 SQL문장을 Java, C#, Delphi, PHP등 다양한 언어의 문자열 선언으로 변환해줍니다.

sql-formatter.png

이렇게 편집을 도와주는 설정이나 도구들을 쓰더라도 중간 변환과정에서 몇번의 키 입력과 클릭이 필요해서 아예 그런 과정이 없는 것보다는 번거롭게 느껴집니다. 그래서 문자열 전체를 중간 변환과정없이 편집할 수 있는 XML에 SQL을 선언하기 시작했다고 생각합니다.

대안으로 Groovy로 따옴표 3개 문법을 이용해서 SQL 관리하기

Python, Groovy, Scala, Ruby에서 이미 지원하고 있는 '따옴표 3개짜리 문자열 선언’이 Java에도 포함된다면 여러줄의 문자열을 따로 편집하는 불편함을 겪지 않아도 됩니다. 아래와 같이 중간에 줄바꿈이 있어도 전체 SQL 내용이 끊어지지 않고 들어갑니다.

 public static final String SELECT_BY_ISBN13 =    """

  SELECT  title,    author,     isbn13,     isbn10,     pages, content,  imageUrl
   FROM book
   WHERE isbn13 = :isbn13

""";

이 따옴표 3개는 이미 JDK7에 포함되는 것이 제안된 상태인데, JDK에 포함될 실험적인 내용을 구현해보는 "Kijaro"라는 프로젝트에서는 Enhanced String Handling for Java라는 이름으로 이 명세를 다루고 있습니다. 그러나, 내년 중반기 쯤에 JDK7에 포함되어 발표될 예정인, java의 문법 개선내용을 주로 담고 있는 project coin에서는 아직 이를 찾아볼 수 없어서, 언제 Java에 반영될지는 아직 미지수입니다.

그렇다면 Java에서 따옴표 3개를 지원해주기 전까지는 계속 XML의 불편함을 감수해야 할까요? 저는 이미 이 문법을 지원하는 Groovy를 SQL관리 용도로 사용해볼만 하다고 생각합니다.

Groovy를 사용하기 위해서는 Eclipse와 Maven에 아래 설정만 해주면 됩니다.

1.Eclipse에서 Groovy plugin 설치

Update site:

Groovy-Eclipse Configurator for M2Eclipse도 설치가 필요한데, 2번 과정에서 pom.xml에 빨간 줄이 뜨면 Ctrl +1 을 눌러서도 설치할수 있습니다.

2.pom.xml에 Groovy를 compile할 수 있는 plugin과 runtime dependency 추가

Groovy를 Compile하는 Maven plugin은 GmavenGroovy-Eclipse Compiler Plugin For Maven이 있습니다. 후자가 Eclipse 최신버전의 me2와 더 나은 궁합을 보여줘서 컴파일을 할 때는 후자를 선택했습니다.

(1)Dependencies에 선언 추가

<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>2.4.5</version>
</dependency>

(2)build-plugins 에 아래 내용 추가

               <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <compilerId>groovy-eclipse-compiler</compilerId>
                    <meminitial>128m</meminitial>
                    <maxmem>512m</maxmem>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>utf-8</encoding>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.codehaus.groovy</groupId>
                        <artifactId>groovy-eclipse-compiler</artifactId>
                        <version>2.7.0-01</version>
                    </dependency>
                </dependencies>
            </plugin>

<plugin>

3.Groovy 사용

그리고 New→ groovy class를 선택하여서 java 파일 작성하듯이 클래스를 만듭니다.

new-groovy-class.png

Java 문법을 그대로 쓸 수 있으니 따옴표 3개를 쓸 수 있다는 점만 다르다고 생각해도 됩니다. 아래와 같이 .groovy 파일 안에 들어간 SQL이 색깔도 다르게 표시되어 비교적 가독성이 높게 표시되는 것을 확인할 수 있습니다.

roovy-sqls.png

그런 다음 DAO 등 SQL을 호출하는 쪽에서는 이 상수 문자열을 바로 참조합니다. 상수 선언이 되어 있으니 아래와 같이 오타를 쳐도 미리 알려주고, Ctrl + Space를 치면 자동완성도 됩니다.

typing-error.png

Dynamic SQL의 경우에도 직접 Java안에서 if문으로 써서 적어주면 됩니다. 아래와 같이 EclEmma 같은 도구로 coverage를 측정하면, 실제 실행되지 않은 조건분기도 눈으로 보입니다.

image

위의 코드를 Spring-JDBC를 사용했는데, 필요하다면 Hibernate나 apache commons DBUtils에서도 적용 가능한 방법입니다. 다만 Hibernate에서는 Criteria 같은 것을 이용하면 문자열로 길게 쓰는 쿼리가 많이 나오지는 않을 것으로 예상합니다. 그리고 myBatis(iBatis 3.0)의 Annotation으로 지정하는 쿼리 문자열에서도 똑같이 참조할 수 있습니다. static final String으로 선언된 문자열 상수만 쓰는 것이기 때문에 Groovy의 성능문제도 걱정할 필요가 없습니다.

단점과 꺼림직함도 물론 있습니다. 별도의 Eclipse plugin을 설치해야 하기 때문에, 이미 많은 수의 Plugin을 설치해서 Eclipse가 무겁다고 느껴지는 개발환경에서는 다소 부담이 될지 모른다는 점입니다. Groovy가 거의 java와 같은 문법을 지원하기는하지만, 이 문법 하나 때문에 새로운 언어를 도입하는 것이 과하다고 느끼시는 분들도 계실 것입니다. 이 문법을 위해서 Groovy의 다른 부분은 쓰지 않는데도 Runtime에 Groovy의 라이브러리를 올리는 것이 부담스러울 수도 있습니다. (따옴표 3개와 같은 Groovy만의 문법을 바이트코드로 변환하는 작업은 Compile time에 이루어지지만, Groovy로 선언한 객체는 groovy.lang.GroovyObject를 상속해야 하기 때문에, 다른 기능을 쓰지 않더라도 Runtime에서 추가 라이브러리가 필요합니다.) 그런 분들은 언제가 될지는 몰라도 Java에서 따옴표 3개를 지원하는 때까지 기다리는 것이 좋으실듯합니다.

SQL을 XML에 쓰는 것이 전혀 불편하지 않다고 느끼신다면 계속 하던대로 개발을 하면 되겠지만, 저는 위의 시도가 조금이라도 더 편한 개발환경을 만든다고 생각합니다.

SpringOne2GX 2010 (3) Spring and Java EE 6,Synergy or Competition?

논쟁에 응하다

2010년 10월 4일, http://www.theserverside.com 에는 이제 프레임웍의 시대는 가고, Spring에서 Java EE6로 옮겨야 한다는 주장을 담은 글이 올라왔고, 뜨거운 논쟁거리가 되었습니다.

  • Moving from Spring to Java EE 6: The Age of Frameworks is Over

    과거 Java EE 스펙의 부족함 때문에 Spring이 떠올랐지만, 이제 Java EE 6에서는 그런 것들을 다 극복을 했으니 Java EE6로 갈아타자는 내용이였습니다.
    이 글의 댓글에서부터 많은 반론이 올라왔고, 별도의 포스트로 쓰여진 아래와 같은 글들도 있었습니다.
  • http://raibledesigns.com/rd/entry/re_moving_from_spring_to

  • Spring vs. Java EE and Why I Don’t Care

    반론들에 포함된 공통적인 내용들은 아래와 같습니다.
  • 크게 볼 때, Spring과 Java EE6 는 비슷한 프로그래밍 모델을 가진 부분이 많다.Annotation을 @Stateless을 쓸지, @Component 쓸지는 프로젝트의 성공여부를 결정지을 만큼 중요한 차이는 아니다.

  • 그러나 Spring이 Tomcat, Jetty를 비롯한 더 많은 WAS에서 실행될 수 있다.

  • Batch, Integration, Spring Roo 같은 Java EE 스펙이 미치지 못하는 영역을 스프링에서는 제공하고 있다.

JavaEE 진영과 스프링 쪽의 갈등은 이미 뿌리가 깊습니다. 스프링의 시초가 된 코드가 있는 "Expert One-on-OneJ2EE Design and Development"책에는 EJB의 단점들이 날카롭게 지적되어 있고, 로드존슨과 유겐할러가 써서최초로 스프링을 언급한 책은 이름부터가 "Expert One-on-One J2EE Development withoutEJB"였습니다. "with Spring"도 아닌 "without EJB"인 것이죠. EJB를 적용했을 때의 실패경험 때문인지로드존슨은 EJB에 맺힌 것이 많아 보이고, 그런 것들이 앞의 저서들을 저술한 동기를 더 강하게 하지 않았을까하는 생각도듭니다. 그래도 J2EE 시절만 해도 표준 스펙은 OS나 DB서버와 같이, low level의 기술을 제공하는 컨테이너로인식이 되었는데, Java EE5 이후 실사용자 레벨의 컴퍼넌트 모델을 제공하기 시작하면서 JavaEE와 Spring은경쟁관계로 인식이 됩니다. 사실 스펙을 정의하는 JavaEE와 구현기술인 Spring을 동등하게 비교할 수도 없고,Spring에서도 JavaEE스펙을 지원하는 부분이 있습니다. 하지만 JavaEE스펙을 더 지지하는 진영에서는 Spring을사유기술일 뿐이고 JavaEE에 근거한 기술은 표준이라는 것을 계속 강조하면서 스프링을 공격하고 있습니다. 로드존슨은 이전에올린 블로그 포스트의 댓글에서 오픈소스 기술인 Spring을 사유(proprietary)라고 표현한 것에 대해서는 그것은 의심스러운 용어일 뿐이라고 말한적도 있습니다. (In any case, "proprietary" is a questionable term when we’retalking about open source. )

마침 SpringOne2GX 컨퍼런스 직전에 또다시 이런 논쟁이 일어난 것이 흥미로웠고, 저는 로드존슨이 키노트에서 바로 이에 대한 반론을 하지 않을까 하는 기대도 했었습니다. 그런데 로드 존슨은 핵심가치 같은 큰 그림에서의 스프링이 추구하는 바를 이야기했고, 이 논쟁에 대한 직접적인이야기는 하지 않았습니다.

바로 셋째날에 한 이 발표 "Spring and Java EE 6,Synergyor Competition?"에서 유겐할러가 그에 대한 구체적인 대답을 했습니다. 유겐할러는 최근 이런 논쟁들을 보고서 발표제목을 바꾸었다고 했고 이미 발표 몇시간 전 팀블로그에 아래와 같은 글을 올려서 이날 발표에서 말할 내용을 먼저 공개하기도했습니다. 저는 컨퍼런스가 끝난 후에야 이 글이 올라온 것을 보았는데, 발표에서 가장 뒷부분에 강조한 핵심내용이 정리되어있었습니다.

뒤에서 언급되겠지만, 간단히 정리하면 JavaEE6 환경에서도 스프링을 사용하면 플랫폼에서 제공되는 기술들을 일관된 프로그래밍과 설정 모델로 조화시키고, 더 많은 기술과 환경을 조합할 수 있으면서, Java EE7보다 더 빨리 발전하는 기능들을사용할 수 있는 것이라는 주장이였습니다.

사실 유겐할러는 이 날 발표와 비슷한 주제의 발표를 Java EE6 스펙의 확정 전에도 여러 번 한적이 있었습니다. 작년에 한 발표도 아래 링크에서 동영상으로 올라와 있습니다.

확정된 스펙을 가지고 이야기 한 것이 작년에 한 위의 발표와 달랐던 점이였습니다. 발표 중에 유겐할러는 Spring 쪽에서도오랫동안 EE 6 스펙의 확정을 기다렸다고 했고 EE6 확정 직후에 발표된 Spring 3.0에서도 EE6의 스펙을 많이지원하고 있음을 강조했습니다. 발표 제목 중에 포함된 "Synergy or Competition"중, "Synergy"를주장하고 싶었던 것이죠.

스프링의 역할

이 것은 이번 컨퍼런스 내내 키노트와 여러 세션에서 반복되어 언급된 말이였는데, 이 발표에서도 스프링을 사용하면 Java EE와 동등한 기능을쓰면서도 어플리케이션을 어느 서버에서도 배포될 수 있다는 것을 강조했습니다. 대상 플랫폼의 런타임에 적용되어서, 서비스추상화를 통해 공통적인 Programming model과 설정으로 개발을 할 수 있고, 전통적인 어플리케이션 서버 역할의 대안을 제공한다고 했습니다. Java EE 5의 스펙 중에서도 @PostConstruct, @PreDestoy ,@PersistenceContext, @PersistenceUnit , @Resource, @EJB, @TransationAttribute 등의 많은 Annotation을 지원하는데, 원하는 Semantics에 따라서 조합하고조화시켜(Mix & Match) 사용하라고 권장했습니다.

Java EE6 스펙 리뷰와 스프링의 지원

Java EE 프로파일

JavaEE프로파일은 EE 스펙 중 일부를 일부를 묶어서 구분하는 개념이였습니다. 가령 "Web Profile"이라고 하면 EE 스펙 중웹기술에 해당하는 Servlet, JSP, jSTL, JTA, JPA, EJB 3.1 Lite를 포함하는 것이라고 했습니다.그래서 벤더들이 초점을 두고 싶은 프로파일만 구현하고, 이미 지나간 잘 안 쓰이는 스펙에 대해서는 구현할 필요가 없이 그 분야의 프로파일에 대해서만 인증을 받을 수도 있다는 것입니다. 좋은 개념이기는 하나 현실적으로 웹프로파일만 구현하고 있는 벤더는아직까지는 없다고 말했습니다. 그런데 컨퍼런스가 끝난 뒤에 SIwpas라는 Web Profile만 구현한 서버를 우연찮게 발견하기도 했습니다.

그리고 스프링은 플랫폼에서 어떤 라이브러리가 제공되던지 상관 없이 사용할 수 있으므로 Java EE 프로파일은 스프링에 영향을 미치지는 않는 개념입니다.

Servlet 3.0

Servlet3.0 스펙에는 web.xml을 간결하게 해주는 "framework auto deployment"기능이 포함되고, 스프링도자동배포 기능 추가를 계획하고 있었습니다. 그리고 비동기적인 Http처리인 Comet은 Spring MVC에서 특별한request/reponse 형식으로 지원할 것이라고 했습니다. 당연히 이전 서블릿 스펙을 지원하는 서버에서의 하위호환성도유지할 것이라고 합니다.

JSF 2.0

JSF 2.0에는 UI 컴퍼넌트 부분에서 Ajax 지원와 페이지 선언 언어 등이 개선됩니다.. 그리고 스프링의 @Component와 @Value와 유사한 역할인@ManagedBean, @ManagedProperty 애노테이션이 있습니다. 스프링에서는 현재의 JSF지원 기능을 새 버전에맞추어 이어나가면서 3.1버전에서는 JSF 지원을 더 확장할 수 있도록 연구 중에 있다고 했습니다.

JPA 2.0

JPA2.0에는 쿼리 타임아웃, 표준화된 쿼리 힌트 등이 추가되었습니다. 역시 스프링에서는 현재의 JPA의 지원기능을 이어나가고,트랜잭션 관리에서 JPA 2.0의 모든 기능을 다 열어준다고 했습니다. 이미 Spring 3.0에서 Hibernate,EclipseLink, OpenJPA 등의 최신버전들과 이런 기능들을 쓸 수 있다고 합니다.

JSR-303 Bean Validation

JSF 2.0과 JPA 2.0에서 동시에 지원하는 스펙인데, Spring 3.0에는 SpringMVC의 Validation기능으로 사용할 수 있습니다.

JAX-RS

JAX-RS((Java™API for RESTful Web Services)는 REST방식의 웹요청 처리를 지원하는 표준 API입니다. 이미Jersey같이 JAX-RS를 지원하는 프레임웍에서 Spring을 자연스럽게 같이 연결해서 사용할 수 있습니다.

아래 코드에 @Path 아노테이션은 JAX-RS에서 정의된 것인데, 여기에 스프링의 @Autowired 를 같이 쓰고 있습니다.

@Path("widgets")
public class WidgetsResource {
    @Autowired
    private WidgetsService service;

    @GET  @Path("{id}")  @Produces("text/html")
    public String getWidget(@PathParam("id") int id){
     ...
    }

}

스프링 3.0에서도 Spring web MVC에서 나름대로의 스펙을 가진 REST지원 기능이 있습니다. 사실 위의 @Path와@PathParam 은 스프링의 @RequestMapping, @RequsetParams 아노테이션과 무척 유사해보이는, 비슷한프로그래밍 모델을 가지고 있습니다. 왜 스프링개발자들이 Spring MVC에서 JAX-RS를 바로 지원 안하고 나름대로의 스펙을만들었는지에 대해서는, 스프링소스의 팀 블로그를 통해서 밝힌 적이 있습니다.

기존의 JAX-RS 스펙을 바로 지원하는 것도 프로토타이핑해봤지만, 자연스럽게 않게 억지로 끼워 맞추는 듯한 방식이 나왔고, 결국Spring MVC사용자들에게 더 일관적이고 편한 방식을 제공하는 나름대로의 기능을 넣기로 결정했다는 것이였습니다. 결국JAX-RS와 Spring MVC는 REST 지원부분에서 겹쳐지는 부분이 생겼고, 이를 두고 스프링은 표준 스펙을 존중하지않는다는 비난을 하는 사람도 있었습니다.

이날 발표에서도 유겐할러는 Spring MVC는 근본적으로 MVC구조라서 View의 rendering을 하는 부분을 분리할 수 밖에 없고, 따라서JAX-RS 방식과 달라질 수 밖에 없다고 했습니다. 그리고 Jersey, RESTEasy, Restlet와같은 JAX-RS 구현체를 쓴다고 해도 Spring를 같이 쓸 수 있으니, 상황에 따라서 Spring MVC의 REST 기능이나JAX-RS 구현체를 모두 골라서 쓸 수 있다고 했습니다. UI페이지와 REST요청을 같이 처리해야하는 어플리케이션에서는Spring MVC로, 계층적인 리소스 구조처럼 REST 방식을 깊이까지 쓰는 어플리케이션이라면 JAX-RS 구현체를 쓰는것처럼 말이죠. 스프링은 언제나 그래왔듯이 선택에 대한 것이라는 말을 덧붙였습니다. (Spring is (and alwayswas) about choice),

그리고 JAX-RS 스펙은 Java EE6에서 독립적인 스펙이고, 다른웹스펙과도 연관관계가 없고, JSF와 프로그래밍 모델도 다르다고 유겐할러는 설명했습니다. 스프링은 그런 관련성이 있는 스펙들을 일관성 있게 묶어가고 있다는 것을 대비시켜 보이기 위해서 굳이 그런 언급을 한 것이 아닐까하는 생각도 들었습니다.

EJB 3.1

EJB3.1는 EJB 3.0에 singleton bean과 비동기 메소드 호출, JNDI 이름에 대한 Convention 제공 등의기능이 추가된 것입니다. 그리고 Local session Bean과 Singleton Bean만을 가지는 "EJB 3.1Lite"라는 것도 정의했습니다. 대부분의 서비스 객체가 원격호출이나 Object pooling이 없이 쓰이는 스프링의 방식과유사한 것인데, 과거의 그런 기능들이 대부분의 상황에서 오버엔지니어링 이였음을 다시 한번 인정하는 스펙 추가가 아닌가 하는생각이 들었습니다.

흥미로운 스펙은 컨테이너가 Lock 관리를 해준다는 것인데,(container-managed locking) 아래 코드에서 @Lock 아노테이션이 그런 역할을 하고 있습니다.

@Singleton @Startup
@DependsOn({"OhterBean1","OtherBean2"})
public class SharedService {
    private Data sharedData;
    @Lock(READ)
    public String returnSharedDataValue(){
        return this.sharedData;
  }
}

그리고 @Singleton이 붙은 클래스의 모든 메소드는 기본적으로 쓰기 잠금이 걸린다고 합니다.

유겐할러는 이런 스펙이 불필요할 상황이 많을 것이라고 했는데, ConcurrentHashMap 같이 thread-safe를 감안한자료구조를 선택할 수도 있고, synchronized나 volatile와 같은 키워드를 이용해서도 개발자가 그런 것들을 제어할수도 있다고 했습니다. 아뭏든 이런 Lock에 대한 디폴트 값을 제외하고는 @Singleton으로 설정되는 Bean은Spring이 관리하는 Bean과 상당히 유사해졌다고 말했습니다.

EJB가 컨테이너와 스프링과의 관계는 EJB3.1에서도 변하지 않는다고 했습니다. EJB 스펙은 나름대로의 Container에 의해서 지원되는 것이고, 필요하다면Spring에서 이를 접근할 수도 있는 것이죠. 그리고 EJB 3.1의 비동기 호출 스펙인 @Asynchronous은@Aysnc 로 Spring에  반영되어, 영향을 주었다고 했습니다.

JSR-299 Web Beans - CDI(Contexts and Dependency Injection)

"Webbeans"라는 이름으로 불렸던, 공식적으로는 "Contexts and Dependency injection"이라는 명칭으로붙여진 이 스펙과 스프링을 눌러싼 논쟁들은 표준 제정 과정 당시에도 가장 뜨거운 화제였었고, 이 날 발표에서도 개인적으로 가장관심이 가는 부분이였습니다. 이 스펙은 원래 JSF에서 Bean관리를 개선해서 JSF와 EJB를 잘 연결하는 역할을 위해만들어졌지만, 점점 확정된 스펙으로 발전해 나갔습니다.

CDI에서는 Type-safe DepedencyInjection, Interceptor, 이벤트 통지, Web conversation context 등의 풍부한Dependency Injection모델을 Annotation을 통해서 제공합니다. javax.decorator,javax.context, javax.inject, javax.event 등에 다양한 패키지에 나눠서 들어가 있고, 이미@Resource 등의 아노테이션이 있는 JSR-250이 담당하는 패키지인 javax.annotation,javax.interceptor 에도 추가되어 있습니다.

발표 슬라이드에는 나와있지 않지만,여기서 유겐할러는 CDI의 부정적인 면들도 언급을 합니다. EJB 3.1이 이 Component 모델을 뒤에서 떠받치는 역할을하지만, EJB와 CDI는 각각의 나름대로의 역할과 생명주기를 가지고 있는 그렇게 다른 Semantics가 섞이면 혼란을 불러일으킬 수 있다고 합니다. 그런 혼란에서 오는 어려움은 그 날 발표 슬라이드나 어떤 슬라이드 내에서는 표현될 수 없고, 실제로개발을 해보고 디버깅을 해서 겪어봐야지 알 수 있다고 했습니다.

그리고 이 스펙은 스프링의 프로그래밍 모델과겹쳐지는 부분이 있고, Spring 3.1에서는 스프링의 원래 프로그래밍 모델을 더 발전시켜서 JSR-299과 표현력과 기능을능가하겠다고 했습니다. 이미 Spring에서도 다양한 scope의 빈을 정의할 수도 있고, Stateful한 웹어플리케이션을개발할 수 있다는 Spring Web Flow가 따로 프로젝트로 나와있지만, Spring 3.1에서 추가될Conversation Management는 그런 것들을 더욱 일반화 시켜서 Spring Core 쪽으로 끌어올리겠다는 의미로해석됩니다.

Spring on Java EE6

앞에서 언급했듯이, 유겐할러는 발표의 뒷부분에서 최근 논쟁에 대한 대답들을 정리해서 설명해줍니다.

첫째, Java EE6 서버는 스프링이 참조하는 미들웨어를 제공하는 좋은 실행환경이라는 것입니다. Java EE6 서버에서제공하는 Servlet 3.0, JSF 2.0, JPA 2.0 등의 플랫폼 기술들은 스프링은 소비자로서 사용할 수 있다고했습니다. 그리고 다소 Java EE 스펙과 중복이 될 수 있는 부분인 EJB나 CDI관련 부분은 Java EE6 기능의일부분에 불과하다는 것이였습니다. GlassFish에서는 코드량 기준으로 5% 정도만 차지할 뿐이고, 아마 5%가 넘는 다른기능들도 사용하지 않고 있는 것이 많을 것이라고 했습니다.

둘째, 스프링을 사용하면 필요에 따라더 넓은 기술을 선택할 수 있기 때문에 그것이 Java EE6 서버를 사용하는 자연스러운 방식이라느 것입니다. JSF대신 Wicket이나 GWT, EE clustering대신 Coherence 등을 쓸 수 있고, , 스프링의 jar파일은 4MB바이트 정도로 크지 않아서 이 용량이 문제가 되는 경우는 거의 없다고 했습니다.

셋째,Java EE6 서버 중 GlassFish만이 지금 GA(Generally Available)버전 이상인 상태이고, JBoss나WebSphere는 아직 안정화된 버전이전이기 때문에 Java EE 6서버만을 선택한다면 실행환경에 제약이 있다고 했습니다.스프링은 Tomcat 5,6,7버전, Java EE5 서버, 그리고 Google App Engine 같은 것에서도 돌아갈 수있고, Java EE5를 쓰면서도 스프링을 사용하면 Hibernate 3.6 같은 구현체를 써서 EE6 스펙을 쓰는 선택도가능하다고 했습니다. 다양한 플랫폼 환경에서 스프링이 조율역할을 한다는 것입니다. 실제로 최근에 올라온 CDI - A Major Risk Factor in Java EE 6라는 글에서는 아직 안정화되지 않은 버전의 서버에서 CDI를 적용하다 어려움을 겪은 이야기가 있습니다.

넷째, EE6는 2009년 초 기술환경에 맞춘 것이고, 그 후로 지금까지 분산캐쉬, Cloud 등 많은 기술들이 중요하게떠올랐는데, 그런 기술들을 스프링을 통해서 서버를 업그레이드할 필요없이 훨씬 빠른 시기에 지원받을 수 있다는 것입니다. 이번컨퍼런스 내내 NoSQL, 분산 캐쉬, Social network 같은 다양한 주제들이 강조된 것도 그런 강점을 강조하기 위한전략으로 보였습니다.

정리하자면 Spring과 Java EE6는 잘 맞는 궁합이면서 중복되는역할의 라이브러리 용량은 현실적으로 문제될 것이 없으며, 스프링으로 더 다양한 기술과 실행환경을 활용하면서 일관된 프로그래밍모델로 개발할 수 있다는 것이 핵심 주장이였습니다.