Loading...
Spring Framework Reference Documentation 7.0.2의 Functions의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
SpEL은 #functionName(…) syntax를 사용하여 expression 내에서 호출될 수 있는 사용자 정의 function을 등록함으로써 확장할 수 있으며, standard method 호출과 마찬가지로 function 호출에서도 varargs가 지원됩니다.
Function은 setVariable() method를 통해 EvaluationContext 구현에서 variables 로 등록될 수 있습니다.
StandardEvaluationContext는 function을java.lang.reflect.Method또는java.lang.invoke.MethodHandle로 등록하는 편리한 방법을 제공하는registerFunction(…)method도 정의합니다.
Function은 evaluation context에서 variables와 공통 namespace를 공유하므로, function 이름과 variable 이름이 겹치지 않도록 주의해야 합니다.
다음 예제는 java.lang.reflect.Method를 사용하여 reflection을 통해 호출될 사용자 정의 function을 등록하는 방법을 보여 줍니다:
1Method method = ...; 2 3EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); 4context.setVariable("myFunction", method);
1val method: Method = ... 2 3val context = SimpleEvaluationContext.forReadOnlyDataBinding().build() 4context.setVariable("myFunction", method)
예를 들어, string을 뒤집는 다음 utility method를 고려해 보겠습니다:
1public abstract class StringUtils { 2 3 public static String reverseString(String input) { 4 return new StringBuilder(input).reverse().toString(); 5 } 6}
1fun reverseString(input: String): String { 2 return StringBuilder(input).reverse().toString() 3}
다음 예제에서 보듯이, 앞의 method를 등록하고 사용할 수 있습니다:
1ExpressionParser parser = new SpelExpressionParser(); 2 3EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); 4context.setVariable("reverseString", 5 StringUtils.class.getMethod("reverseString", String.class)); 6 7// evaluates to "olleh" 8String helloWorldReversed = parser.parseExpression( 9 "#reverseString('hello')").getValue(context, String.class);
1val parser = SpelExpressionParser() 2 3val context = SimpleEvaluationContext.forReadOnlyDataBinding().build() 4context.setVariable("reverseString", ::reverseString.javaMethod) 5 6// evaluates to "olleh" 7val helloWorldReversed = parser.parseExpression( 8 "#reverseString('hello')").getValue(context, String::class.java)
Function은 java.lang.invoke.MethodHandle로도 등록될 수 있습니다. 이는 MethodHandle target과 parameter가 등록 전에 완전히 bound되어 있는 경우 잠재적으로 더 효율적인 사용 사례를 가능하게 하지만, 부분적으로 bound된 handle도 지원됩니다.
Template와 가변 개수의 argument
(varargs)에 따라 message를 생성하는 String#formatted(Object…) instance method를 고려해 보십시오.
다음 예제에서 보듯이, formatted method를 MethodHandle로 등록하고 사용할 수 있습니다:
1ExpressionParser parser = new SpelExpressionParser(); 2EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); 3 4MethodHandle mh = MethodHandles.lookup().findVirtual(String.class, "formatted", 5 MethodType.methodType(String.class, Object[].class)); 6context.setVariable("message", mh); 7 8// evaluates to "Simple message: <Hello World>" 9String message = parser.parseExpression("#message('Simple message: <%s>', 'Hello World', 'ignored')") 10 .getValue(context, String.class);
1val parser = SpelExpressionParser() 2val context = SimpleEvaluationContext.forReadOnlyDataBinding().build() 3 4val mh = MethodHandles.lookup().findVirtual(String::class.java, "formatted", 5 MethodType.methodType(String::class.java, Array<Any>::class.java)) 6context.setVariable("message", mh) 7 8// evaluates to "Simple message: <Hello World>" 9val message = parser.parseExpression("#message('Simple message: <%s>', 'Hello World', 'ignored')") 10 .getValue(context, String::class.java)
위에서 언급했듯이, MethodHandle을 binding하고 bound된 MethodHandle을 등록하는 것도 지원됩니다. Target과 모든 argument가 bound된 경우 더 성능이 좋을 가능성이 큽니다. 그런 경우에는 다음 예제에서 보듯이 SpEL expression에서 argument가 필요하지 않습니다:
1ExpressionParser parser = new SpelExpressionParser(); 2EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); 3 4String template = "This is a %s message with %s words: <%s>"; 5Object varargs = new Object[] { "prerecorded", 3, "Oh Hello World!", "ignored" }; 6MethodHandle mh = MethodHandles.lookup().findVirtual(String.class, "formatted", 7 MethodType.methodType(String.class, Object[].class)) 8 .bindTo(template) 9 // Here we have to provide the arguments in a single array binding: 10 .bindTo(varargs); 11context.setVariable("message", mh); 12 13// evaluates to "This is a prerecorded message with 3 words: <Oh Hello World!>" 14String message = parser.parseExpression("#message()") 15 .getValue(context, String.class);
1val parser = SpelExpressionParser() 2val context = SimpleEvaluationContext.forReadOnlyDataBinding().build() 3 4val template = "This is a %s message with %s words: <%s>" 5val varargs = arrayOf("prerecorded", 3, "Oh Hello World!", "ignored") 6 7val mh = MethodHandles.lookup().findVirtual(String::class.java, "formatted", 8 MethodType.methodType(String::class.java, Array<Any>::class.java)) 9 .bindTo(template) 10 // Here we have to provide the arguments in a single array binding: 11 .bindTo(varargs) 12context.setVariable("message", mh) 13 14// evaluates to "This is a prerecorded message with 3 words: <Oh Hello World!>" 15val message = parser.parseExpression("#message()") 16 .getValue(context, String::class.java)
Variables
Varargs Invocations