From dc75ca3942fba9a7773fdd0536b9289037b33668 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 24 Apr 2020 12:41:51 +0100 Subject: [PATCH] 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 --- .../boot/autoconfigure/jdbc/DataSourceInitializer.java | 5 +++-- .../mustache/MustacheResourceTemplateLoader.java | 4 ++-- .../restart/ClassLoaderFilesResourcePatternResolver.java | 4 +++- .../boot/context/config/ConfigFileApplicationListener.java | 3 ++- .../springframework/boot/convert/StringToFileConverter.java | 5 +++-- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializer.java index 5b862d40243..f4472fd0e4b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializer.java @@ -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()); } /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheResourceTemplateLoader.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheResourceTemplateLoader.java index 9c2702cccb7..54c2bd6f143 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheResourceTemplateLoader.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheResourceTemplateLoader.java @@ -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() { } diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ClassLoaderFilesResourcePatternResolver.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ClassLoaderFilesResourcePatternResolver.java index 82f0dea17f1..05452deeace 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ClassLoaderFilesResourcePatternResolver.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ClassLoaderFilesResourcePatternResolver.java @@ -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> protocolResolvers; ApplicationContextResourceLoader(Supplier> protocolResolvers) { + // Use the restart class loader + super(Thread.currentThread().getContextClassLoader()); this.protocolResolvers = protocolResolvers; } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java index feac3a0f02f..e2766a4389c 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java @@ -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); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/StringToFileConverter.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/StringToFileConverter.java index 70c486dcbde..f149d9d872b 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/StringToFileConverter.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/StringToFileConverter.java @@ -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 { - private static final ResourceLoader resourceLoader = new DefaultResourceLoader(); + private static final ResourceLoader resourceLoader = new DefaultResourceLoader( + StringToFileConverter.class.getClassLoader()); @Override public File convert(String source) {