Update resource handler Java config
This change separates out resource chain related methods previously in ResourceHandlerRegistration into a new class ResourceChainRegistration with the goal of improving readability. Along with that, the registration of caching resolver and transformer is now explicitly controled with a boolean flag (on the method used to obtain the ResourceChainRegistration) and an overloaded method also allows providing a Cache instance. Issue: SPR-12124
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.servlet.config.annotation;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.servlet.resource.CachingResourceResolver;
|
||||
import org.springframework.web.servlet.resource.CachingResourceTransformer;
|
||||
import org.springframework.web.servlet.resource.CssLinkResourceTransformer;
|
||||
import org.springframework.web.servlet.resource.PathResourceResolver;
|
||||
import org.springframework.web.servlet.resource.ResourceResolver;
|
||||
import org.springframework.web.servlet.resource.ResourceTransformer;
|
||||
import org.springframework.web.servlet.resource.VersionResourceResolver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Assists with the registration of resource resolvers and transformers.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.1
|
||||
*/
|
||||
public class ResourceChainRegistration {
|
||||
|
||||
private static final String DEFAULT_CACHE_NAME = "spring-resource-chain-cache";
|
||||
|
||||
private final List<ResourceResolver> resolvers = new ArrayList<ResourceResolver>(4);
|
||||
|
||||
private final List<ResourceTransformer> transformers = new ArrayList<ResourceTransformer>(4);
|
||||
|
||||
private boolean hasVersionResolver;
|
||||
|
||||
private boolean hasPathResolver;
|
||||
|
||||
private boolean hasCssLinkTransformer;
|
||||
|
||||
|
||||
public ResourceChainRegistration(boolean cacheResources) {
|
||||
this(cacheResources, cacheResources ? new ConcurrentMapCache(DEFAULT_CACHE_NAME) : null);
|
||||
}
|
||||
|
||||
public ResourceChainRegistration(boolean cacheResources, Cache cache) {
|
||||
Assert.isTrue(!cacheResources || cache != null, "'cache' is required when cacheResources=true");
|
||||
if (cacheResources) {
|
||||
this.resolvers.add(new CachingResourceResolver(cache));
|
||||
this.transformers.add(new CachingResourceTransformer(cache));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a resource resolver to the chain.
|
||||
* @param resolver the resolver to add
|
||||
* @return the current instance for chained method invocation
|
||||
*/
|
||||
public ResourceChainRegistration addResolver(ResourceResolver resolver) {
|
||||
Assert.notNull(resolver, "The provided ResourceResolver should not be null");
|
||||
this.resolvers.add(resolver);
|
||||
if (resolver instanceof VersionResourceResolver) {
|
||||
this.hasVersionResolver = true;
|
||||
}
|
||||
else if (resolver instanceof PathResourceResolver) {
|
||||
this.hasPathResolver = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a resource transformer to the chain.
|
||||
* @param transformer the transformer to add
|
||||
* @return the current instance for chained method invocation
|
||||
*/
|
||||
public ResourceChainRegistration addTransformer(ResourceTransformer transformer) {
|
||||
Assert.notNull(transformer, "The provided ResourceTransformer should not be null");
|
||||
this.transformers.add(transformer);
|
||||
if (transformer instanceof CssLinkResourceTransformer) {
|
||||
this.hasCssLinkTransformer = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
protected List<ResourceResolver> getResourceResolvers() {
|
||||
if (!this.hasPathResolver) {
|
||||
List<ResourceResolver> result = new ArrayList<ResourceResolver>(this.resolvers);
|
||||
result.add(new PathResourceResolver());
|
||||
return result;
|
||||
}
|
||||
return this.resolvers;
|
||||
}
|
||||
|
||||
protected List<ResourceTransformer> getResourceTransformers() {
|
||||
if (this.hasVersionResolver && !this.hasCssLinkTransformer) {
|
||||
List<ResourceTransformer> result = new ArrayList<ResourceTransformer>(this.transformers);
|
||||
boolean hasTransformers = !this.transformers.isEmpty();
|
||||
boolean hasCaching = hasTransformers && this.transformers.get(0) instanceof CachingResourceTransformer;
|
||||
result.add(hasCaching ? 1 : 0, new CssLinkResourceTransformer());
|
||||
return result;
|
||||
}
|
||||
return this.transformers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,27 +16,16 @@
|
||||
|
||||
package org.springframework.web.servlet.config.annotation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.servlet.resource.CachingResourceResolver;
|
||||
import org.springframework.web.servlet.resource.CachingResourceTransformer;
|
||||
import org.springframework.web.servlet.resource.ContentVersionStrategy;
|
||||
import org.springframework.web.servlet.resource.CssLinkResourceTransformer;
|
||||
import org.springframework.web.servlet.resource.FixedVersionStrategy;
|
||||
import org.springframework.web.servlet.resource.PathResourceResolver;
|
||||
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
|
||||
import org.springframework.web.servlet.resource.ResourceResolver;
|
||||
import org.springframework.web.servlet.resource.ResourceTransformer;
|
||||
import org.springframework.web.servlet.resource.VersionResourceResolver;
|
||||
import org.springframework.web.servlet.resource.VersionStrategy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Encapsulates information required to create a resource handlers.
|
||||
@@ -49,8 +38,6 @@ import org.springframework.web.servlet.resource.VersionStrategy;
|
||||
*/
|
||||
public class ResourceHandlerRegistration {
|
||||
|
||||
private static final String RESOURCE_CACHE_NAME = "spring-resourcehandler-cache";
|
||||
|
||||
private final ResourceLoader resourceLoader;
|
||||
|
||||
private final String[] pathPatterns;
|
||||
@@ -59,17 +46,7 @@ public class ResourceHandlerRegistration {
|
||||
|
||||
private Integer cachePeriod;
|
||||
|
||||
private List<ResourceResolver> customResolvers = new ArrayList<ResourceResolver>();
|
||||
|
||||
private List<ResourceTransformer> customTransformers = new ArrayList<ResourceTransformer>();
|
||||
|
||||
private boolean hasVersionResolver;
|
||||
|
||||
private boolean hasCssLinkTransformer;
|
||||
|
||||
private boolean isDevMode = false;
|
||||
|
||||
private Cache resourceCache;
|
||||
private ResourceChainRegistration resourceChainRegistration;
|
||||
|
||||
|
||||
/**
|
||||
@@ -100,78 +77,6 @@ public class ResourceHandlerRegistration {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a {@code ResourceResolver} to the chain, allowing to resolve server-side resources from
|
||||
* HTTP requests.
|
||||
*
|
||||
* <p>{@link ResourceResolver}s are registered, in the following order:
|
||||
* <ol>
|
||||
* <li>a {@link org.springframework.web.servlet.resource.CachingResourceResolver}
|
||||
* for caching the results of the next Resolvers; this resolver is only registered if you
|
||||
* did not provide your own instance of {@link CachingResourceResolver} at the beginning of the chain</li>
|
||||
* <li>all {@code ResourceResolver}s registered using this method, in the order of methods calls</li>
|
||||
* <li>a {@link VersionResourceResolver} if a versioning configuration has been applied with
|
||||
* {@code addVersionStrategy}, {@code addVersion}, etc.</li>
|
||||
* <li>a {@link PathResourceResolver} for resolving resources on the file system</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param resolver a {@link ResourceResolver} to add to the chain of resolvers
|
||||
* @return the same {@link ResourceHandlerRegistration} instance for chained method invocation
|
||||
* @see ResourceResolver
|
||||
* @since 4.1
|
||||
*/
|
||||
public ResourceHandlerRegistration addResolver(ResourceResolver resolver) {
|
||||
Assert.notNull(resolver, "The provided ResourceResolver should not be null");
|
||||
this.customResolvers.add(resolver);
|
||||
if (resolver instanceof VersionResourceResolver) {
|
||||
this.hasVersionResolver = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a {@code ResourceTransformer} to the chain, allowing to transform the content
|
||||
* of server-side resources when serving them to HTTP clients.
|
||||
*
|
||||
* <p>{@link ResourceTransformer}s are registered, in the following order:
|
||||
* <ol>
|
||||
* <li>a {@link org.springframework.web.servlet.resource.CachingResourceTransformer}
|
||||
* for caching the results of the next Transformers; this transformer is only registered if you
|
||||
* did not provide your own instance of {@link CachingResourceTransformer} at the beginning of the chain</li>
|
||||
* <li>a {@link CssLinkResourceTransformer} for updating links within CSS files; this transformer
|
||||
* is only registered if a versioning configuration has been applied with {@code addVersionStrategy},
|
||||
* {@code addVersion}, etc</li>
|
||||
* <li>all {@code ResourceTransformer}s registered using this method, in the order of methods calls</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param transformer a {@link ResourceTransformer} to add to the chain of transformers
|
||||
* @return the same {@link ResourceHandlerRegistration} instance for chained method invocation
|
||||
* @see ResourceResolver
|
||||
* @since 4.1
|
||||
*/
|
||||
public ResourceHandlerRegistration addTransformer(ResourceTransformer transformer) {
|
||||
Assert.notNull(transformer, "The provided ResourceTransformer should not be null");
|
||||
this.customTransformers.add(transformer);
|
||||
if (transformer instanceof CssLinkResourceTransformer) {
|
||||
this.hasCssLinkTransformer = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable automatic registration of caching Resolver/Transformer, thus disabling {@code Resource} caching
|
||||
* if no caching Resolver/Transformer was manually registered.
|
||||
* <p>Useful when updating static resources at runtime, i.e. during the development phase.</p>
|
||||
* @return the same {@link ResourceHandlerRegistration} instance for chained method invocation
|
||||
* @see ResourceResolver
|
||||
* @see ResourceTransformer
|
||||
* @since 4.1
|
||||
*/
|
||||
public ResourceHandlerRegistration enableDevMode() {
|
||||
this.isDevMode = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the cache period for the resources served by the resource handler, in seconds. The default is to not
|
||||
* send any cache headers but to rely on last-modified timestamps only. Set to 0 in order to send cache headers
|
||||
@@ -184,6 +89,47 @@ public class ResourceHandlerRegistration {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a chain of resource resolvers and transformers to use. This
|
||||
* can be useful for example to apply a version strategy to resource URLs.
|
||||
*
|
||||
* <p>If this method is not invoked, by default only a simple
|
||||
* {@link PathResourceResolver} is used in order to match URL paths to
|
||||
* resources under the configured locations.
|
||||
*
|
||||
* @param cacheResources whether to cache the result of resource resolution;
|
||||
* setting this to "true" is recommended for production (and "false" for
|
||||
* development, especially when applying a version strategy.
|
||||
* @return the same {@link ResourceHandlerRegistration} instance for chained method invocation
|
||||
* @since 4.1
|
||||
*/
|
||||
public ResourceChainRegistration resourceChain(boolean cacheResources) {
|
||||
this.resourceChainRegistration = new ResourceChainRegistration(cacheResources);
|
||||
return this.resourceChainRegistration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a chain of resource resolvers and transformers to use. This
|
||||
* can be useful for example to apply a version strategy to resource URLs.
|
||||
*
|
||||
* <p>If this method is not invoked, by default only a simple
|
||||
* {@link PathResourceResolver} is used in order to match URL paths to
|
||||
* resources under the configured locations.
|
||||
*
|
||||
* @param cacheResources whether to cache the result of resource resolution;
|
||||
* setting this to "true" is recommended for production (and "false" for
|
||||
* development, especially when applying a version strategy.
|
||||
* @param cache the cache to use for storing resolved and transformed resources;
|
||||
* by default a {@link org.springframework.cache.concurrent.ConcurrentMapCache}
|
||||
* is used.
|
||||
* @return the same {@link ResourceHandlerRegistration} instance for chained method invocation
|
||||
* @since 4.1
|
||||
*/
|
||||
public ResourceChainRegistration resourceChain(boolean cacheResources, Cache cache) {
|
||||
this.resourceChainRegistration = new ResourceChainRegistration(cacheResources, cache);
|
||||
return this.resourceChainRegistration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL path patterns for the resource handler.
|
||||
*/
|
||||
@@ -191,76 +137,21 @@ public class ResourceHandlerRegistration {
|
||||
return this.pathPatterns;
|
||||
}
|
||||
|
||||
protected List<ResourceResolver> getResourceResolvers() {
|
||||
if (this.customResolvers.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
List<ResourceResolver> resolvers = new ArrayList<ResourceResolver>();
|
||||
ResourceResolver first = this.customResolvers.get(0);
|
||||
if (!ClassUtils.isAssignable(CachingResourceResolver.class, first.getClass()) && !this.isDevMode) {
|
||||
resolvers.add(new CachingResourceResolver(getDefaultResourceCache()));
|
||||
}
|
||||
resolvers.addAll(this.customResolvers);
|
||||
ResourceResolver last = this.customResolvers.get(this.customResolvers.size() - 1);
|
||||
if (!ClassUtils.isAssignable(PathResourceResolver.class, last.getClass())) {
|
||||
resolvers.add(new PathResourceResolver());
|
||||
}
|
||||
return resolvers;
|
||||
}
|
||||
|
||||
protected List<ResourceTransformer> getResourceTransformers() {
|
||||
if (this.customTransformers.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
List<ResourceTransformer> transformers = new ArrayList<ResourceTransformer>();
|
||||
ResourceTransformer first = this.customTransformers.get(0);
|
||||
ResourceTransformer cachingTransformer = null;
|
||||
if (!this.isDevMode) {
|
||||
if (ClassUtils.isAssignable(CachingResourceTransformer.class, first.getClass())) {
|
||||
cachingTransformer = first;
|
||||
}
|
||||
else {
|
||||
cachingTransformer = new CachingResourceTransformer(getDefaultResourceCache());
|
||||
transformers.add(cachingTransformer);
|
||||
}
|
||||
}
|
||||
transformers.addAll(this.customTransformers);
|
||||
if (this.hasVersionResolver && !this.hasCssLinkTransformer) {
|
||||
transformers.add(cachingTransformer != null ? 1 : 0, new CssLinkResourceTransformer());
|
||||
}
|
||||
return transformers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link ResourceHttpRequestHandler} instance.
|
||||
*/
|
||||
protected ResourceHttpRequestHandler getRequestHandler() {
|
||||
Assert.isTrue(!CollectionUtils.isEmpty(locations), "At least one location is required for resource handling.");
|
||||
ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
|
||||
List<ResourceResolver> resourceResolvers = getResourceResolvers();
|
||||
if (!CollectionUtils.isEmpty(resourceResolvers)) {
|
||||
requestHandler.setResourceResolvers(resourceResolvers);
|
||||
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
|
||||
if (this.resourceChainRegistration != null) {
|
||||
handler.setResourceResolvers(this.resourceChainRegistration.getResourceResolvers());
|
||||
handler.setResourceTransformers(this.resourceChainRegistration.getResourceTransformers());
|
||||
}
|
||||
List<ResourceTransformer> resourceTransformers = getResourceTransformers();
|
||||
if (!CollectionUtils.isEmpty(resourceTransformers)) {
|
||||
requestHandler.setResourceTransformers(resourceTransformers);
|
||||
}
|
||||
requestHandler.setLocations(this.locations);
|
||||
handler.setLocations(this.locations);
|
||||
if (this.cachePeriod != null) {
|
||||
requestHandler.setCacheSeconds(this.cachePeriod);
|
||||
handler.setCacheSeconds(this.cachePeriod);
|
||||
}
|
||||
return requestHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a default instance of a {@code ConcurrentCacheMap} for
|
||||
* caching resolved/transformed resources.
|
||||
*/
|
||||
private Cache getDefaultResourceCache() {
|
||||
if(this.resourceCache == null) {
|
||||
this.resourceCache = new ConcurrentMapCache(RESOURCE_CACHE_NAME);
|
||||
}
|
||||
return this.resourceCache;
|
||||
return handler;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user