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:
parent
828efb2589
commit
001f2d6c69
|
|
@ -17,6 +17,8 @@
|
||||||
package org.springframework.boot.autoconfigure;
|
package org.springframework.boot.autoconfigure;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration.ResourceBundleCondition;
|
import org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration.ResourceBundleCondition;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
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.Resource;
|
||||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||||
|
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import static org.springframework.util.StringUtils.commaDelimitedListToStringArray;
|
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}.
|
* {@link EnableAutoConfiguration Auto-configuration} for {@link MessageSource}.
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
|
* @author Phillip Webb
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnMissingBean(MessageSource.class)
|
@ConditionalOnMissingBean(MessageSource.class)
|
||||||
|
|
@ -99,11 +103,23 @@ public class MessageSourceAutoConfiguration {
|
||||||
|
|
||||||
protected static class ResourceBundleCondition extends SpringBootCondition {
|
protected static class ResourceBundleCondition extends SpringBootCondition {
|
||||||
|
|
||||||
|
private static ConcurrentReferenceHashMap<String, ConditionOutcome> cache = new ConcurrentReferenceHashMap<String, ConditionOutcome>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||||
AnnotatedTypeMetadata metadata) {
|
AnnotatedTypeMetadata metadata) {
|
||||||
String basename = context.getEnvironment().getProperty(
|
String basename = context.getEnvironment().getProperty(
|
||||||
"spring.messages.basename", "messages");
|
"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 (String name : commaDelimitedListToStringArray(trimAllWhitespace(basename))) {
|
||||||
for (Resource resource : getResources(context.getClassLoader(), name)) {
|
for (Resource resource : getResources(context.getClassLoader(), name)) {
|
||||||
if (resource.exists()) {
|
if (resource.exists()) {
|
||||||
|
|
@ -118,7 +134,7 @@ public class MessageSourceAutoConfiguration {
|
||||||
|
|
||||||
private Resource[] getResources(ClassLoader classLoader, String name) {
|
private Resource[] getResources(ClassLoader classLoader, String name) {
|
||||||
try {
|
try {
|
||||||
return new PathMatchingResourcePatternResolver(classLoader)
|
return new SkipPatternPathMatchingResourcePatternResolver(classLoader)
|
||||||
.getResources("classpath*:" + name + "*.properties");
|
.getResources("classpath*:" + name + "*.properties");
|
||||||
}
|
}
|
||||||
catch (IOException ex) {
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue