Documentation updates describing SpEL compiler usage
This commit is contained in:
parent
f617d28eef
commit
8bf141eca9
|
|
@ -11866,8 +11866,147 @@ being placed in it. A simple example:
|
|||
Boolean b = simple.booleanList.get(0);
|
||||
----
|
||||
|
||||
[[expressions-parser-configuration]]
|
||||
==== Parser configuration
|
||||
It is possible to configure the SpEL expression parser using a parser configuration object
|
||||
(`org.springframework.expression.spel.SpelParserConfiguration`). The configuration
|
||||
object controls the behaviour of some of the expression components. For example, if
|
||||
indexing into an array or collection and the element at the specified index is `null`
|
||||
it is possible to automatically create the element. This is useful when using expressions made up of a
|
||||
chain of property references. If indexing into an array or list
|
||||
and specifying an index that is beyond the end of the current size of the array or
|
||||
list it is possible to automatically grow the array or list to accommodate that index.
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
class Demo {
|
||||
public List<String> list;
|
||||
}
|
||||
|
||||
// Turn on:
|
||||
// - auto null reference initialization
|
||||
// - auto collection growing
|
||||
SpelParserConfiguration config = new SpelParserConfiguration(true,true);
|
||||
|
||||
ExpressionParser parser = new SpelExpressionParser(config);
|
||||
|
||||
Expression expression = parser.parseExpression("list[3]");
|
||||
|
||||
Demo demo = new Demo();
|
||||
|
||||
Object o = expression.getValue(demo);
|
||||
|
||||
// demo.list will now be a real collection of 4 entries
|
||||
// Each entry is a new empty String
|
||||
----
|
||||
|
||||
It is also possible to configure the behaviour of the SpEL expression compiler.
|
||||
|
||||
[[expressions-spel-compilation]]
|
||||
==== SpEL compilation
|
||||
|
||||
Spring Framework 4.1 includes a basic expression compiler. Expressions are usually
|
||||
interpreted which provides a lot of dynamic flexibility during evaluation but
|
||||
does not provide the optimum performance. For occasional expression usage
|
||||
this is fine, but when used by other components like Spring Integration,
|
||||
performance can be very important and there is no real need for the dynamism.
|
||||
|
||||
The new SpEL compiler is intended to address this need. The
|
||||
compiler will generate a real Java class on the fly during evaluation that embodies the
|
||||
expression behaviour and use that to achieve much faster expression
|
||||
evaluation. Due to the lack of typing around expressions the compiler
|
||||
uses information gathered during the interpreted evaluations of an
|
||||
expression when performing compilation. For example, it does not know the type
|
||||
of a property reference purely from the expression but during the first
|
||||
interpreted evaluation it will find out what it is. Of course, basing the
|
||||
compilation on this information could cause trouble later if the types of
|
||||
the various expression elements change over time. For this reason compilation
|
||||
is best suited to expressions whose type information is not going to change
|
||||
on repeated evaluations.
|
||||
|
||||
For a basic expression like this:
|
||||
|
||||
`someArray[0].someProperty.someOtherProperty < 0.1`
|
||||
|
||||
which involves array access, some property derefencing and numeric operations, the performance
|
||||
gain can be very noticeable. In an example microbenchmark run of 50000 iterations, it was
|
||||
taking 75ms to evaluate using only the interpreter and just 3ms using the compiled version
|
||||
of the expression.
|
||||
|
||||
[[expressions-compiler-configuration]]
|
||||
===== Compiler configuration
|
||||
|
||||
The compiler is not turned on by default, there are two ways to turn
|
||||
it on. It can be turned on using the parser configuration process discussed earlier or
|
||||
via a system property when SpEL usage is embedded inside another component. This section
|
||||
discussed both of these options.
|
||||
|
||||
Is is important to understand that there are a few modes the compiler can operate in, captured
|
||||
in an enum (`org.springframework.expression.spel.SpelCompilerMode`). The modes are as follows:
|
||||
|
||||
- `OFF` - the compiler is switched off, this is the default.
|
||||
- `IMMEDIATE` - In immediate mode the expressions are compiled as soon as possible. This
|
||||
is typically after the first interpreted evaluation. If the compiled expression fails
|
||||
(typically due to a type changing, as described above) then the caller of the expression
|
||||
evaluation will receive an exception.
|
||||
- `MIXED` - In mixed mode the expressions silently switch between interpreted and compiled
|
||||
mode over time. After some number of interpreted runs they will switch to compiled
|
||||
form and if something goes wrong with the compiled form (like a type changing, as
|
||||
described above) then the expression will automatically switch back to interpreted form
|
||||
again. Sometime later it may generate another compiled form and switch to it. Basically
|
||||
the exception that the user gets in `IMMEDIATE` mode is instead handled internally.
|
||||
|
||||
`IMMEDIATE` mode exists because `MIXED` mode could cause issues for expressions that
|
||||
have side effects. If a compiled expression blows up after partially succeeding it
|
||||
may have already done something that has affected the state of the system. If this
|
||||
has happened the caller may not want it to silently re-run in interpreted mode
|
||||
since part of the expression may be running twice.
|
||||
|
||||
After selecting a mode, use the `SpelParserConfiguration` to configure the parser:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,
|
||||
this.getClass().getClassLoader());
|
||||
|
||||
SpelExpressionParser parser = new SpelExpressionParser(config);
|
||||
|
||||
Expression expr = parser.parseExpression("payload");
|
||||
|
||||
MyMessage message = new MyMessage();
|
||||
|
||||
Object payload = expr.getValue(message);
|
||||
----
|
||||
|
||||
When specifying the compiler mode it is also possible to specify a classloader (passing null is allowed).
|
||||
Compiled expressions will be defined in a child classloader created under any that is supplied.
|
||||
It is important to ensure if a classloader is specified it can see all the types involved in
|
||||
the expression evaluation process.
|
||||
If none is specified then a default classloader will be used (typically the context classloader for
|
||||
the thread that is running during expression evaluation).
|
||||
|
||||
The second way to configure the compiler is for use when SpEL is embedded inside some other
|
||||
component and it may not be possible to configure via a configuration object.
|
||||
In these cases it is possible to use a system property. The property
|
||||
`spring.expression.compiler.mode` can be set to one of the `SpelCompilerMode`
|
||||
enum values (`off`, `immediate` or `mixed`).
|
||||
|
||||
[[expressions-compiler-limitations]]
|
||||
===== Compiler limitations
|
||||
|
||||
With Spring Framework 4.1 the basic compilation framework is in place. However, the framework does not
|
||||
yet support compiling every kind of expression. The initial focus has been on the common expressions that are
|
||||
likely to be used in performance critical contexts. These kinds of expression cannot be compiled
|
||||
at the moment:
|
||||
|
||||
- expressions involving assignment
|
||||
- expressions relying on the conversion service
|
||||
- expressions using custom resolvers or accessors
|
||||
- expressions using selection or projection
|
||||
|
||||
More and more types of expression will be compilable in the future.
|
||||
|
||||
[[expressions-beandef]]
|
||||
=== Expression support for defining bean definitions
|
||||
|
|
|
|||
Loading…
Reference in New Issue