Improve performance of MessageSource condition

Update the MessageSourceAutoConfiguration condition to skip scanning for
well known JARs. Results are now also cached.

Fixes gh-1689
This commit is contained in:
Phillip Webb 2014-10-10 11:38:51 -07:00
parent 828efb2589
commit 001f2d6c69
1 changed files with 73 additions and 1 deletions

View File

@ -17,6 +17,8 @@
package org.springframework.boot.autoconfigure;
import java.io.IOException;
import java.util.Iterator;
import java.util.Set;
import org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration.ResourceBundleCondition;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
@ -35,6 +37,7 @@ import org.springframework.core.annotation.Order;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.StringUtils;
import static org.springframework.util.StringUtils.commaDelimitedListToStringArray;
@ -44,6 +47,7 @@ import static org.springframework.util.StringUtils.trimAllWhitespace;
* {@link EnableAutoConfiguration Auto-configuration} for {@link MessageSource}.
*
* @author Dave Syer
* @author Phillip Webb
*/
@Configuration
@ConditionalOnMissingBean(MessageSource.class)
@ -99,11 +103,23 @@ public class MessageSourceAutoConfiguration {
protected static class ResourceBundleCondition extends SpringBootCondition {
private static ConcurrentReferenceHashMap<String, ConditionOutcome> cache = new ConcurrentReferenceHashMap<String, ConditionOutcome>();
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
String basename = context.getEnvironment().getProperty(
"spring.messages.basename", "messages");
ConditionOutcome outcome = cache.get(basename);
if (outcome == null) {
outcome = getMatchOutcomeForBasename(context, basename);
cache.put(basename, outcome);
}
return outcome;
}
private ConditionOutcome getMatchOutcomeForBasename(ConditionContext context,
String basename) {
for (String name : commaDelimitedListToStringArray(trimAllWhitespace(basename))) {
for (Resource resource : getResources(context.getClassLoader(), name)) {
if (resource.exists()) {
@ -118,7 +134,7 @@ public class MessageSourceAutoConfiguration {
private Resource[] getResources(ClassLoader classLoader, String name) {
try {
return new PathMatchingResourcePatternResolver(classLoader)
return new SkipPatternPathMatchingResourcePatternResolver(classLoader)
.getResources("classpath*:" + name + "*.properties");
}
catch (IOException ex) {
@ -128,4 +144,60 @@ public class MessageSourceAutoConfiguration {
}
/**
* {@link PathMatchingResourcePatternResolver} that skips well known JARs that don't
* contain messages.properties.
*/
private static class SkipPatternPathMatchingResourcePatternResolver extends
PathMatchingResourcePatternResolver {
private static final ClassLoader ROOT_CLASSLOADER;
static {
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
while (classLoader.getParent() != null) {
classLoader = classLoader.getParent();
}
ROOT_CLASSLOADER = classLoader;
}
private static final String[] SKIPPED = { "aspectjweaver-", "hibernate-core-",
"hsqldb-", "jackson-annotations-", "jackson-core-", "jackson-databind-",
"javassist-", "snakeyaml-", "spring-aop-", "spring-beans-",
"spring-boot-", "spring-boot-actuator-", "spring-boot-autoconfigure-",
"spring-core-", "spring-context-", "spring-data-commons-",
"spring-expression-", "spring-jdbc-", "spring-orm-", "spring-tx-",
"spring-web-", "spring-webmvc-", "tomcat-embed-", "joda-time-",
"hibernate-entitymanager-", "hibernate-validator-", "logback-classic-",
"logback-core-", "thymeleaf-" };
public SkipPatternPathMatchingResourcePatternResolver(ClassLoader classLoader) {
super(classLoader);
}
@Override
protected void addAllClassLoaderJarRoots(ClassLoader classLoader,
Set<Resource> result) {
if (classLoader != ROOT_CLASSLOADER) {
super.addAllClassLoaderJarRoots(classLoader, result);
}
};
@Override
protected Set<Resource> doFindAllClassPathResources(String path)
throws IOException {
Set<Resource> resources = super.doFindAllClassPathResources(path);
for (Iterator<Resource> iterator = resources.iterator(); iterator.hasNext();) {
Resource resource = iterator.next();
for (String skipped : SKIPPED) {
if (resource.getFilename().startsWith(skipped)) {
iterator.remove();
break;
}
}
}
return resources;
}
}
}