mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Update DevTools' ResourceLoader to delegate to user's custom loader
Previously, when DevTools' was used it would set the application context's ResourceLoader and overwrite any custom ResourceLoader that had been configured. On the rare occasion when the user had customized the ResourceLoader this meant that the customization was lost and certain resources would become unavailable. This commit updates DevTools' ResourceLoader to delegate a custom ResourceLoader if one has been configured. If one has not been configured it delegates as before, i.e. to WebApplicationContextResourceLoader for web applications and to DefaultResourceLoader for all others apps. Closes gh-8010
This commit is contained in:
parent
b28d537c78
commit
6a0fb8e44c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
* Copyright 2012-2017 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.
|
||||
@ -18,6 +18,7 @@ package org.springframework.boot.devtools.restart;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
@ -40,6 +41,7 @@ import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.ServletContextResource;
|
||||
import org.springframework.web.context.support.ServletContextResourcePatternResolver;
|
||||
@ -59,7 +61,7 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
|
||||
private static final String WEB_CONTEXT_CLASS = "org.springframework.web.context."
|
||||
+ "WebApplicationContext";
|
||||
|
||||
private final ResourcePatternResolver delegate;
|
||||
private final ResourcePatternResolver patternResolverDelegate;
|
||||
|
||||
private final PathMatcher antPathMatcher = new AntPathMatcher();
|
||||
|
||||
@ -68,8 +70,19 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
|
||||
ClassLoaderFilesResourcePatternResolver(ApplicationContext applicationContext,
|
||||
ClassLoaderFiles classLoaderFiles) {
|
||||
this.classLoaderFiles = classLoaderFiles;
|
||||
this.delegate = getResourcePatternResolverFactory()
|
||||
.getResourcePatternResolver(applicationContext);
|
||||
this.patternResolverDelegate = getResourcePatternResolverFactory()
|
||||
.getResourcePatternResolver(applicationContext,
|
||||
retrieveResourceLoader(applicationContext));
|
||||
}
|
||||
|
||||
private ResourceLoader retrieveResourceLoader(ApplicationContext applicationContext) {
|
||||
Field field = ReflectionUtils.findField(applicationContext.getClass(),
|
||||
"resourceLoader", ResourceLoader.class);
|
||||
if (field == null) {
|
||||
return null;
|
||||
}
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
return (ResourceLoader) ReflectionUtils.getField(field, applicationContext);
|
||||
}
|
||||
|
||||
private ResourcePatternResolverFactory getResourcePatternResolverFactory() {
|
||||
@ -81,12 +94,12 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return this.delegate.getClassLoader();
|
||||
return this.patternResolverDelegate.getClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getResource(String location) {
|
||||
Resource candidate = this.delegate.getResource(location);
|
||||
Resource candidate = this.patternResolverDelegate.getResource(location);
|
||||
if (isDeleted(candidate)) {
|
||||
return new DeletedClassLoaderFileResource(location);
|
||||
}
|
||||
@ -96,7 +109,8 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
|
||||
@Override
|
||||
public Resource[] getResources(String locationPattern) throws IOException {
|
||||
List<Resource> resources = new ArrayList<Resource>();
|
||||
Resource[] candidates = this.delegate.getResources(locationPattern);
|
||||
Resource[] candidates = this.patternResolverDelegate
|
||||
.getResources(locationPattern);
|
||||
for (Resource candidate : candidates) {
|
||||
if (!isDeleted(candidate)) {
|
||||
resources.add(candidate);
|
||||
@ -190,8 +204,9 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
|
||||
private static class ResourcePatternResolverFactory {
|
||||
|
||||
public ResourcePatternResolver getResourcePatternResolver(
|
||||
ApplicationContext applicationContext) {
|
||||
return new PathMatchingResourcePatternResolver();
|
||||
ApplicationContext applicationContext, ResourceLoader resourceLoader) {
|
||||
return new PathMatchingResourcePatternResolver(resourceLoader == null
|
||||
? new DefaultResourceLoader() : resourceLoader);
|
||||
}
|
||||
|
||||
}
|
||||
@ -205,13 +220,14 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
|
||||
|
||||
@Override
|
||||
public ResourcePatternResolver getResourcePatternResolver(
|
||||
ApplicationContext applicationContext) {
|
||||
ApplicationContext applicationContext, ResourceLoader resourceLoader) {
|
||||
if (applicationContext instanceof WebApplicationContext) {
|
||||
return new ServletContextResourcePatternResolver(
|
||||
new WebApplicationContextResourceLoader(
|
||||
(WebApplicationContext) applicationContext));
|
||||
return new ServletContextResourcePatternResolver(resourceLoader == null
|
||||
? new WebApplicationContextResourceLoader(
|
||||
(WebApplicationContext) applicationContext)
|
||||
: resourceLoader);
|
||||
}
|
||||
return super.getResourcePatternResolver(applicationContext);
|
||||
return super.getResourcePatternResolver(applicationContext, resourceLoader);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
* Copyright 2012-2017 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.
|
||||
@ -31,17 +31,21 @@ import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
import org.springframework.web.context.support.ServletContextResource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link ClassLoaderFilesResourcePatternResolver}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class ClassLoaderFilesResourcePatternResolverTests {
|
||||
|
||||
@ -71,7 +75,7 @@ public class ClassLoaderFilesResourcePatternResolverTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResourceWhenHasServeletContextShouldReturnServletResource()
|
||||
public void getResourceWhenHasServletContextShouldReturnServletResource()
|
||||
throws Exception {
|
||||
GenericWebApplicationContext context = new GenericWebApplicationContext(
|
||||
new MockServletContext());
|
||||
@ -111,6 +115,27 @@ public class ClassLoaderFilesResourcePatternResolverTests {
|
||||
assertThat(resources).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customResourceLoaderIsUsedInNonWebApplication() throws Exception {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
ResourceLoader resourceLoader = mock(ResourceLoader.class);
|
||||
context.setResourceLoader(resourceLoader);
|
||||
this.resolver = new ClassLoaderFilesResourcePatternResolver(context, this.files);
|
||||
this.resolver.getResource("foo.txt");
|
||||
verify(resourceLoader).getResource("foo.txt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customResourceLoaderIsUsedInWebApplication() throws Exception {
|
||||
GenericWebApplicationContext context = new GenericWebApplicationContext(
|
||||
new MockServletContext());
|
||||
ResourceLoader resourceLoader = mock(ResourceLoader.class);
|
||||
context.setResourceLoader(resourceLoader);
|
||||
this.resolver = new ClassLoaderFilesResourcePatternResolver(context, this.files);
|
||||
this.resolver.getResource("foo.txt");
|
||||
verify(resourceLoader).getResource("foo.txt");
|
||||
}
|
||||
|
||||
private File createFile(File folder, String name) throws IOException {
|
||||
File file = new File(folder, name);
|
||||
FileCopyUtils.copy("test".getBytes(), file);
|
||||
|
Loading…
Reference in New Issue
Block a user