Spring Filter
使用
实现filter接口
public class A implements java.servletx.Filter{
private FilterConfig filterConfig = null;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
paramValue = filterConfig.getInitParameter("encoding");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("过滤器A");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
this.filterConfig = null;
}
}
spring注册
<filter>
<filter-name>A</filter-name>
<filter-class>A</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>GB2312</param-value>
</init-param>
</filter>
springboot注册
//继承FilterRegistrationBean springboot 会自动扫描所有的FilterRegistrationBean 将返回的filter注册到容器中
public class AuthFilterRegistrationBean extends FilterRegistrationBean<Filter> {
@Autowired
UserService userService;
@Override
public Filter getFilter() {
return new AuthFilter();
}
class AuthFilter implements Filter {
...
}
}
源码解读
请求过滤需要的Filter接口
public interface Filter {
default void init(FilterConfig filterConfig) throws ServletException {
}
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
default void destroy() {
}
}
public interface FilterChain {
void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}
public interface FilterConfig {
String getFilterName();
ServletContext getServletContext();
String getInitParameter(String var1);
Enumeration<String> getInitParameterNames();
}
需要注意:
如果过滤器中没有调用chain.doFilter 那么
1. 后面的拦截器都不会执行
2. servlet.service 也不执行 开始弹出栈帧 相当于拦截器
//FilterChain实现
public final class ApplicationFilterChain implements FilterChain {
//filter完成后 执行 service 方法
//生命周期是servlet的生命周期
private Servlet servlet = null;
//定义多个filterConfig 通过filterConfig 获取filter
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
//用来判断是否责任链是否结束 当前位置
private int pos = 0;
//过滤链总的大小
private int n = 0;
//添加一个过滤器
void addFilter(ApplicationFilterConfig filterConfig) {
ApplicationFilterConfig[] newFilters = this.filters;
int var3 = newFilters.length;
//先判断是否已存在
for(int var4 = 0; var4 < var3; ++var4) {
ApplicationFilterConfig filter = newFilters[var4];
if (filter == filterConfig) {
return;
}
}
//数组扩容
if (this.n == this.filters.length) {
newFilters = new ApplicationFilterConfig[this.n + 10];
System.arraycopy(this.filters, 0, newFilters, 0, this.n);
this.filters = newFilters;
}
//把filter加进去 2个操作
//容量加1
//数组内容加1
this.filters[this.n++] = filterConfig;
}
//链式调用的方法 这个方法只是判断是否开启安全管理
//具体的处理在internalDoFilter这个方法
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
if (Globals.IS_SECURITY_ENABLED) {
ServletRequest req = request;
ServletResponse res = response;
try {
AccessController.doPrivileged(() -> {
this.internalDoFilter(req, res);
return null;
});
} catch (PrivilegedActionException var7) {
Exception e = var7.getException();
if (e instanceof ServletException) {
throw (ServletException)e;
}
if (e instanceof IOException) {
throw (IOException)e;
}
if (e instanceof RuntimeException) {
throw (RuntimeException)e;
}
throw new ServletException(e.getMessage(), e);
}
} else {
this.internalDoFilter(request, response);
}
}
//具体的过滤处理
private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
//判断是否已经到过滤器链的结束
//如果过滤器中没有chain.doFilter 那么就会开始退栈 导致service方法不执行
if (this.pos < this.n) {
//pos加1
//获取下一个过滤器
ApplicationFilterConfig filterConfig = this.filters[this.pos++];
try {
Filter filter = filterConfig.getFilter();
if (request.isAsyncSupported() && "false".equalsIgnoreCase(filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", Boolean.FALSE);
}
//调用过滤器的方法
if (Globals.IS_SECURITY_ENABLED) {
Principal principal = ((HttpServletRequest)request).getUserPrincipal();
Object[] args = new Object[]{request, response, this};
SecurityUtil.doAsPrivilege("doFilter", filter, classType, args, principal);
} else {
filter.doFilter(request, response, this);
}
} catch (ServletException | RuntimeException | IOException var15) {
throw var15;
} catch (Throwable var16) {
Throwable e = ExceptionUtils.unwrapInvocationTargetException(var16);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.filter"), e);
}
} else {
try {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(request);
lastServicedResponse.set(response);
}
if (request.isAsyncSupported() && !this.servletSupportsAsync) {
request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", Boolean.FALSE);
}
//最后一个过滤器用进入servlet 的 service 方法
//没调用一次doFilter 栈帧都会增长
//这里需要注意,没有return 所以过滤器链 和 所有过滤器 的栈帧不会退出,会等待servlet.service执行完毕
if (request instanceof HttpServletRequest && response instanceof HttpServletResponse && Globals.IS_SECURITY_ENABLED) {
Principal principal = ((HttpServletRequest)request).getUserPrincipal();
Object[] args = new Object[]{request, response};
SecurityUtil.doAsPrivilege("service", this.servlet, classTypeUsedInService, args, principal);
} else {
this.servlet.service(request, response);
}
} catch (ServletException | RuntimeException | IOException var17) {
throw var17;
} catch (Throwable var18) {
Throwable e = ExceptionUtils.unwrapInvocationTargetException(var18);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.servlet"), e);
} finally {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set((Object)null);
lastServicedResponse.set((Object)null);
}
}
}
}
}
应用启动需要的接口
- ApplicationFilterConfig
- FilterDef
- FilterMap
//filterchain中添加的是这个类
//这个类是依赖FilterDef生成的
//Filter类的初始化又依赖这个类
public final class ApplicationFilterConfig implements FilterConfig, Serializable {
//应用上下文
private final transient Context context;
//过滤器
private transient Filter filter = null;
//过滤器定义
private final FilterDef filterDef;
//初始化filter
private void initFilter() throws ServletException {
if (this.context instanceof StandardContext && this.context.getSwallowOutput()) {
boolean var5 = false;
try {
var5 = true;
SystemLogHandler.startCapture();
//根据filterconfig初始化filter
this.filter.init(this);
var5 = false;
} finally {
if (var5) {
String capturedlog = SystemLogHandler.stopCapture();
if (capturedlog != null && capturedlog.length() > 0) {
this.getServletContext().log(capturedlog);
}
}
}
String capturedlog = SystemLogHandler.stopCapture();
if (capturedlog != null && capturedlog.length() > 0) {
this.getServletContext().log(capturedlog);
}
} else {
this.filter.init(this);
}
//注册到java jmx管理中心
this.registerJMX();
}
}
public class FilterDef implements Serializable {
//filter对象实例
private transient Filter filter = null;
//类名 反射会用到
private String filterClass = null;
//filter对应的别名
private String filterName = null;
//参数 用于filter的初始化init
private final Map<String, String> parameters = new HashMap();
}
public class FilterMap extends XmlEncodingBase implements Serializable {
private String filterName = null;
private String[] servletNames = new String[0];
}
启动前的加载过程
- ServletContext
- ApplicationContext
- StandardContext
servlet上下文 接口中声明 添加filter接口 用来将filter添加到应用上下文
生成webserver需要用到这个实例
public interface ServletContext {
//通过类名加载
javax.servlet.FilterRegistration.Dynamic addFilter(String var1, String var2);
//直接加载实例
javax.servlet.FilterRegistration.Dynamic addFilter(String var1, Filter var2);
//通过类型加载
javax.servlet.FilterRegistration.Dynamic addFilter(String var1, Class<? extends Filter> var2);
}
ApplicationContext
实现了 ServletContext 中的 addFilter 方法
向属性中的StandandContext实例添加filterDef
public class ApplicationContext implements ServletContext {
//标准上下文属性 包含 filterConfigs filterMaps filterDefs 属性
private final StandardContext context;
//调用StandandContext添加filterDef
private FilterRegistration.Dynamic addFilter(String filterName,
String filterClass, Filter filter) throws IllegalStateException {
if (filterName == null || filterName.equals("")) {
throw new IllegalArgumentException(sm.getString(
"applicationContext.invalidFilterName", filterName));
}
if (!context.getState().equals(LifecycleState.STARTING_PREP)) {
//TODO Spec breaking enhancement to ignore this restriction
throw new IllegalStateException(
sm.getString("applicationContext.addFilter.ise",
getContextPath()));
}
FilterDef filterDef = context.findFilterDef(filterName);
// Assume a 'complete' FilterRegistration is one that has a class and
// a name
if (filterDef == null) {
filterDef = new FilterDef();
filterDef.setFilterName(filterName);
context.addFilterDef(filterDef);
} else {
if (filterDef.getFilterName() != null &&
filterDef.getFilterClass() != null) {
return null;
}
}
if (filter == null) {
filterDef.setFilterClass(filterClass);
} else {
filterDef.setFilterClass(filter.getClass().getName());
filterDef.setFilter(filter);
}
return new ApplicationFilterRegistration(filterDef, context);
}
}
StandandContext类
filter关键的3个属性和2个方法
-
filterMaps
-
filterDefs
-
filterConfigs
-
addFilterDef(填充filterDef对象)
-
filterStart(初始化 filterConfigs )
在ApplicationContext中调用addFilterDef方法
//tomcat 标准 context
public class StandardContext extends ContainerBase
implements Context, NotificationEmitter {
//servletContext
protected ApplicationContext context = null;
//获取servletContext
@Override
public ServletContext getServletContext() {
if (context == null) {
context = new ApplicationContext(this);
if (altDDName != null)
context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
}
return context.getFacade();
}
//filterMaps 封装的对象
private final ContextFilterMaps filterMaps = new ContextFilterMaps();
@Override
//servletContext添加filter时调用
public void addFilterMap(FilterMap filterMap) {
validateFilterMap(filterMap);
// Add this filter mapping to our registered set
filterMaps.add(filterMap);
fireContainerEvent("addFilterMap", filterMap);
}
//获取filterMaps
//请求到达时获取
@Override
public FilterMap[] findFilterMaps() {
return filterMaps.asArray();
}
//filtername 和 filterconfig 映射
private Map<String, ApplicationFilterConfig> filterConfigs = new HashMap<>();
//通过filtername获取filterconfig bean实例
public FilterConfig findFilterConfig(String name) {
return filterConfigs.get(name);
}
//通过 filterDefs 生成 filterconfigs 映射
/**
* Configure and initialize the set of filters for this Context.
* @return <code>true</code> if all filter initialization completed
* successfully, or <code>false</code> otherwise.
*/
public boolean filterStart() {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Starting filters");
}
// Instantiate and record a FilterConfig for each defined filter
boolean ok = true;
synchronized (filterConfigs) {
filterConfigs.clear();
for (Entry<String,FilterDef> entry : filterDefs.entrySet()) {
String name = entry.getKey();
if (getLogger().isDebugEnabled()) {
getLogger().debug(" Starting filter '" + name + "'");
}
try {
ApplicationFilterConfig filterConfig =
new ApplicationFilterConfig(this, entry.getValue());
filterConfigs.put(name, filterConfig);
} catch (Throwable t) {
t = ExceptionUtils.unwrapInvocationTargetException(t);
ExceptionUtils.handleThrowable(t);
getLogger().error(sm.getString(
"standardContext.filterStart", name), t);
ok = false;
}
}
}
return ok;
}
//filterDefs定义
private Map<String, FilterDef> filterDefs = new HashMap<>();
//添加filterDef
public void addFilterDef(FilterDef filterDef) {
synchronized (filterDefs) {
filterDefs.put(filterDef.getFilterName(), filterDef);
}
fireContainerEvent("addFilterDef", filterDef);
}
//查找filterDef
public FilterDef findFilterDef(String filterName) {
synchronized (filterDefs) {
return filterDefs.get(filterName);
}
}
}
ServletContextInitializer
对ServletContext对象进行初始化操作
//servlet上下文初始化接口
public interface ServletContextInitializer {
//给servletContext填充属性 进行初始化
//异步操作 先实例 再初始化
void onStartup(ServletContext servletContext) throws ServletException;
}
ServletContextInitializer的实现
public abstract class AbstractFilterRegistrationBean<T extends Filter> extends DynamicRegistrationBean<Dynamic> {
public final void onStartup(ServletContext servletContext) throws ServletException {
String description = this.getDescription();
if (!this.isEnabled()) {
logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
} else {
//注册
this.register(description, servletContext);
}
}
protected final void register(String description, ServletContext servletContext) {
D registration = this.addRegistration(description, servletContext);
if (registration == null) {
logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)");
} else {
//配置registration
this.configure(registration);
}
}
protected Dynamic addRegistration(String description, ServletContext servletContext) {
Filter filter = this.getFilter();
//servletContext 添加 filter
return servletContext.addFilter(this.getOrDeduceName(filter), filter);
}
}
通过配置将AbstractFilterRegistrationBean加载到容器中
并且配置到servlet的ServletContextInitializerBeans中
等待被webserver(tomcat)调用
//封装多个servletContenctInitializer上下文初始化接口实例
//通过beanFactory ioc 容器来生成上下文实例
public class ServletContextInitializerBeans extends AbstractCollection<ServletContextInitializer> {
//一个类型和初始化接口的映射
private final MultiValueMap<Class<?>, ServletContextInitializer> initializers = new LinkedMultiValueMap();
public ServletContextInitializerBeans(ListableBeanFactory beanFactory, Class<? extends ServletContextInitializer>... initializerTypes) {
}
}
TomcatStarter
调用 ServletContextInitializer.onStartup(ServletContext) 来初始化 ServletContext
class TomcatStarter implements ServletContainerInitializer {
private static final Log logger = LogFactory.getLog(TomcatStarter.class);
private final ServletContextInitializer[] initializers;
private volatile Exception startUpException;
TomcatStarter(ServletContextInitializer[] initializers) {
this.initializers = initializers;
}
public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {
try {
ServletContextInitializer[] var3 = this.initializers;
int var4 = var3.length;
for(int var5 = 0; var5 < var4; ++var5) {
ServletContextInitializer initializer = var3[var5];
//被调用
initializer.onStartup(servletContext);
}
} catch (Exception var7) {
this.startUpException = var7;
if (logger.isErrorEnabled()) {
logger.error("Error starting Tomcat context. Exception: " + var7.getClass().getName() + ". Message: " + var7.getMessage());
}
}
}
Exception getStartUpException() {
return this.startUpException;
}
}
servletContext实例
public class ServletWebServerApplicationContext extends GenericWebApplicationContext implements ConfigurableWebServerApplicationContext {
private ServletContextInitializer getSelfInitializer() {
return this::selfInitialize;
}
//初始化 onStartup 执行的方法
private void selfInitialize(ServletContext servletContext) throws ServletException {
this.prepareWebApplicationContext(servletContext);
this.registerApplicationScope(servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(this.getBeanFactory(), servletContext);
Iterator var2 = this.getServletContextInitializerBeans().iterator();
while(var2.hasNext()) {
ServletContextInitializer beans = (ServletContextInitializer)var2.next();
beans.onStartup(servletContext);
}
}
//通过本类的实例构造一个webServer(Tomcat)
//并且初始化
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = this.getServletContext();
if (webServer == null && servletContext == null) {
StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
ServletWebServerFactory factory = this.getWebServerFactory();
createWebServer.tag("factory", factory.getClass().toString());
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
createWebServer.end();
this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));
this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));
} else if (servletContext != null) {
try {
this.getSelfInitializer().onStartup(servletContext);
} catch (ServletException var5) {
throw new ApplicationContextException("Cannot initialize servlet context", var5);
}
}
this.initPropertySources();
}
//添加过滤器
private Dynamic addFilter(String filterName, String filterClass, Filter filter) throws IllegalStateException {
if (filterName != null && !filterName.equals("")) {
if (!this.context.getState().equals(LifecycleState.STARTING_PREP)) {
throw new IllegalStateException(sm.getString("applicationContext.addFilter.ise", new Object[]{this.getContextPath()}));
} else {
FilterDef filterDef = this.context.findFilterDef(filterName);
if (filterDef == null) {
filterDef = new FilterDef();
filterDef.setFilterName(filterName);
this.context.addFilterDef(filterDef);
} else if (filterDef.getFilterName() != null && filterDef.getFilterClass() != null) {
return null;
}
if (filter == null) {
filterDef.setFilterClass(filterClass);
} else {
filterDef.setFilterClass(filter.getClass().getName());
filterDef.setFilter(filter);
}
return new ApplicationFilterRegistration(filterDef, this.context);
}
} else {
throw new IllegalArgumentException(sm.getString("applicationContext.invalidFilterName", new Object[]{filterName}));
}
}
}
请求到达时的处理流程
从StandandContext中获取filterMap
从filterMap中找到和request对象能匹配到的filter-name
从StandandContext中通过filter-name找到filter-config实例
https://blog.csdn.net/wq5350/article/details/108719708
final class StandardWrapperValve extends ValveBase {
public final void invoke(Request request, Response response)
throws IOException, ServletException {
//省略其他不做分析
//重点在这 创建filterchain
//每个请求都会创建一个filterchain
//并不是所有的请求共用一个
// Create the filter chain for this request
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
// Call the filter chain for this request
// NOTE: This also calls the servlet's service() method
Container container = this.container;
try {
if ((servlet != null) && (filterChain != null)) {
// Swallow output if needed
if (context.getSwallowOutput()) {
try {
SystemLogHandler.startCapture();
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else {
filterChain.doFilter(request.getRequest(),
response.getResponse());
}
} finally {
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0) {
context.getLogger().info(log);
}
}
} else {
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else {
filterChain.doFilter
(request.getRequest(), response.getResponse());
}
}
}
} catch (ClientAbortException | CloseNowException e) {
//省略异常处理
} finally {
//请求处理完成后 要释放掉filterchain
//使得filter可以被垃圾处理器回收
// Release the filter chain (if any) for this request
if (filterChain != null) {
filterChain.release();
}
//省略后续操作
}
}
}
public final class ApplicationFilterFactory {
//创建filterchain
public static ApplicationFilterChain createFilterChain(ServletRequest request,
Wrapper wrapper, Servlet servlet) {
// If there is no servlet to execute, return null
if (servlet == null)
return null;
//实例化一个filterchain
// Create and initialize a filter chain object
ApplicationFilterChain filterChain = null;
if (request instanceof Request) {
Request req = (Request) request;
if (Globals.IS_SECURITY_ENABLED) {
// Security: Do not recycle
filterChain = new ApplicationFilterChain();
} else {
//复用filterchain
filterChain = (ApplicationFilterChain) req.getFilterChain();
if (filterChain == null) {
filterChain = new ApplicationFilterChain();
req.setFilterChain(filterChain);
}
}
} else {
// Request dispatcher in use
filterChain = new ApplicationFilterChain();
}
//初始化配置
filterChain.setServlet(servlet);
filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());
//从context中获取filterMap
// Acquire the filter mappings for this Context
StandardContext context = (StandardContext) wrapper.getParent();
FilterMap filterMaps[] = context.findFilterMaps();
// If there are no filter mappings, we are done
if ((filterMaps == null) || (filterMaps.length == 0))
return filterChain;
// Acquire the information we will need to match filter mappings
DispatcherType dispatcher =
(DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);
String requestPath = null;
Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
if (attribute != null){
requestPath = attribute.toString();
}
String servletName = wrapper.getName();
//从filterMap中寻找匹配路径的filter添加到链中
// Add the relevant path-mapped filters to this filter chain
for (FilterMap filterMap : filterMaps) {
if (!matchDispatcher(filterMap, dispatcher)) {
continue;
}
if (!matchFiltersURL(filterMap, requestPath))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMap.getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
filterChain.addFilter(filterConfig);
}
//如果匹配到servlet名 也添加进去
// Add filters that match on servlet name second
for (FilterMap filterMap : filterMaps) {
if (!matchDispatcher(filterMap, dispatcher)) {
continue;
}
if (!matchFiltersServlet(filterMap, servletName))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMap.getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
filterChain.addFilter(filterConfig);
}
// Return the completed filter chain
return filterChain;
}
}
责任链模式
类似于递归压栈
总结
流程
- context启动时,调用ServletContainerInitializers添加filter,调用AbstractFilterRegistrationBean类的addRegistration方法向context添加filter
- context中不存在FilterDef则创建对应FilterDef
- AbstractFilterRegistrationBean中configure方法添加匹配filter的uri,默认为/*
- context启动时,调用filterStart方法配置初始化ApplicationFilterConfig
- 调用filter的init方法
- 对每次到达的请求在StandardWrapperVavel的invoke方法中创建过滤器链
- 根据名称获得ApplicationFilterConfig添加到过滤器链,通过ApplicationFilterConfig来获取filter执行
流程2
-
ServletContainerInitializer(TomcatStarter实现类).onStartup() 调用 ServletContextInitializer.onStartup(ServletContext)
-
ServletContextInitializer(AbstractFilterRegistrationBean实现类).onStartup(ServletContext) 调用 ServletContext.addFilter() 方法
-
ServletContext(ApplicationContext实现类).addFilter 方法调用了 StandandContext.addFilterDef()
-
StandandContext.addFilterDef() 方法填充 StandandContext.filterDefs
-
StandandContext.filterStart()
方法根据 StandandContext.filterDefs属性 填充 StandandContext.filterConfigs
-
ApplicationFilterFactory根据StandandContext生成filterchain
-
StandardWrapperValve中调用filterchain.doFilter() 方法
-
filterchain结束后调用servlet.service方法
思路
- 将filterchain放到context中
- 每次请求到达从context中获取
- filterchain可以复用