2222
2323import com .fasterxml .jackson .databind .JsonNode ;
2424import com .fasterxml .jackson .databind .node .ArrayNode ;
25- import com .google .common .base .Throwables ;
25+ import com .github .benmanes .caffeine .cache .Cache ;
26+ import com .github .benmanes .caffeine .cache .Caffeine ;
27+ import com .github .benmanes .caffeine .cache .Scheduler ;
2628import org .springframework .beans .factory .config .ConfigurableBeanFactory ;
2729import org .springframework .context .ApplicationContext ;
2830import org .springframework .context .ConfigurableApplicationContext ;
4547
4648import java .util .ArrayList ;
4749import java .util .List ;
48- import java .util .Map ;
49- import java .util .concurrent .ConcurrentHashMap ;
50+ import java .util .concurrent .TimeUnit ;
5051import java .util .stream .Stream ;
5152import java .util .stream .StreamSupport ;
5253
@@ -58,7 +59,10 @@ public class SpecExpressionResolver {
5859
5960 private final ApplicationContext appContext ;
6061 private final ExpressionParser expressionParser ;
61- private final Map <SpecExpressionContext , StandardEvaluationContext > evaluationCache = new ConcurrentHashMap <>(8 );
62+ private final Cache <SpecExpressionContext , StandardEvaluationContext > evaluationCache = Caffeine .newBuilder ()
63+ .scheduler (Scheduler .systemScheduler ())
64+ .expireAfterAccess (1 , TimeUnit .MINUTES )
65+ .build ();
6266
6367 private final ParserContext beanExpressionParserContext = new ParserContext () {
6468 @ Override
@@ -91,20 +95,19 @@ public <T> T evaluate(String expression, SpecExpressionContext context, Class<T>
9195
9296 ConfigurableBeanFactory beanFactory = ((ConfigurableApplicationContext ) appContext ).getBeanFactory ();
9397
94- StandardEvaluationContext sec = evaluationCache .get (context );
95- if (sec == null ) {
96- sec = new StandardEvaluationContext ();
97- sec .setRootObject (context );
98- sec .addPropertyAccessor (new BeanExpressionContextAccessor ());
99- sec .addPropertyAccessor (new BeanFactoryAccessor ());
100- sec .addPropertyAccessor (new MapAccessor ());
101- sec .addPropertyAccessor (new EnvironmentAccessor ());
102- sec .setBeanResolver (new BeanFactoryResolver (appContext ));
103- sec .setTypeLocator (new StandardTypeLocator (beanFactory .getBeanClassLoader ()));
98+ StandardEvaluationContext sec = evaluationCache .get (context , k -> {
99+ StandardEvaluationContext result = new StandardEvaluationContext ();
100+ result .setRootObject (context );
101+ result .addPropertyAccessor (new BeanExpressionContextAccessor ());
102+ result .addPropertyAccessor (new BeanFactoryAccessor ());
103+ result .addPropertyAccessor (new MapAccessor ());
104+ result .addPropertyAccessor (new EnvironmentAccessor ());
105+ result .setBeanResolver (new BeanFactoryResolver (appContext ));
106+ result .setTypeLocator (new StandardTypeLocator (beanFactory .getBeanClassLoader ()));
104107 ConversionService conversionService = beanFactory .getConversionService ();
105- if (conversionService != null ) sec .setTypeConverter (new StandardTypeConverter (conversionService ));
106- evaluationCache . put ( context , sec ) ;
107- }
108+ if (conversionService != null ) result .setTypeConverter (new StandardTypeConverter (conversionService ));
109+ return result ;
110+ });
108111
109112 return expr .getValue (sec , resType );
110113 } catch (ExpressionException ex ) {
0 commit comments