Spring 2.0은 Spring으로 동적 언어를 사용하여 정의된 bean을 가지는 클래스와 객체를 사용하기 위한 편리한 지원을 소개한다.
이 지원은 지원되는 동적언어로 많은 수의 클래스를 작성하는 것을 허용하고 Spring컨테이너를 투명하게 인스턴스화하고 설정하며 결과객체를 의존성 삽입한다.
현재 지원하는 동적언어는 다음과 같다.
Groovy
BeanShell
JRuby
이 동적언어 지원이 즉시 유용할수 있는 완벽하게 작동하는 예제는 Section 24.7, “시나리오” 부분에서 언급된다.
이 장에서 상세화되는 동적언어 지원은 오직 Spring 2.0과 그 이상의 버전에서만 사용가능하다. 현재 이전버전에 대한 동적언어 지원은 계획에 없다.
이 장의 대부분은 동적언어 지원을 상세하게 다루고 있다. 지원에 대해 나누기 전에, 동적언어에 정의된 bean의 빠른 예제를 보자.
이 첫번째 bean을 위한 동적언어는 Groovy다(이 예제를 위한 기본은 Spring테스트 모음로 부터 얻어진다. 그래서 지원되는 다른 언어와 동등한 예제를 보길 원한다면, 스스로 직접 소스코드를 보라.)
Groovy bean이 구현되는 Messenger 인터페이스를 보자. 이 인터페이스는 명백한 Java로 정의된다. 기초적인 구현물을 알지않는 Messenger에 대한 참조를 가지고 삽입되는 의존적인 객체는 Groovy 스크립트이다.
package org.springframework.scripting; public interface Messenger { String getMessage(); }
그리고 이것은 Messenger 인터페이스에 의존성을 가지는 클래스의 정의이다.
package org.springframework.scripting; public class DefaultBookingService implements BookingService { private Messenger messenger; public void setMessenger(Messenger messenger) { this.messenger = messenger; } public void processBooking() { // use the injected Messenger object... } }
이것은 Groovy내 Messenger 인터페이스의 구현물이다.
// from the file 'Messenger.groovy' package org.springframework.scripting.groovy; // import the Messenger interface (written in Java) that is to be implemented import org.springframework.scripting.Messenger // define the implementation in Groovy class GroovyMessenger implements Messenger { @Property String message; }
마지막으로 이것은 Groovy스크립트 Messenger 구현물을 DefaultBookingService 클래스의 인스턴스로 삽입하는 것에 영향을 끼칠 bean정의이다.
![]() | Note |
---|---|
동적언어를 지원하는 bean을 정의하기 위한 사용자정의 동적언어 태그를 사용하기 위해, Spring XML설정파일의 가장 위에 XML스키마 서문을 가질 필요가 있다. 또한 IoC컨테이너로 Spring ApplicationContext 구현물이 사용될 필요가 있다. 명백한 BeanFactory 구현물과 함께 동적언어를 지원하는 bean을 사용하는 것은 지원된다. 하지만 그렇게 하기 위해 Spring내부의 구현을 관리해야만 한다. 스키마-기반의 설정에 대한 좀더 많은 정보를 위해서 Appendix A, XML 스키마-기반 설정를 보라. |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd"> <!-- this is the bean definition for the Groovy-backed Messenger implementation --> <lang:groovy id="messenger" script-source="classpath:Messenger.groovy"> <lang:property name="message" value="I Can Do The Frug" /> </lang:groovy> <!-- an otherwise normal bean that will be injected by the Groovy-backed Messenger --> <bean id="bookingService" class="x.y.DefaultBookingService"> <property name="messenger" ref="messenger" /> </bean> </beans>
삽입되는 Messenger 인스턴스가 Messenger 인스턴스이기 때문에 bookingService bean(DefaultBookingService)은 대개 private messenger 멤버 변수를 사용할수 있다. 여기에 특별한 것은 없다. 이것은 명백한 Java이고 명백한 Groovy이다.
위 XML조각은 이름 자체가 설명을 하도록 바라지만, 그렇지 않더라도 걱정하지 말라. 위 설정의 이유와 원인에 대한 깊은 상세사항을 위해 계속 읽어라.
이 부분은 지원되는 동적언어로 Spring관리 bean을 정의하는 방법을 언급한다.
이 부분은 지원되는 동적언어의 문법과 표현형식을 설명하는 것을 시도하지 않는다. 예를 들어, 당신이 애플리케이션에서 어떤 클래스를 작성하기 위해 Groovy를 사용하길 원한다면, 당신은 이미 Groovy를 알고 있다고 가정한다. 만약 당신이 동적언어에 대해 좀더 상세하게 다룰필요가 있다면, 이 장의 마지막 부부인 Section 24.8, “더 많은 자원”를 참조하라.
동적언어-지원 bean을 사용하는 것을 포함하는 단계는 다음과 같다.
동적언어를 위한 테스트 작성
그리고 나서 동적언어 자체를 작성 :)
XML설정내 적절한 <lang:language/> 요소를 사용하여 동적언어를 지원하는 bean을 정의하라(비록 당신이 이 장에서는 다루어지지 않는 고급 설정에서 이러한 타입으로 수행하는 방법에 대한 지시를 위한 소스코드를 언급하더라도 당신은 Spring API를 사용하여 이러한 bean을 프로그램처리로 정의할수 있다.). 이것은 반복적인 단계이다. 당신은 동적언어 소스파일마다 적어도 하나의 bean정의가 필요할 것이다(비록 같은 동적언어 소스파일이 다중 bean정의에 의해 참조될수 있더라도).
첫번째 두단계(동적언어에 대한 테스팅과 작성)는 이 장의 범위를 넘어서는 것이다. 언어 스펙과/또는 당신이 선택한 동적언어를 위한 참조문서를 보고 동적언어를 개발하라. 당신은 먼저 이 장의 나머지를 읽기를 원할것이다.
마지막 단계는 설정(이것은 대개의 Java bean설정과는 차이점이 없다.)하고자 하는 각각의 bean을 위한 동적언어를 지원하는 bean정의를 정의하는 것을 포함한다. 어쨌든, 컨테이너에 의해 인스턴스화되고 설정되는 클래스의 전체경로를 포함한 클래스명을 명시하는 것 대신에, 동적언어를 지원하는 bean을 정의하기 위해 <lang:language/>요소를 사용한다.
지원되는 각각의 언어는 관련된 <lang:language/> 요소를 가진다.
<lang:jruby/> (JRuby)
<lang:groovy/> (Groovy)
<lang:bsh/> (BeanShell)
설정에서 사용가능한 속성과 자식 요소는 bean이 정의되는 언어에 의존한다.(아래의 언어에 종속한 부분은 이것에 대해 완전하게 다룬다.)
Spring에서 동적언어지원에 추가되는 가장 마음에 드는(compelling) 값중에 하나는 'refreshable bean'기능이다.
갱신가능한 bean은 적은 양의 설정을 가지는 동적언어를 지원하는 bean이다. 동적언어를 지원하는 bean은 참조하는 소스파일 자원의 변경을 모니터링하고 동적언어 소스파일이 변경되면 자체적으로 리로드(예를 들어 개발자가 파일시스템의 파일을 편집하고 저장할때)한다.
이것은 애플리케이션의 일부로 많은 수의 동적언어 소스 파일을 배치하고 동적언어 소스파일에 의해 지원되는 bean을 생성하기 위해 Spring컨테이너를 설정(이 장에서 언급되는 기법을 사용하여) 하는것을 가능하게 한다. 그리고 나서, 요구사항 변경이나 몇몇 다른 외부 요소는 작동하기 시작한다. 동적언어 소스파일을 간단히 편집하고 동적언어 소스파일을 변경하여 지원되는 bean을 반영한다. 여기서는 구동중인 애플리케이션을 중지할 필요가 없다(또는 웹 애플리케이션의 경우 다시 배치할 필요가 없다.). 동적언어를 지원하는 bean은 변경된 동적언어 소스파일로부터 새로운 상태와 로직을 간단히 가져올것이다. 이것은 빠른 프로토타이핑과 같은 시나리오를 위해 명백하다.
![]() | Note |
---|---|
이 기능은 디폴트로 사용되지 않는다. |
갱신가능한 bean을 사용하여 시작하는 방법을 보기 위한 예제를 먼저 보자. 갱신가능한 bean기능을 사용하기 위해, bean정의의 <lang:language/> 요소에 하나의 추가적인 속성을 명시해야만 한다. 그리고 이 장의 앞부분으로 부터 예제에 충실하다면, 이것은 갱신가능한 bean에 영향을 끼치는 Spring XML설정내 변경일것이다.
<beans> <!-- this bean is now 'refreshable' due to the presence of the 'refresh-check-delay' attribute --> <lang:groovy id="messenger" refresh-check-delay="5000" <!-- switches refreshing on with 5 seconds between checks --> script-source="classpath:Messenger.groovy"> <lang:property name="message" value="I Can Do The Frug" /> </lang:groovy> <bean id="bookingService" class="x.y.DefaultBookingService"> <property name="messenger" ref="messenger" /> </bean> </beans>
'messenger' bean정의에 정의된 'refresh-check-delay' 속성은 bean이 참조하는 동적언어 소스파일에 대한 변경으로 갱신되는 초단위 값이다. 당신은 'refresh-check-delay' 속성에 음수를 할당하여 갱신행위를 끌수 있다. 디폴트는 갱신행위가 작동하지 않는다. 당신이 갱신행위를 원하지 않는다면, 속성을 정의하지 말라.
우리가 다음의 애플리케이션을 실행한다면, 우리는 refreshable기능을 사용할수 있다. 이 코드의 다음 부분에서 'jumping-through-hoops-to-pause-the-execution'를 실행해보라. System.in.read() 호출은 내가 기초적인 스크립트 파일을 진행하고 편집하는 동안 프로그램의 실행이 잠시 멈춘다. 그래서 스크립티-지원 bean은 프로그램이 다시 실행될때 이것의 상태를 갱신할것이다.
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scripting.Messenger;
public final class Boot {
public static void main(final String[] args) throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
Messenger messenger = (Messenger) ctx.getBean("messenger");
System.out.println(messenger.getMessage());
// pause execution while I go off and make changes to the source file...
System.in.read();
System.out.println(messenger.getMessage());
}
}
변경되는 Messenger 구현물의 getMessage() 메소드를 호출한다고 가정해보자. 프로그램의 실행이 멈추었을때, Messenger.groovy 스크립트에 대한 변경을 아래에서 보라.
package org.springframework.scripting
class GroovyMessenger implements Messenger {
private String message = "Bingo"
public String getMessage() {
// change the implementation to surround the message in quotes
return "'" + this.message + "'"
}
public void setMessage(String message) {
this.message = message
}
}
프로그램이 실행되었을때, 입력이 중단되기 전 출력은 I Can Do The Frug 일것이다. 소스파일을 변경하고 저장한후에, 프로그램 수행을 다시 한다면, 동적언어를 지원하는 Messenger 구현물의 getMessage() 메소드 호출의 결과는 'I Can Do The Frug' 가 될것이다(따옴표를 포함한다는 것에 주의하라.).
언급된 변경이 'refresh-check-delay' 값의 창에서 발생한다면 스크립트에 대한 변경이 갱신을 처리하지 않을것이라는 것을 이해하는 것이 중요하다. 메소드가 동적언어를 지원하는 bean에서 호출될때까지 스크립트에 대한 변경이 실제로 '가지지(picked up)' 않는 것을 이해하는 것도 동등하게 중요하다. 메소드가 동적언어를 지원하는 bean에서 호출될때 참조하는 스크립트 소스가 변경될때만 보는것을 체크한다. 스크립트를 갱신하는것에 관련된 예외(컴파일 에러나 스크립트 파일이 삭제된 것을 찾는 것과 같은)는 호출 코드에 위임되는 치명적인(fatal) 예외의 결과가 될것이다.
위에서 언급된 갱신가능한 bean행위는 <lang:inline-script/> 요소을 사용하여 정의된 동적언어 소스파일에 적용되지 않는다(Section 24.3.1.3, “즉시 처리되는(Inline-인라인) 동적언어 소스파일” 를 보라). 추가적으로, 실질적으로 감지될수 있는 참조하는 소스파일에 대한 변경이 있는 bean에만 적용된다. 예를 들어, 코드에 의해 파일시스템에 존재하는 동적언어 소스파일의 마지막 변경날짜를 체크한다.
동적언어 지원은 Spring bean정의내 직접 내장되는 동적언어를 제공할수 있다. 좀더 특별히, <lang:inline-script/> 요소는 Spring 설정파일내부에서 즉시 동적언어 소스를 정의하는 것을 허용한다. 예제는 인라인 스크립트 기능을 보여줄것이다.
<lang:groovy id="messenger"> <lang:property name="message" value="I Can Do The Frug" /> <lang:inline-script> package org.springframework.scripting.groovy; import org.springframework.scripting.Messenger class GroovyMessenger implements Messenger { @Property String message; } </lang:inline-script> </lang:groovy>
만약 우리가 Spring설정파일 내부에 동적언어 소스를 정의하는 좋은 상황에 둘러쌓인 이슈에 놓여있다면, <lang:inline-script/> 요소는 몇가지 시나리오에서 유용할수 있다. 예를 들어, 우리가 Spring Validator 구현물을 Spring MVC Controller 에 추가하길 원할때, 이것은 인라인 스크립트를 사용하는 상황이 된다(이러한 예제를 위해서는 Section 24.7.2, “스크립트된 Validators” 를 보라.)
물론 위에서 보여진것보다 좀더 복잡한 클래스의 경우도 잊지 말라. 당신은 <![CDATA[]]> 영역내 인라인 스크립트를 둘러싸야 할지도 모른다.
아래는 inline: 주석을 사용하여 Spring XML설정파일에 직접 JRuby기반 bean을 위한 소스를 정의하는 예제이다.('<' 문자를 나타내는 < 문자의 사용에 유의하라.)
<lang:jruby id="messenger" script-interfaces="org.springframework.scripting.Messenger"> <lang:inline-script> require 'java' include_class 'org.springframework.scripting.Messenger' class RubyMessenger < Messenger def setMessage(message) @@message = message end def getMessage @@message end end </lang:inline-script> <lang:property name="message" value="Hello World!" /> </lang:jruby>
Spring의 동적언어 지언에 관련하여 인지되는 매우 중요한 것이 있다. 명명하여, 이것은 동적언어를 지원하는 bean에 생성자의 인자를 제공하는 것이 가능하지 않다(나아가 생성자 삽입은 동적언어를 지원하는 bean에 사용가능하지 않다).
생성자를 특별히 다루는 것과 프라퍼티를 100%로 명백하게 만들기 위한 관심으로, 다음의 코드와 설정의 혼합은 작동하지 않을것이다.
이것은 Groovy내 Messenger 인터페이스의 구현물이다.
// from the file 'Messenger.groovy' package org.springframework.scripting.groovy; import org.springframework.scripting.Messenger class GroovyMessenger implements Messenger { GroovyMessenger() {} // this constructor is not available for Constructor Injection... GroovyMessenger(String message) { this.message = message; } @Property String message; @Property String anotherMessage }
<lang:groovy id="badMessenger" script-source="classpath:Messenger.groovy"> <!-- this next constructor argument will *not* be injected into the GroovyMessenger --> <!-- in fact, this isn't even allowed according to the schema --> <constructor-arg value="This will *not* work" /> <!-- only property values are injected into the dynamic-language-backed object --> <lang:property name="anotherMessage" value="Passed straight through to the dynamic-language-backed object" /> </lang>
사실 이 제한은 setter삽입이 대다수의 개발자에 의해 선호되는 삽입 스타일이 된 이후에 처음으로 나타난것처럼 명백하지는 않다(이것은 나중에 좋은 것이 무엇인지에 대한 논의로 남겨두자.)
JRuby 홈페이지로부터...
“ [JRuby is an] Java로 작성된 Ruby인터프리터를 재생성하기 위한 영향을 끼치고 Java 바이트코드 컴파일러를 위한 Ruby이다. ”Spring의 동적언어 지원은 JRuby언어에 정의된 bean도 지원한다. JRuby언어는 Ruby언어에 기초를 둔다. 그리고 인라인 정규표현식, 블럭(클로져), 개발을 좀더 쉽도록 몇가지 도메인 문제를 위한 해결책을 만들어주는 다른 기능들을 지원한다.
Spring내 JRuby동적언어 지원의 구현물은 무엇이 발생하는지에 흥미를 가진다. Spring은 <lang:ruby> 요소의 'script-interfaces' 속성에 명시된 모든 인터페이스의 JDK동적 프록시 구현물을 생성한다. (이것은 당신이 언급된 속성값의 적어도 하나의 인터페이스를 제공하고 JRuby를 지원하는 bean을 사용할때 인터페이스에 대한 프로그래밍을 해야만 하는 이유이다.)
JRuby기반의 bean을 사용한 예제를 보자. 이것은 이전에 먼저 정의한 Messenger 인터페이스의 JRuby구현물이다.
package org.springframework.scripting; public interface Messenger { String getMessage(); }
require 'java'
include_class 'org.springframework.scripting.Messenger'
class RubyMessenger < Messenger
def setMessage(message)
@@message = message
end
def getMessage
@@message
end
end
RubyMessenger.new # this last line is not essential (but see below)
그리고 이것은 RubyMessenger JRuby bean의 인스턴스를 정의한 Spring XML이다.
<lang:jruby id="messageService" script-interfaces="org.springframework.scripting.Messenger" script-source="classpath:RubyMessenger.rb"> <lang:property name="message" value="Hello World!" /> </lang:jruby>
JRuby소스의 마지막 라인('RubyMessenger.new')을 노트하자. Spring의 동적언어 지원의 컨텍스트에서 JRuby를 사용할때, 당신은 JRuby소스의 수행의 결과로 동적언어를 지원하는 bean으로 사용하길 원하는 JRuby클래스의 새로운 인스턴스를 인스턴스화하거나 반환하기 위해 격려된다. 소스파일의 마지막 라인에서 JRuby클래스의 새로운 인스턴스를 간단히 인스턴스화하여 이것을 달성할수 있다.
require 'java' include_class 'org.springframework.scripting.Messenger' # class definition same as above... # instantiate and return a new instance of the RubyMessenger class RubyMessenger.new
당신이 이것을 하는것을 잊었다면, 이것이 끝이 아니다. 이것은 인스턴스화하기 위한 클래스를 찾는 JRuby클래스의 타입 표시를 통해 Spring이 (반사적으로) 견지질하는(trawl) 결과를 만든다. 이 중요한 스키마에서, 이것은 결코 알리지 않아서 빠를것이다. 하지만 이것은 때때로 JRuby스크립트의 마지막 줄과같은 것을 가져서 피할수 있다. 이러한 줄을 제공하지 않거나 Spring이 스크립트에서 인스턴스화하기 위한 JRuby클래스를 찾을수 없다면 ScriptCompilationException은 소스가 JRuby 인터프리터에 의해 수행된 직후 던져질것이다. 예외의 가장 위에 있는 이유로 이것을 식별하는 핵심 텍스트는 밑에서 즉시 찾을수 있다(그래서 동적언어를 지원하는 bean을 생성할때 Spring컨테이너가 다음의 예외를 던지고 관련 stacktrace에서 다음 텍스트가 있다면, 이것은 확인하는 것을 허용하고 이슈를 쉽게 개정한다.)
org.springframework.scripting.ScriptCompilationException: Compilation of JRuby script returned ''
이것을 개정하기 위해, JRuby-동적언어를 지원하는 bean처럼 나타나길 원하는 클래스의 새로운 인스턴스를 간단히 인스턴스화하라. 당신이 JRuby스크립트에서 원하는 만큼의 클래스와 객체를 정의할수 있다는 것을 노트하라. 중요한 것은 소스파일이 객체를 반환해야만 한다는 것이다.
JRuby-기반의 bean를 사용하기 위한 몇가지 시나리오를 위해 Section 24.7, “시나리오”를 보라.
Groovy홈페이지로부터....
“Groovy는 Python, Ruby와 Smalltalk처럼 사람들이 좋아하는 많은 기능을 가진 Java 2 플랫폼을 위한 활기찬(agile) 동적 언어이다. Java와 같은 문법을 사용하여 Java개발자를 위해 사용가능하다. ”이 문서를 처음부터 계속 읽었다면, Groovy 동적언어를 지원하는 bean의 예제를 보았을것이다. 다른 예제를 보자.
![]() | Note |
---|---|
Groovy 자체는 JDK 1.4이상을 요구한다는 것에 주의하라. |
package org.springframework.scripting; public interface Calculator { int add(int x, int y); }
이것은 Groovy내 Calculator 인터페이스의 구현물이다.
// from the file 'calculator.groovy'
package org.springframework.scripting.groovy
class GroovyCalculator implements Calculator {
int add(int x, int y) {
x + y
}
}
그리고 이것은 부수적인 Spring설정이다(XML).
<-- from the file 'beans.xml' -->
<beans>
<lang:groovy id="calculator" script-source="classpath:calculator.groovy"/>
</beans>
마지막으로 이것은 위 설정을 수행하기 위한 작은 애플리케이션이다.
package org.springframework.scripting; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void Main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); Calculator calc = (Calculator) ctx.getBean("calculator"); System.out.println(calc.add(2, 8)); } }
위 프로그램의 실행으로부터의 결과는 10이 될것이다(놀라운 예제인가.? 의도는 개념을 전달하는것이라는것을 기억하라. 좀더 실질적인 예제를 위해서는 동적언어 전시 프로젝트를 보거나 이 장의 마지막의 Section 24.7, “시나리오”를 보라).
Groovy 소스파일마다 한개 이상의 클래스를 정의하지 않는다는 것이 중요하다. Groovy내에서는 완전한 반면에 좋지 않은 상황이다. 일관적인 접근법에 관심을 가지고 당신은 소스파일마다 한개의 (public)클래스라는 표준 Java규칙을 반영해야만 할것이다(저자의 의견으로).
이것은 Groovy기반 bean이 작동하는데 충분하다. 그럼 Groovy를 사용해보라.
BeanShell 홈페이지로부터...
“ Java로 작성된 BeanShell은 객체 동적언어 기능을 가진 작고, free이며, 내장된 Java소스 인터프리퍼이다. BeanShell은 표준 Java문법을 동적으로 수행하고 느슨한(loose) 타입, 커멘드, 그리고 Perl과 자바스크립트의 그것과 같은 메소드 closure와 같은 공통 동적언어 편리성으로 이것을 확장한다. ”Groovy와는 반대로, BeanShell을 지원하는 bean정의는 몇가지 추가적인 설정을 요구한다. Spring내 BeanShell 동적언어 지원의 구현물은 무엇이 발생하는지에 대해 흥미를 가진다. Spring은 <lang:bsh> 요소의 'script-interfaces' 속성값에 명시된 모든 인터페이스의 JDK 동적 프록시 구현물을 생성한다(이것은 당신이 언급된 속성값의 적어도 하나의 인터페이스를 제공하고 BeanShell을 지원하는 bean을 사용할때 인터페이스에 대한 프로그래밍을 해야만 하는 이유이다.). 이것은 BeanShell을 지원하는 객체의 모든 메소드 호출이 JDK 동적 프록시 호출 기법을 통한다는 것을 의미한다.
이 장에서 이미 정의된 Messenger 인터페이스를 구현하는 BeanShell기반 bean을 사용하는 예제를 보자(편리성을 위해 밑에서 반복될것이다.).
package org.springframework.scripting; public interface Messenger { String getMessage(); }
이것은 Messenger 인터페이스의 BeanShell 'implementation'이다(여기서는 매우 느슨하게 사용되는것을 뜻한다).
String message; String getMessage() { return message; } void setMessage(String aMessage) { message = aMessage; }
그리고 이것은 위 'clsss'의 'instance'를 정의하는 Spring XML이다(다시 말해, 여기서는 매우 느슨하게 사용되는것을 뜻한다.).
<lang:bsh id="messageService" script-source="classpath:BshMessenger.bsh" script-interfaces="org.springframework.scripting.Messenger"> <lang:property name="message" value="Hello World!" /> </lang:bsh>
BeanShell 기반 bean을 사용하길 원하는 몇몇 시나리오를 위해 Section 24.7, “시나리오”를 보라.
스크립트 언어내 Spring관리 bean을 정의하는 가능한 시나리오는 이익이 될것이다. 물론 많고 다양한 이익이 될것이다. 이 부분은 Spring에서 동적언어 지원을 위한 두가지의 가능한 사용 케이스를 언급한다.
Spring 배포판은 Spring은 배포판의 관련 부분내 Spring의 동적언어 지원을 위한 보여주기 위한 프로젝트를 가진다는 것을 알아달라(보여주기 위한 프로젝트는 Spring프레임워크의 특정 관점을 다루는 범위내에서 제한되는 작은 프로젝트이다.)
동적언어를 지원하는 bean을 사용하는 이득을 얻는 하나의 클래스 그룹은 Spring MVC컨트롤러이다. 단순히 Spring MVC애플리케이션에서, 웹 애플리케이션을 통한 탐색이 가능한 흐름(navigational flow)은 하나의 Spring MVC 컨트롤러에서 캡슐화되는 코드에 의해 결정되는 큰 범위이다. 웹 애플리케이션의 탐색가능한 흐름과 다른 표현 레이어 로직은 지원 이슈에 응하거나 비지니스 요구사항을 변경하기 위해 업데이트 될 필요가 있다. 이것은 하나 이상의 동적언어 소스파일을 편집하고 수행중인 애플리케이션의 상태가 즉시 반영되는 변경을 보는 이러한 요구되는 변경에 좀더 쉽게 영향을 끼친다.
Spring과 같은 프로젝트가 채택한 경량 구조 모델(lightweight architectural model)에서, 도메인과 서비스 레이어 클래스에 포함된 모든 애플리케이션의 비지니스 로직과 함께 가벼운 표현 레이어를 대개 지향한다. 동적언어를 지원하는 bean처럼 Spring MVC컨트롤러를 개발하는 것은 텍스트 파일을 간단히 편집하고 저장하여 표현 레이어를 변경하는 것을 허용한다. 이러한 동적언어 소스파일의 변경(설정에 따라)은 언급된 스크립트에 의해 지원되는 bean에 자동적으로 영향을 끼칠것이다.
![]() | Note |
---|---|
동적언어를 지원하는 bean에 대한 변경을 자동적으로 'pickup' 하는데 영향을 끼치지 위해, '갱신가능한(refreshable) beans' 기능을 사용가능하게 해야 한다는 것을 알아두라. 이 기능에 대한 완전하고 상세한 처리를 Section 24.3.1.2, “갱신가능한(Refreshable) beans” 를 보라. |
Groovy 동적언어를 사용하여 구현된 org.springframework.web.servlet.mvc.Controller의 예제는 아래에서 찾아보라(이 예제는 Spring 배포판과 함께 제공되는 동적언어 지원 전시 프로젝트의 일부에 있다. Spring 배포판의 'samples/showcases/dynamvc/' 디렉토리내 프로젝트를 보라).
<!-- from the file '/WEB-INF/groovy/FortuneController.groovy' -->
package org.springframework.showcase.fortune.web;
import org.springframework.showcase.fortune.service.FortuneService;
import org.springframework.showcase.fortune.domain.Fortune;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FortuneController implements Controller {
@Property FortuneService fortuneService
public ModelAndView handleRequest(
HttpServletRequest request, HttpServletResponse httpServletResponse) {
return new ModelAndView("tell", "fortune", this.fortuneService.tellFortune())
}
}
위 Controller의 부수적인 bean정의는 다음과 같을것이다.
<lang:groovy id="fortune" refresh-check-delay="3000" script-source="/WEB-INF/groovy/FortuneController.groovy"> <lang:property name="fortuneService" ref="fortuneService"/> </lang:groovy>
동적언어를 지원하는 bean으로 인해 가져지는 유연성을 가지는 Spring을 사용한 애플리케이션 개발의 다른 영역은 유효성체크이다. 이것은 아마도 일반적인 Java에 비해 느슨하게 타이핑된 동적언어를 사용하여 복잡한 유효성체크 로직을 표현하는 것을 좀더 쉽게 할것이다.
다시 말해, 동적언어를 지원하는 bean처럼 하나의 validator를 개발하는 것은 간단한 텍스트 파일을 편집하고 저장하여 유효성 체크 로직을 변경하는 것을 허용한다. 이러한 변경(설정에 따라)은 수행중인 애플리케이션의 실행에 자동적으로 영향을 끼치고 애플리케이션의 재시작을 요구하지는 않는다.
![]() | Note |
---|---|
스크립트-지원 bean에 대한 변경을 자동적으로 'pickup' 하는데 영향을 끼치지 위해, 'refreshable beans' 기능을 사용가능하게 해야 한다는 것을 알아두라. 이 기능에 대한 완전하고 상세한 처리를 Section 24.3.1.2, “갱신가능한(Refreshable) beans” 를 보라. |
Groovy 동적언어를 사용하여 구현되는 Spring org.springframework.validation.Validator 예제는 아래에서 찾아보라. (Validator 인터페이스에 대한 언급은 Section 5.2, “Spring의 Validator인터페이스를 사용하여 유효성 체크하기” 에서 보라.)
import org.springframework.validation.Validator import org.springframework.validation.Errors import org.springframework.beans.TestBean public class TestBeanValidator implements Validator { boolean supports(Class clazz) { return TestBean.isAssignableFrom(clazz) } void validate(Object bean, Errors errors) { String name = bean.getName() if(name == null || name.trim().length == 0) { errors.reject("whitespace", "Cannot be composed wholly of whitespace") } } }
이 장에서 언급된 다양한 동적언어에 대한 더 많은 자원을 위한 링크를 밑에서 알아보라.
Spring커뮤니티의 몇 활동적인 멤버는 위 추가적인 동적언어의 지원과 이 장에서 다루는것 이상을 추가했다. 이러한 여타의 기여는 주요 Spring배포판에 의해 지원되는 언어의 목록에 추가되는것이 가능한 동안, 당신이 선호하는 스크립트 언어를 보기 위한 베팅은 Spring Modules project이다.