Spring Boot
提供的用于向Servlet
容器注册Filter
的类的抽象基类,实现了接口ServletContextInitializer
。适用于Servlet 3.0 +
。对于该抽象基类,Spring Boot
提供了两个实现类:
FilterRegistrationBean
注册一个
Filter
对象到Servlet
容器。DelegatingFilterProxyRegistrationBean
注册一个
DelegatingFilterProxy Filter
对象到Servlet
容器。该DelegatingFilterProxy
对象其实绑定了另外特定名称的Filter bean
。真正处理请求时,对DelegatingFilterProxy
的调用最终是调用它所绑定的Filter bean
上。
源代码
源代码版本 : Spring Boot 2.1.3 RELEASE
package org.springframework.boot.web.servlet;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.FilterRegistration.Dynamic;
import javax.servlet.ServletContext;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
public abstract class AbstractFilterRegistrationBean<T extends Filter>
extends DynamicRegistrationBean<Dynamic> {
/**
* Filters that wrap the servlet request should be ordered less than or equal to this.
* @deprecated since 2.1.0 in favor of
* {@code OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER}
*/
@Deprecated
protected static final int REQUEST_WRAPPER_FILTER_MAX_ORDER = 0;
private static final String[] DEFAULT_URL_MAPPINGS = { "/*" };
private Set<ServletRegistrationBean<?>> servletRegistrationBeans = new LinkedHashSet<>();
private Set<String> servletNames = new LinkedHashSet<>();
private Set<String> urlPatterns = new LinkedHashSet<>();
private EnumSet<DispatcherType> dispatcherTypes;
private boolean matchAfter = false;
/**
* Create a new instance to be registered with the specified
* ServletRegistrationBeans.
* @param servletRegistrationBeans associate ServletRegistrationBeans
*/
AbstractFilterRegistrationBean(
ServletRegistrationBean<?>... servletRegistrationBeans) {
Assert.notNull(servletRegistrationBeans,
"ServletRegistrationBeans must not be null");
Collections.addAll(this.servletRegistrationBeans, servletRegistrationBeans);
}
/**
* Set ServletRegistrationBeans that the filter will be registered against.
* @param servletRegistrationBeans the Servlet registration beans
*/
public void setServletRegistrationBeans(
Collection<? extends ServletRegistrationBean<?>> servletRegistrationBeans) {
Assert.notNull(servletRegistrationBeans,
"ServletRegistrationBeans must not be null");
this.servletRegistrationBeans = new LinkedHashSet<>(servletRegistrationBeans);
}
/**
* Return a mutable collection of the ServletRegistrationBean that the filter
* will be registered against. ServletRegistrationBeans.
* @return the Servlet registration beans
* @see #setServletNames
* @see #setUrlPatterns
*/
public Collection<ServletRegistrationBean<?>> getServletRegistrationBeans() {
return this.servletRegistrationBeans;
}
/**
* Add ServletRegistrationBeans for the filter.
* @param servletRegistrationBeans the servlet registration beans to add
* @see #setServletRegistrationBeans
*/
public void addServletRegistrationBeans(
ServletRegistrationBean<?>... servletRegistrationBeans) {
Assert.notNull(servletRegistrationBeans,
"ServletRegistrationBeans must not be null");
Collections.addAll(this.servletRegistrationBeans, servletRegistrationBeans);
}
/**
* Set servlet names that the filter will be registered against. This will replace any
* previously specified servlet names.
* @param servletNames the servlet names
* @see #setServletRegistrationBeans
* @see #setUrlPatterns
*/
public void setServletNames(Collection<String> servletNames) {
Assert.notNull(servletNames, "ServletNames must not be null");
this.servletNames = new LinkedHashSet<>(servletNames);
}
/**
* Return a mutable collection of servlet names that the filter will be registered
* against.
* @return the servlet names
*/
public Collection<String> getServletNames() {
return this.servletNames;
}
/**
* Add servlet names for the filter.
* @param servletNames the servlet names to add
*/
public void addServletNames(String... servletNames) {
Assert.notNull(servletNames, "ServletNames must not be null");
this.servletNames.addAll(Arrays.asList(servletNames));
}
/**
* Set the URL patterns that the filter will be registered against. This will replace
* any previously specified URL patterns.
* @param urlPatterns the URL patterns
* @see #setServletRegistrationBeans
* @see #setServletNames
*/
public void setUrlPatterns(Collection<String> urlPatterns) {
Assert.notNull(urlPatterns, "UrlPatterns must not be null");
this.urlPatterns = new LinkedHashSet<>(urlPatterns);
}
/**
* Return a mutable collection of URL patterns, as defined in the Servlet
* specification, that the filter will be registered against.
* @return the URL patterns
*/
public Collection<String> getUrlPatterns() {
return this.urlPatterns;
}
/**
* Add URL patterns, as defined in the Servlet specification, that the filter will be
* registered against.
* @param urlPatterns the URL patterns
*/
public void addUrlPatterns(String... urlPatterns) {
Assert.notNull(urlPatterns, "UrlPatterns must not be null");
Collections.addAll(this.urlPatterns, urlPatterns);
}
/**
* Convenience method to #setDispatcherTypes(EnumSet) set dispatcher types
* using the specified elements.
* @param first the first dispatcher type
* @param rest additional dispatcher types
*/
public void setDispatcherTypes(DispatcherType first, DispatcherType... rest) {
this.dispatcherTypes = EnumSet.of(first, rest);
}
/**
* Sets the dispatcher types that should be used with the registration. If not
* specified the types will be deduced based on the value of
* #isAsyncSupported().
* @param dispatcherTypes the dispatcher types
*/
public void setDispatcherTypes(EnumSet<DispatcherType> dispatcherTypes) {
this.dispatcherTypes = dispatcherTypes;
}
/**
* Set if the filter mappings should be matched after any declared filter mappings of
* the ServletContext. Defaults to false indicating the filters are supposed
* to be matched before any declared filter mappings of the ServletContext.
* @param matchAfter if filter mappings are matched after
*/
public void setMatchAfter(boolean matchAfter) {
this.matchAfter = matchAfter;
}
/**
* Return if filter mappings should be matched after any declared Filter mappings of
* the ServletContext.
* @return if filter mappings are matched after
*/
public boolean isMatchAfter() {
return this.matchAfter;
}
@Override
protected String getDescription() {
Filter filter = getFilter();
Assert.notNull(filter, "Filter must not be null");
return "filter " + getOrDeduceName(filter);
}
// 实现基类定义的模版方法,将 Filter 注册到 Servlet 容器,
// 在该方法之后,会调用 configure 方法配置该过滤器注册
@Override
protected Dynamic addRegistration(String description, ServletContext servletContext) {
Filter filter = getFilter();
return servletContext.addFilter(getOrDeduceName(filter), filter);
}
/**
* Configure registration settings. Subclasses can override this method to perform
* additional configuration if required.
* 配置过滤器注册
* @param registration the registration
*/
@Override
protected void configure(FilterRegistration.Dynamic registration) {
super.configure(registration);
EnumSet<DispatcherType> dispatcherTypes = this.dispatcherTypes;
if (dispatcherTypes == null) {
dispatcherTypes = EnumSet.of(DispatcherType.REQUEST);
}
Set<String> servletNames = new LinkedHashSet<>();
for (ServletRegistrationBean<?> servletRegistrationBean : this.servletRegistrationBeans) {
servletNames.add(servletRegistrationBean.getServletName());
}
servletNames.addAll(this.servletNames);
if (servletNames.isEmpty() && this.urlPatterns.isEmpty()) {
// 如果没有指定 servletNames ,也没有指定 urlPatterns,
// 则将该过滤器映射到缺省路径 : /*
registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter,
DEFAULT_URL_MAPPINGS);
}
else {
if (!servletNames.isEmpty()) {
// 如果指定了 servletNames,则将该过滤器映射到这些 Servlet
registration.addMappingForServletNames(dispatcherTypes, this.matchAfter,
StringUtils.toStringArray(servletNames));
}
if (!this.urlPatterns.isEmpty()) {
// 如果指定了 urlPatterns,则将这些过滤器映射到这些 urlPatterns
registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter,
StringUtils.toStringArray(this.urlPatterns));
}
}
}
/**
* Return the Filter to be registered.
* 抽象方法,留给实现类用于提供要注册到Servlet容器的Filter。
* @return the filter
*/
public abstract T getFilter();
@Override
public String toString() {
StringBuilder builder = new StringBuilder(getOrDeduceName(this));
if (this.servletNames.isEmpty() && this.urlPatterns.isEmpty()) {
builder.append(" urls=").append(Arrays.toString(DEFAULT_URL_MAPPINGS));
}
else {
if (!this.servletNames.isEmpty()) {
builder.append(" servlets=").append(this.servletNames);
}
if (!this.urlPatterns.isEmpty()) {
builder.append(" urls=").append(this.urlPatterns);
}
}
return builder.toString();
}
}