Skip to content

ConversionService performance regression [SPR-14929] #19496

Closed
@spring-projects-issues

Description

@spring-projects-issues

Gary Russell opened SPR-14929 and commented

Consider the following:

public class SpELTests {

	@Test
	public void test() {
		Expression exp = new SpelExpressionParser().parseExpression(
				"#target.filter(headers['dummyHeader'] != null "
				+ "? headers['dummyHeader'] "
				+ ": T(org.springframework.util.Assert).isTrue(false, 'required header not available: dummyHeader'))");
		Message<String> message = MessageBuilder.withPayload("foo").setHeader("dummyHeader", "bar").build();
		EvaluationContext context = new StandardEvaluationContext();
		context.setVariable("target", new DummyFilter());
		StopWatch watch = new StopWatch();
		watch.start();
		for (int i = 0; i < 5000; i++) {
			Object value = exp.getValue(context, message);
		}
		watch.stop();
		System.out.println("Elapsed: " + watch.getTotalTimeSeconds());
	}

	public static class DummyFilter {

		@Filter
		public boolean filter(@Header("dummyHeader") String dummyValue) {
			return true;
		}

	}

}

When run with Spring Framework 4.3.3 it runs in < 0.5 seconds; with 4.3.4 it takes 40+ seconds.

With YourKit, I tracked the problem down to DefaultConversionService.getConverter() with source and target type descriptors:

java.lang.String
@org.springframework.messaging.handler.annotation.Header java.lang.String

The performance issue is because this.converterCache.get(key); seems to miss on every iteration (which in turn causes AnnotationUtils.getDefaultValue() which is where the cost is incurred). getDefaultConverter() correctly returns a NoOp converter which is inserted into the cache but, for some reason, that entry is not found in later iterations.

After several iterations, this.converterCache contains

{ConverterCacheKey [sourceType = java.lang.String, targetType = @org.springframework.messaging.handler.annotation.Header java.lang.String]=NO_OP, 
ConverterCacheKey [sourceType = java.lang.String, targetType = @org.springframework.messaging.handler.annotation.Header java.lang.String]=NO_OP, 
ConverterCacheKey [sourceType = java.lang.String, targetType = java.lang.String]=NO_OP, 
ConverterCacheKey [sourceType = java.lang.String, targetType = @org.springframework.messaging.handler.annotation.Header java.lang.String]=NO_OP, 
ConverterCacheKey [sourceType = java.lang.String, targetType = @org.springframework.messaging.handler.annotation.Header java.lang.String]=NO_OP, 
ConverterCacheKey [sourceType = java.lang.Boolean, targetType = java.lang.Boolean]=NO_OP}

With 4.3.3, I this.converterCache contains:

{ConverterCacheKey [sourceType = java.lang.String, targetType = @org.springframework.messaging.handler.annotation.Header java.lang.String]=NO_OP, 
ConverterCacheKey [sourceType = java.lang.String, targetType = java.lang.String]=NO_OP, 
ConverterCacheKey [sourceType = java.lang.Boolean, targetType = java.lang.Boolean]=NO_OP}

So the issue seems to be the cache entries are not found, perhaps some problem with the hash.


Affects: 4.3.4

Issue Links:

0 votes, 7 watchers

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: regressionA bug that is also a regression

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions