diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelCompiler.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelCompiler.java index a83bf5dbe0..847da65a73 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelCompiler.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelCompiler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,18 +63,20 @@ import org.springframework.util.StringUtils; *

Individual expressions can be compiled by calling {@code SpelCompiler.compile(expression)}. * * @author Andy Clement + * @author Juergen Hoeller * @since 4.1 */ public final class SpelCompiler implements Opcodes { - private static final Log logger = LogFactory.getLog(SpelCompiler.class); - private static final int CLASSES_DEFINED_LIMIT = 100; + private static final Log logger = LogFactory.getLog(SpelCompiler.class); + // A compiler is created for each classloader, it manages a child class loader of that // classloader and the child is used to load the compiled expressions. private static final Map compilers = new ConcurrentReferenceHashMap<>(); + // The child ClassLoader used to load the compiled expression classes private ChildClassLoader ccl; @@ -90,7 +92,7 @@ public final class SpelCompiler implements Opcodes { /** * Attempt compilation of the supplied expression. A check is made to see * if it is compilable before compilation proceeds. The check involves - * visiting all the nodes in the expression Ast and ensuring enough state + * visiting all the nodes in the expression AST and ensuring enough state * is known about them that bytecode can be generated for them. * @param expression the expression to compile * @return an instance of the class implementing the compiled expression, @@ -125,7 +127,7 @@ public final class SpelCompiler implements Opcodes { /** * Generate the class that encapsulates the compiled expression and define it. - * The generated class will be a subtype of CompiledExpression. + * The generated class will be a subtype of CompiledExpression. * @param expressionToCompile the expression to be compiled * @return the expression call, or {@code null} if the decision was to opt out of * compilation during code generation @@ -150,7 +152,7 @@ public final class SpelCompiler implements Opcodes { // Create getValue() method mv = cw.visitMethod(ACC_PUBLIC, "getValue", "(Ljava/lang/Object;Lorg/springframework/expression/EvaluationContext;)Ljava/lang/Object;", null, - new String[ ]{"org/springframework/expression/EvaluationException"}); + new String[] {"org/springframework/expression/EvaluationException"}); mv.visitCode(); CodeFlow cf = new CodeFlow(className, cw); @@ -187,7 +189,7 @@ public final class SpelCompiler implements Opcodes { /** * Load a compiled expression class. Makes sure the classloaders aren't used too much - * because they anchor compiled classes in memory and prevent GC. If you have expressions + * because they anchor compiled classes in memory and prevent GC. If you have expressions * continually recompiling over time then by replacing the classloader periodically * at least some of the older variants can be garbage collected. * @param name the name of the class @@ -202,6 +204,7 @@ public final class SpelCompiler implements Opcodes { return (Class) this.ccl.defineClass(name, bytes); } + /** * Factory method for compiler instances. The returned SpelCompiler will * attach a class loader as the child of the given class loader and this @@ -222,10 +225,12 @@ public final class SpelCompiler implements Opcodes { } /** - * Request that an attempt is made to compile the specified expression. It may fail if - * components of the expression are not suitable for compilation or the data types - * involved are not suitable for compilation. Used for testing. - * @return true if the expression was successfully compiled + * Request that an attempt is made to compile the specified expression. + * It may fail if components of the expression are not suitable for compilation + * or the data types involved are not suitable for compilation. Used for testing. + * @param expression the expression to compile + * @return {@code true} if the expression was successfully compiled, + * {@code false} otherwise */ public static boolean compile(Expression expression) { return (expression instanceof SpelExpression && ((SpelExpression) expression).compileExpression()); @@ -256,18 +261,21 @@ public final class SpelCompiler implements Opcodes { super(NO_URLS, classLoader); } - int getClassesDefinedCount() { - return this.classesDefinedCount; - } - public Class defineClass(String name, byte[] bytes) { Class clazz = super.defineClass(name, bytes, 0, bytes.length); this.classesDefinedCount++; return clazz; } + + public int getClassesDefinedCount() { + return this.classesDefinedCount; + } } + /** + * An ASM ClassWriter extension bound to the SpelCompiler's ClassLoader. + */ private class ExpressionClassWriter extends ClassWriter { public ExpressionClassWriter() {