19
19
import java .util .ArrayList ;
20
20
import java .util .Collections ;
21
21
import java .util .List ;
22
+ import java .util .Map ;
23
+ import java .util .concurrent .ConcurrentHashMap ;
22
24
25
+ import org .springframework .core .SmartClassLoader ;
23
26
import org .springframework .expression .EvaluationException ;
24
27
import org .springframework .expression .TypeLocator ;
25
28
import org .springframework .expression .spel .SpelEvaluationException ;
@@ -48,6 +51,8 @@ public class StandardTypeLocator implements TypeLocator {
48
51
49
52
private final List <String > importPrefixes = new ArrayList <>(1 );
50
53
54
+ private final Map <String , Class <?>> typeCache = new ConcurrentHashMap <>();
55
+
51
56
52
57
/**
53
58
* Create a {@code StandardTypeLocator} for the default {@link ClassLoader}
@@ -110,6 +115,21 @@ public List<String> getImportPrefixes() {
110
115
*/
111
116
@ Override
112
117
public Class <?> findType (String typeName ) throws EvaluationException {
118
+ Class <?> cachedType = this .typeCache .get (typeName );
119
+ if (cachedType != null ) {
120
+ return cachedType ;
121
+ }
122
+ Class <?> loadedType = loadType (typeName );
123
+ if (loadedType != null &&
124
+ !(this .classLoader instanceof SmartClassLoader scl && scl .isClassReloadable (loadedType ))) {
125
+ this .typeCache .put (typeName , loadedType );
126
+ return loadedType ;
127
+ }
128
+ throw new SpelEvaluationException (SpelMessage .TYPE_NOT_FOUND , typeName );
129
+ }
130
+
131
+ @ Nullable
132
+ private Class <?> loadType (String typeName ) {
113
133
try {
114
134
return ClassUtils .forName (typeName , this .classLoader );
115
135
}
@@ -125,7 +145,7 @@ public Class<?> findType(String typeName) throws EvaluationException {
125
145
// might be a different prefix
126
146
}
127
147
}
128
- throw new SpelEvaluationException ( SpelMessage . TYPE_NOT_FOUND , typeName ) ;
148
+ return null ;
129
149
}
130
150
131
151
}
0 commit comments