Skip to content

Commit

Permalink
Re-use EvaluationContext in DefaultSubscriptionRegistry
Browse files Browse the repository at this point in the history
Rather than create a new EvaluationContext instance per evaluation, we
now create a statically shared instance, without the root object in it,
and re-use it for all evalutations.
  • Loading branch information
rstoyanchev committed Apr 9, 2018
1 parent 6deee3e commit 0009806
Showing 1 changed file with 27 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,14 @@
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;

import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
Expand Down Expand Up @@ -64,6 +63,10 @@ public class DefaultSubscriptionRegistry extends AbstractSubscriptionRegistry {
/** Default maximum number of entries for the destination cache: 1024 */
public static final int DEFAULT_CACHE_LIMIT = 1024;

/** Static evaluation context to reuse */
private static EvaluationContext messageEvalContext =
SimpleEvaluationContext.forPropertyAccessors(new SimpMessageHeaderPropertyAccessor()).build();


private PathMatcher pathMatcher = new AntPathMatcher();

Expand Down Expand Up @@ -191,7 +194,6 @@ private MultiValueMap<String, String> filterSubscriptions(
if (!this.selectorHeaderInUse) {
return allMatches;
}
EvaluationContext context = null;
MultiValueMap<String, String> result = new LinkedMultiValueMap<String, String>(allMatches.size());
for (String sessionId : allMatches.keySet()) {
for (String subId : allMatches.get(sessionId)) {
Expand All @@ -208,12 +210,8 @@ private MultiValueMap<String, String> filterSubscriptions(
result.add(sessionId, subId);
continue;
}
if (context == null) {
context = new StandardEvaluationContext(message);
context.getPropertyAccessors().add(new SimpMessageHeaderPropertyAccessor());
}
try {
if (expression.getValue(context, boolean.class)) {
if (Boolean.TRUE.equals(expression.getValue(messageEvalContext, message, Boolean.class))) {
result.add(sessionId, subId);
}
}
Expand Down Expand Up @@ -525,7 +523,7 @@ private static class SimpMessageHeaderPropertyAccessor implements PropertyAccess

@Override
public Class<?>[] getSpecificTargetClasses() {
return new Class<?>[] {MessageHeaders.class};
return new Class<?>[] {Message.class, MessageHeaders.class};
}

@Override
Expand All @@ -534,19 +532,29 @@ public boolean canRead(EvaluationContext context, Object target, String name) {
}

@Override
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
MessageHeaders headers = (MessageHeaders) target;
SimpMessageHeaderAccessor accessor =
MessageHeaderAccessor.getAccessor(headers, SimpMessageHeaderAccessor.class);
public TypedValue read(EvaluationContext context, Object target, String name) {
Object value;
if ("destination".equalsIgnoreCase(name)) {
value = accessor.getDestination();
if (target instanceof Message) {
value = name.equals("headers") ? ((Message) target).getHeaders() : null;
}
else {
value = accessor.getFirstNativeHeader(name);
if (value == null) {
value = headers.get(name);
else if (target instanceof MessageHeaders) {
MessageHeaders headers = (MessageHeaders) target;
SimpMessageHeaderAccessor accessor =
MessageHeaderAccessor.getAccessor(headers, SimpMessageHeaderAccessor.class);
Assert.state(accessor != null, "No SimpMessageHeaderAccessor");
if ("destination".equalsIgnoreCase(name)) {
value = accessor.getDestination();
}
else {
value = accessor.getFirstNativeHeader(name);
if (value == null) {
value = headers.get(name);
}
}
}
else {
// Should never happen...
throw new IllegalStateException("Expected Message or MessageHeaders.");
}
return new TypedValue(value);
}
Expand Down

0 comments on commit 0009806

Please sign in to comment.