Avoid capturing TCCL when creating DefaultResourceLoaders

Previously, DefaultResourceLoader instances were created using the
default constructor. This causes the resource loader to capture the
TCCL that was in place at that time. This can lead to a class loader
leak if the resource loader is referenced directly or indirectly from
a static field of a class loaded by a different class loader.

This commit updates the creation of DefaultResourceLoader instances
in main code so that the resource load will use the class loader of
the creating class. In almost all cases this will be the same class
loader as was the thread context class loader that was being captured
so the change in behavior is minimal. Crucially, it will still address
the situation where the TCCL was different.

Note the DevTools' ApplicationContextResourceLoader has been updated
to explicitly use the TCCL. This ensures that it uses the restart
class loader which is required for DevTools to function correctly.

Fixes gh-20900
This commit is contained in:
Andy Wilkinson 2020-04-24 12:41:51 +01:00
parent d53be18582
commit dc75ca3942
5 changed files with 13 additions and 8 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -67,7 +67,8 @@ class DataSourceInitializer {
DataSourceInitializer(DataSource dataSource, DataSourceProperties properties, ResourceLoader resourceLoader) {
this.dataSource = dataSource;
this.properties = properties;
this.resourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader();
this.resourceLoader = (resourceLoader != null) ? resourceLoader
: new DefaultResourceLoader(getClass().getClassLoader());
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -47,7 +47,7 @@ public class MustacheResourceTemplateLoader implements TemplateLoader, ResourceL
private String charSet = "UTF-8";
private ResourceLoader resourceLoader = new DefaultResourceLoader();
private ResourceLoader resourceLoader = new DefaultResourceLoader(getClass().getClassLoader());
public MustacheResourceTemplateLoader() {
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -238,6 +238,8 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
private final Supplier<Collection<ProtocolResolver>> protocolResolvers;
ApplicationContextResourceLoader(Supplier<Collection<ProtocolResolver>> protocolResolvers) {
// Use the restart class loader
super(Thread.currentThread().getContextClassLoader());
this.protocolResolvers = protocolResolvers;
}

View File

@ -320,7 +320,8 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
this.environment = environment;
this.placeholdersResolver = new PropertySourcesPlaceholdersResolver(this.environment);
this.resourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader();
this.resourceLoader = (resourceLoader != null) ? resourceLoader
: new DefaultResourceLoader(getClass().getClassLoader());
this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,
getClass().getClassLoader());
this.patternResolver = new PathMatchingResourcePatternResolver(this.resourceLoader);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -33,7 +33,8 @@ import org.springframework.util.ResourceUtils;
*/
class StringToFileConverter implements Converter<String, File> {
private static final ResourceLoader resourceLoader = new DefaultResourceLoader();
private static final ResourceLoader resourceLoader = new DefaultResourceLoader(
StringToFileConverter.class.getClassLoader());
@Override
public File convert(String source) {