그 동안 몰랐던 서버 사이드 자바스크립트 이야기, Part 2: 자바로 만든 자바스크립트 엔진, 리노
|
 |


김영후 zerohoo.kim@gmail.com
웹 개발 기술과 매킨토시에 관심이 많은 스물여섯 살 개발자다. 능력과 시간을 전부 창조하는 작업에만 쓸 수 없을까 궁리 중이며 현재 병역 특례 업체에서 플렉스를 주로 다루고 있다.
|
|
 |
난이도 : 중급 2008년 10월 21일 |
|
연재순서
1회(2008년9월): 다시 보는 자바스크립트의 역사
2회(2008년10월): 자바로 만든 자바스크립트 엔진, 리노
[오픈 developerWorks]는 여러분이 직접 필자로 참가하는 코너입니다.
Part 1에선 자바스크립트의 여러 특징을 형성한 자바스크립트의 역사에 대해 주로 알아보았다. Part 2에선 실제 서버 사이드에서 사용할 수 있는 자바스크립트 기술들을 알아보고, 그 중 가장 널리 사용되는 리노(Rhino)를 살펴보자.
서버 사이드 자바스크립트의 이점
요즘은 굳이 다수의 최종 사용자를 타겟으로 한 웹 사이트가 아니라도 대부분의 서버 사이드 애플리케이션이 그 인터페이스를 웹으로 구현하는 일이 많다. 이런 경우 개발자에게 가장 고통스러운 부분 중 하나는 웹에서 사용하는 자바스크립트 언어일 수 있는데, 그것은 사실 자바스크립트 언어 자체의 문제이기보다는 C++, 자바, 파이썬, 루비 같은 언어에서 자바스크립트라는 언어로 '생각의 전환'이 필요하기 때문이다. PHP 코드를 스무 줄 쓰고, 이와 연동하는 50여 줄의 자바스크립트 코드를 짜는 일처럼, 이러한 생각의 전환은 전문 웹 개발자라면 하루에도 몇 번씩 비일비재하게 요구된다. Ajax 기술을 많이 사용하고 클라이언트에서 점점 더 '리치(rich)'함을 요구하는 요즘에는 서버 사이드에서 요구되는 작업보다 자바스크립트를 이용해야 하는 클라이언트에서의 작업이 더욱 더 늘어나고 있다.
서버 사이드에서 자바스크립트를 이용할 경우 얻을 수 있는 가장 큰 이득은 이것이다. 개발을 하면서 하나의 언어만을 사용할 수 있다는 것. 뇌의 기어를 계속 이 언어 저 언어로 변경하지 않아도 된다는 것. Part 1에서 알아봤듯이 자바스크립트는 범용적인 목적으로 사용하더라도 다른 주류 언어들에 비해 결코 수준 낮은 언어가 아니다.
자바스크립트 엔진과 서버 사이드 자바스크립트
최근 구글 크롬 브라우저가 출시되면서 이 브라우저에서 사용하는 자바스크립트 엔진이 큰 주목을 받은 것 처럼, 서버 사이드 자바스크립트 역시 다양한 엔진이 있다. 이것들은 모두 같은 자바스크립트 언어에 대한 구현이지만 실제 동작하는 자바스크립트 버전, 서버 플랫폼, 사용 가능한 라이브러리, 성능 등에서 차이를 보인다.
세상에서 가장 널리 사용되는 자바스크립트 엔진은 마이크로소프트의 제이스크립트(Jscript) 엔진이다. 이 엔진이 가장 많은 사용자를 확보한 인터넷 익스플로러에서 사용되기 때문인데, 마이크로소프트의 IIS 서버에 내장되어 ASP 기술의 스크립트 언어로도 많이 사용되었다(ASP는 비록 사장되고 있지만 실제로 가장 대중화된 서버 사이드 자바스크립트 기술이라고 볼 수 있다).
브랜든 에이크에 의해 최초로 개발된 자바스크립트 엔진인 스파이더 몽키(SpiderMoneky)는 현재 오픈 소스가 되어 모질라 재단에서 관리한다. 무엇보다 파이어폭스(Firefox) 웹 브라우저에서 사용되는 자바스크립트 엔진으로 널리 알려져 있으며 어도비 애크로뱃(Adobe Acrobat)이나 야후 위젯 기능에서도 스파이더 몽키를 자바스크립트 엔진으로 이용한다. 소스가 공개된 자바스크립트 엔진이므로 어느 용도로도 쓸 수 있지만 mod_js나 Jaxer[1] 같은 기술은 스파이더 몽키를 아파치(Apache) 웹 서버에 내장하여 서버 사이드 웹 언어로 사용할 수 있도록 해준다.
스파이더 몽키는 오랫동안 개발되고 많은 벤더에 의해 검증 받은 자바스크립트 엔진이지만 한 가지 아쉬운 점은 표준화된 라이브러리가 불충분하다는 것이다. 이는 무엇보다 '브라우저 내에서' 동작해야 하는 자바스크립트 언어의 초기 목적이 가지는 제약이기도 하며, 역사적으로 여러 다른 구현이 있어 표준화된 공통 라이브러리를 제공하기 어려웠다. 실제로 마이크로소프트의 ASP나 넷스케이프의 라이브스크립트(LiveScript)는 상당수의 라이브러리를 연동해 사용할 수 있었지만 이 엔진들이 동작하는 플랫폼에 제한적인 것이었다.
라이브러리가 부족하지만 언어 자체의 강점을 잘 가지고 있는 언어들, 혹은 라이브러리가 충분히 있지만 강력하지 못한 엔진 기술로 성능 문제를 겪는 언어들이 줄곧 새로운 기회를 발견하는 땅이 있다. 그것은 바로 자바가상머신(JVM)이며 리노는 그 JVM에서 구현된 자바스크립트 엔진이다.
리노의 역사
리노의 개발 역시 넷스케이프에서 시작되었다. 리노가 개발된 1997년, 넷스케이프에선 자사의 웹 브라우저 전체를 자바로 새로 구현하려는 '자바게이터(Javagator)' 프로젝트를 진행하고 있었다. 다소 황당하게 들리는 이 프로젝트는 곧 중단되었지만 이 브라우저를 위해 개발되었던 '자바로 만든 자바스크립트 엔진'은 살아남았다. 몇몇 기업은 이 자바스크립트 엔진을 사용하기 위해 넷스케이프에 돈을 지불했고, 넷스케이프 역시 자체적으로 이 엔진을 사용해왔다. 그리고 1998년 이 엔진은 유명한 자바스크립트 책인 'JavaScript: The Definitive Guide'[2]의 표지를 따서 리노라는 이름으로 공개되었으며 역시 모질라 재단이 관리하고 있다.
리노는 넷스케이프에서 구현된 최초의 자바스크립트 엔진인 스파이더 몽키를 본따 개발되었으며, 사실상 '자매 엔진'이라 볼 수 있으며 두 엔진에 대한 업그레이드는 비슷하게 이루어진다. 리노는 자바의 모든 라이브러리를 사용할 수 있으며 표준 라이브러리가 절실히 부족한 자바스크립트는 이 점에서 큰 의미를 지닌다.
최신 버전 리노는 자바스크립트 1.7[3]을 지원하며 자바 1.6에는 따로 설치를 하지 않아도 javax.script 패키지에 포함되어 있다.
자바 라이브러리라는 압도적인 지원을 얻은 리노는 사실상 현재 서버 사이드에서 가장 안정적이고 유망한 자바스크립트 엔진으로 평가 받고 있으며 AppJet, 10gen, 구글과 같은 기업에서 적극적으로 사용하고 있다.
설치와 실행
모질라 홈페이지의 http://www.mozilla.org/rhino/download.html에서 리노 최신판을 받을 수 있다. 압축을 풀면 소스-테스트 파일들과, 예제를 볼 수 있는데 실제 작업을 위해선 js.jar 파일만 자바 클래스패스(classpath)에 추가하면 된다. 설치 후 콘솔에서 'java org.mozilla.javascript.tools.shell.Main'을 입력했을 때 아래와 같은 셸을 볼 수 있다면 정상으로 설치된 것이다.
리노가 제공하는 이 셸은 파이썬이나 루비의 셸과 마찬가지로 개발을 진행하면서 테스트나 프로토타이핑에 유용하게 사용할 수 있다. 자바 라이브러리를 탐험하는 데도 유용하다. 앞으로 이 셸을 켜놓고 진행하자.
리노에서 자바 사용하기
앞서 말했듯이 리노는 모든 자바 클래스에 접근하여 사용할 수 있고, 자바가 할 수 있는 일을 모두 할 수 있다. 이를 위해 리노는 자바의 패키지에 접근 가능한 Packages라는 최상위(top-level) 변수를 제공한다. 이 Packages의 프로퍼티들은 자바 패키지들이다. 셸에서 다음을 실행해 보자.
js> Packages.java
[JavaPackage Java]
js> java.io.File
[JavaClass java.io.File]
|
리노는 java 패키지에 대해선 바로 접근 가능한 최상위 변수 java를 제공하기 때문에 Packages는 생략할 수 있다. 매번 전체 패키지 이름을 쓰는 것은 번거로우니 importPackage를 사용하자.
js> importPackage(java.io)
js> File
[JavaClass java.io.File]
|
자바 클래스에 접근이 가능하면 다음과 같이 객체를 만들고 메서드를 호출할 수 있다. 물론 정적(static) 메서드도 상식적으로 호출이 가능하다.
js> new java.util.Date()
Fri Oct 10 07:09:53 KST 2008
js> f = new java.io.File("test.txt")
test.txt
js> f.exists()
false
js> java.lang.Math.PI
3.141592653589793
|
기존 언어 플랫폼 위에 구현된 '손님 언어'에게 항상 요구되는 기능 중 하나가 바탕이 되는 '주인 언어'를 확장할 수 있느냐다. 리노의 경우 쉽게 말해 미리 정의된 자바의 클래스나 인터페이스를 자바스크립트로 확장할 수 있느냐인데, 리노는 JavaAdapter라는 기술을 사용해 이를 지원한다. 우선 클래스를 상속받아 보자.
var obj = {
speak: function() { print("Hello World!") },
run: function() { this.speak(); }
}
var t = new JavaAdapter(java.lang.Thread, obj);
t.start();
"Hello World!"
|
객체 리터럴을 사용해 두 개의 프로퍼티를 가지는 객체 obj를 만들었다. 그리고 JavaAdapter를 사용해 상속할 자바 클래스를 지정해주고 그 구현부가 될 객체를 obj로 하여 상속을 구현한 새 객체 t를 만들었다. t는 java.lang.Thread를 상속받아 구현한 것이기 때문에 start 메서드를 이용해 스레드를 구동할 수 있다.
다음은 자바 인터페이스를 자바스크립트에서 구현해보자. 역시 객체 리터럴을 사용하여 구현하고자 하는 인터페이스가 요구하는 메서드를 구현한다.
obj = { run: function () { print("\nrunning"); } }
|
이 자바스크립트 객체를 원하는 인터페이스 생성자를 이용해 인터페이스에 대한 구현 객체로 만들 수 있다.
r = new java.lang.Runnable(obj); //자바 인터페이스 구현
t = new java.lang.Thread(r); //자바 클래스를 이용해 새 객체 생성
t.start();
"running"
|
자바스크립트에서 인터페이스를 상속 받을 때 내부적으로 리노는 인터페이스를 상속 받는 객체에 대한 바이트코드를 만들고 그 객체에 대한 호출을 자바스크립트 객체로 넘겨주는데 이러한 일을 JavaAdapter가 담당한다. 위의 예제들은 자바의 인터페이스 구현과 클래스 상속을 그대로 흉내낸 것 같지만 자바스크립트 객체를 만든 후에 상속과 구현을 정하는 것은 자바스크립트의 동적인 특성을 잘 보여주는 부분이다. 자바나 타 언어에선 어느 객체가 어떤 인터페이스를 구현할지, 혹은 부모 객체를 상속할지를 객체 '선언'에서 지정해야 하지만, 여기서 보이는 기법은 일반적인 자바스크립트 객체를 만든 후에 원하는 때에 상속을 만들 수 있기 때문에 더 동적인 프로그래밍이 가능하다. 런타임에서 상황에 따라 상속을 지정하는 일종의 메타프로그래밍이라고 볼 수 있다.
문자열과 배열
상속이나 확장과 달리 주인 언어에서 구현된 손님 언어가 주인 언어의 기능과 겹치는 일도 있을 수 있다. 대표적인 것이 대부분의 언어에서 지원하는 문자열과 배열이다. JVM 위에서 자바가 아닌 타 언어로 코딩을 하다 보면 종종 '이 문자열이 자바 문자열인가? 아니면 파이썬(혹은 자바스크립트) 문자열인가? 아니면 둘 모두를 지원하는가?' 등의 의문이 들 때가 있을 것이다. 이러한 경우 그 구현에서 제공하는 규칙을 잘 알아두어야 혼란에 빠지지 않고 개발할 수 있다. 우선 리노는 자바 배열을 지원하는 특별한 문법을 전혀 지원하지 않는다. 다음과 같이 꼭 리플렉션 클래스를 사용해야만 자바 배열을 만들 수 있다.
a = java.lang.reflect.Array.newInstance(java.lang.String, 2);
|
문자열에 대해서도 자바 문자열과 자바스크립트 문자열을 똑같이 취급하지 않고 구분한다.
javaString = new java.lang.String("Rhino");
jsString = "Rhino";
javaString == jsString;
javaString.length();
jsString.length;
|
하지만 문자열의 경우 자바 문자열을 요구하는 자바 메서드에 매개변수로 넣을 경우 자동으로 변환이 일어난다. 또한 자바 문자열에서 자바 String 클래스에 없는 메서드를 호출할 경우 자바스크립트 String.prototype의 프로퍼티를 참조한다. 다음 예를 보자.
자바에서 자바스크립트 사용
리노는 자바스크립트에서 자바 라이브러리를 사용할 수 있게 해주지만 반대로 자바에서 자바스크립트 코드를 불러오고 실행할 수도 있다.
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
public class CallRhino {
public static void main(String[] args) {
Context cx = Context.enter();
Scriptable scope = cx.initStandardObjects();
// var foo = {a: "hello"}
Scriptable foo = cx.newObject(scope);
foo.put("a", foo, "hello");
scope.put("foo", scope, foo);
// fetch and print foo: prints ({a:"hello"})
Object result = cx.evaluateString( scope, //글로벌 스코프
"foo.toSource()", //수행할 자바스크립트 코드
"", //수행할 파일 이름
1, null);
System.out.println(cx.jsToJava(result, String.class));
Context.exit();
}
}
|
Context 객체는 리노가 실행될 스레드의 정보를 가지고 있다.
활용
리노는 어디에서 사용할 수 있을까? 우선 서버 사이드의 웹 프로그래밍에서 널리 쓰인다. 앞서 말한 것처럼 무엇보다 웹 브라우저의 자바스크립트 프로그래밍과 같은 언어를 사용한다는 점은 분명한 장점이다. 다른 강점은 리노는 자바 바이트코드로 컴파일할 수 있을 뿐 아니라 인터프리터를 이용할 수도 있다는 점이다. 빈번하게 수정이 일어나는 서블릿을 예를 들어보자. 자바로 작성된 이 서블릿의 처리 부분에 위 '자바에서 자바스크립트 사용'과 같은 자바스크립트 코드를 실행하는 브릿지를 두고 실제 요청을 처리는 자바스크립트 코드를 불러와 수행하게 하면 웹 개발을 컴파일 없이 할 수 있다. 여기에 실제 배포시엔 빌드 도구에서 자바스크립트 코드를 컴파일하게 하고 브릿지 부분을 제외하면 배포 모듈은 바이트코드 컴파일된 효과를 얻을 수 있을 것이다.
운영하고자 하는 시스템의 '스크립트 언어'를 제공하고자 할 때도 리노가 유용하다. 어도비 애크로뱃 등 많은 시스템에서 자바스크립트를 스크립트 언어로 제공하며, appjet.com과 같이 웹에서 개발 가능한 개발 환경을 구축할 때도 리노는 아주 이상적인 선택이 될 수 있다.
10년 이상 넷스케이프, IBM, 구글 등에서 사용되어 온 리노는 견고하다고 알려져 있지만 컴파일된 바이트코드의 효율성이 순수 자바 코드의 바이트코드보단 떨어지기 때문에 성능이 아주 중요한 서버 사이드 프로세스에선 사용을 피하거나 적절한 부분에만 사용하는 것이 좋을 것이다.
지금까지 서버 사이드 자바스크립트 엔진에 대한 전반적인 소개와 리노를 쓰는 방법에 대해 알아봤다. 사실 중요한 것은 리노보다는 자바스크립트 그 자체에 있을 것이다. 자바스크립트를 더 공부하고 더 좋은 코드를 만들어 낼수록 리노를 더 잘 사용할 수 있을 뿐 아니라 웹 클라이언트 프로그래밍에도 더 능숙해질 수 있다. 다음 달엔 실제로 리노를 이용한 서버 사이드 웹 프로그래밍 프레임워크를 이용해보자. 마치 자바스크립트로 루비 온 레일즈나 장고(Django)를 쓰는 것 같은 기분을 느낄 수 있을 것이다.
참고자료
- 구글 I/O 세션 비디오•슬라이드 중 Server-side JavaScript on the Java Virtual Machine
- Scripting Java
- Embedding Rhino
- Scopes and Contexts
주
[1] Aptana에서 만든 Jaxer는 굉장히 흥미로운 서버 사이드 자바스크립트 기술이다. 브라우저 자체가 서버처럼 작동하여 서버 사이드 자바스크립트에서 클라이언트 사이드의 함수를 호출하고 사용할 수 있다는 데서 기존 웹 프레임워크와 근본적으로 다른 접근을 시도한다. 즉 Ajax 개발 기술을 클라이언트에서뿐 아니라 서버 사이드에서 사용할 수 있는 장점이 있다. 본 기사에선 Jaxer를 다루지 않을 예정이지만 서버 사이드 자바스크립트 기술에 관심이 많은 독자라면 참고하기 바란다.
[2] 더글라스 크록포드가 추천한 유일한 자바스크립트 책으로도 유명하다. 리노는 코뿔소란 뜻이며 동물 그림을 표지에 사용하는 것으로 유명한 오라일리 출판사의 이 책은 코뿔소를 책 표지로 사용했다.
[3] 이 점은 웹 브라우저에서 사용하는 자바스크립트 버전과 리노의 버전이 다르기 때문에 약간 주의가 필요하다. 인터넷 익스플로러 6엔 자바스크립트 1.6 버전이, 익스플로러 7엔 자바스크립트 1.7이 내장되어 있다. 파이어폭스 3는 자바스크립트 1.8을 이용하며 이 버전들 간의 중요한 차이를 어느 정도 숙지해야 '하나의 언어'를 사용하는 데서 어려움을 겪지 않을 수 있다.
이 문서 북마킹 하기

|
| 이제 전문가의 글을 단순히 ‘보는 것’에서, 직접 여러분이 developerWorks의 필자가 될 수 있습니다. IBM developerWorks를 통해 공유하고 싶은 지식이 있으신 분들은 원고 기획안을 접수해주세요. 채택되신 분께는 소정의 원고료를 드립니다. |
|
|
|
[지난 Open dW 보기] |
|