写在前面
源码 。
本文来实现下过滤器和监听器相关内容。
1:过滤器
过滤器的功能是在servlet执行前和执行后执行一些动作,即属于wrapper容器内的功能。servlet规范中也定义了相关的接口,比如过滤器接口javax.servlet.Filter:
java
package javax.servlet;
import java.io.IOException;
public interface Filter {
default public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException;
default public void destroy() {}
}
以及对应的配置接口:
java
package javax.servlet;
import java.util.Enumeration;
public interface FilterConfig {
public String getFilterName();
public ServletContext getServletContext();
public String getInitParameter(String name);
public Enumeration<String> getInitParameterNames();
}
首先定义配置类,同时维护将来用户自定义的Filter:
java
package monitomcat.server.core;
// ...
/**
* 包装filter+filter配置
*/
final class ApplicationFilterConfig implements FilterConfig {
public ApplicationFilterConfig(Context context, FilterDef filterDef)
throws ClassCastException, ClassNotFoundException,
IllegalAccessException, InstantiationException,
ServletException {
super();
this.context = context;
setFilterDef(filterDef);
}
private Context context = null;
private Filter filter = null;
private FilterDef filterDef = null;
// ...
}
FilterDef是用户配置的过滤器定义信息,如下:
java
package monitomcat.server.core;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 因为filter是需要用户在配置文件中定义的,所以需要定义类来对应用户的配置信息,即filter的定义,filter definition
* <!-- 1.注册Filter -->
* <filter>
* <!-- filter名字,自定义 -->
* <filter-name>EncodingFilter</filter-name>
* <!-- 过滤器全类名 -->
* <filter-class>com.example.filter.EncodingFilter</filter-class>
*
* <!-- 过滤器初始化参数,filterConfig可以读取 -->
* <init-param>
* <param-name>charset</param-name>
* <param-value>UTF-8</param-value>
* </init-param>
*
* <!-- 容器启动就实例化filter,数字代表加载顺序,数字越小越先加载 -->
* <load-on-startup>1</load-on-startup>
* </filter>
*/
public final class FilterDef {
private String description = null;
private String filterClass = null;
private String filterName = null;
private Map<String, String> parameters = new ConcurrentHashMap<>();
}
filter多个时支持链式管理:
java
package monitomcat.server.core;
// ...
/**
* 过滤器filter 链,实现责任链,即链式调用
*/
final class ApplicationFilterChain implements FilterChain {
public ApplicationFilterChain() {
super();
}
private ArrayList<ApplicationFilterConfig> filters = new ArrayList<>();
private Iterator<ApplicationFilterConfig> iterator = null;
private Servlet servlet = null;
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
System.out.println("FilterChain doFilter()");
internalDoFilter(request,response);
}
private void internalDoFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
// Construct an iterator the first time this method is called
if (this.iterator == null)
this.iterator = filters.iterator();
// Call the next filter if there is one
if (this.iterator.hasNext()) {
ApplicationFilterConfig filterConfig =
(ApplicationFilterConfig) iterator.next();
Filter filter = null;
try {
filter = filterConfig.getFilter();
System.out.println("Filter doFilter()");
filter.doFilter(request, response, this);
// ...
return;
}
// We fell off the end of the chain -- call the servlet instance
try {
HttpServletRequest requestFacade = new HttpRequestFacade((HttpRequestImpl) request);
HttpServletResponse responseFacade = new HttpResponseFacade((HttpResponseImpl) response);
servlet.service(requestFacade, responseFacade);
// ...
}
void addFilter(ApplicationFilterConfig filterConfig) {
this.filters.add(filterConfig);
}
// ...
}
internalDoFilter方法内部会递归调用doFilter方法从而完成链式调用,形成职责链。当然最终会执行servlet.service(requestFacade, responseFacade);。用户除了需要定义自定义过滤器本身外还需要定义过滤器对哪些请求生效,即过滤哪些请求,针对该信息定义如下对象:
java
package monitomcat.server.core;
import monitomcat.server.util.URLDecoder;
/**
* servlet -> url 映射信息,每个filter都有该配置,用来确定filter对哪些servlet请求生效
* <!-- 2.映射:指定哪些url走这个过滤器 -->
* <filter-mapping>
* <!-- 和上面filter-name保持一致 -->
* <filter-name>EncodingFilter</filter-name>
* <!-- 拦截所有请求 -->
* <url-pattern>/*</url-pattern>
*
* <!-- 可指定拦截的Servlet名称 -->
* <!-- <servlet-name>MyServlet</servlet-name> -->
*
* <!-- 指定拦截请求方式:REQUEST(普通请求),FORWARD,INCLUDE,ERROR -->
* <dispatcher>REQUEST</dispatcher>
* <dispatcher>FORWARD</dispatcher>
* </filter-mapping>
*/
public final class FilterMap {
private String filterName = null;
private String servletName = null;
private String urlPattern = null;
}
在wrapper容器的父容器context中,即StandardContext类中维护filter的定义以及映射信息:
java
package monitomcat.server.core;
public class StandardContext extends ContainerBase implements Context {
// ...
public void addFilterDef(FilterDef filterDef) {
filterDefs.put(filterDef.getFilterName(), filterDef);
}
public void addFilterMap(FilterMap filterMap) {
// 验证所建议的过滤器映射
String filterName = filterMap.getFilterName();
String servletName = filterMap.getServletName();
String urlPattern = filterMap.getURLPattern();
// ...
// 因为过滤器模式是2.3中的新功能,所以不需要调整
// 对于2.2版本的向后兼容性
if ((urlPattern != null) && !validateURLPattern(urlPattern))
throw new IllegalArgumentException("standardContext.filterMap.pattern" + urlPattern);
// 将这个过滤器映射添加到我们已注册的集合中
synchronized (filterMaps) {
FilterMap results[] = new FilterMap[filterMaps.length + 1];
System.arraycopy(filterMaps, 0, results, 0, filterMaps.length);
results[filterMaps.length] = filterMap;
filterMaps = results;
}
}
// ...
//对配置好的所有filter名字,创建实例,存储在filterConfigs中,可以生效了
public boolean filterStart() {
System.out.println("Filter init..........");
// 为每个定义的过滤器实例化并记录一个FilterConfig
boolean ok = true;
synchronized (filterConfigs) {
filterConfigs.clear();
Iterator<String> names = filterDefs.keySet().iterator();
while (names.hasNext()) {
String name = names.next();
ApplicationFilterConfig filterConfig = null;
try {
filterConfig = new ApplicationFilterConfig
(this, (FilterDef) filterDefs.get(name));
filterConfigs.put(name, filterConfig);
} catch (Throwable t) {
ok = false;
}
}
}
return (ok);
}
}
filterStart用来初始化filter信息,这里叫xxxStart只是更加形象而已,不用纠结。接着还要来修改wrapper,就不直接调用servlet了而是调用filter chain:
java
package monitomcat.server.core;
// ...
public class StandardWrapperValve extends ValveBase {
@Override
public void invoke(Request request, Response response, ValveContext context) throws IOException, ServletException {
// TODO Auto-generated method stub
System.out.println("StandardWrapperValve invoke()");
Servlet instance = ((StandardWrapper) getContainer()).getServlet();
ApplicationFilterChain filterChain = createFilterChain(request, instance);
if ((instance != null) && (filterChain != null)) {
filterChain.doFilter((ServletRequest) request, (ServletResponse) response);
}
filterChain.release();
}
private ApplicationFilterChain createFilterChain(Request request, Servlet servlet) {
System.out.println("createFilterChain()");
if (servlet == null)
return (null);
ApplicationFilterChain filterChain = new ApplicationFilterChain();
// ...
return (filterChain);
}
}
这样过滤器链就运转起来了,最终会调用到目标servlet。最后在启动类中注册用户过滤器信息就行了:
java
package monitomcat.server.startup;
// ...
/**
* 总的服务器对象,负责管理类工作的对象(类似于公司的管理层,负责管理,但不负责具体干活,但管理本身不也是一种职责嘛!所以也可以用单一职责来进行说明)
*/
public class Bootstrap {
// ...
public static void main(String[] args) {
// ...
FilterDef filterDef = new FilterDef();
filterDef.setFilterName("TestFilter");
// filterDef.setFilterClass("test.TestFilter");
filterDef.setFilterClass("monitomcat.server.test.TestFilter");
servletContainer.addFilterDef(filterDef);
FilterMap filterMap = new FilterMap();
filterMap.setFilterName("TestFilter");
filterMap.setURLPattern("/*");
servletContainer.addFilterMap(filterMap);
servletContainer.filterStart();
// ...
}
}
过滤器定义如下:
java
package monitomcat.server.test;
// ...
public class TestFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("test filter invoked ......");
chain.doFilter(request, response);
}
}
启动测试:

2:监听器
针对各种容器,servlet,session的生命周期提供监听功能。
定义容器的事件对象和监听器对象:
java
package monitomcat.server;
import java.util.EventObject;
/**
* 容器事件,加入jdk的时间体系
*/
public final class ContainerEvent extends EventObject {
}
java
package monitomcat.server;
/**
* 容器监听器,监听容器事件
*/
public interface ContainerListener {
public void containerEvent(ContainerEvent event);
}
定义servlet的事件对象和监听器对象:
java
package monitomcat.server;
// ...
/**
* servlet事件
*/
public final class InstanceEvent extends EventObject {
}
定义session的事件对象和监听器对象:
java
package monitomcat.server;
import java.util.EventObject;
/**
* session事件
*/
public final class SessionEvent extends EventObject {
}
java
package monitomcat.server;
public interface SessionListener {
public void sessionEvent(SessionEvent event);
}
接着在StandardContext中增加监听器相关代码:
java
package monitomcat.server.core;
// ...
public class StandardContext extends ContainerBase implements Context {
// ...
private ArrayList<ContainerListenerDef> listenerDefs = new ArrayList<>();
private ArrayList<ContainerListener> listeners = new ArrayList<>();
public void start() {
// 触发一个容器启动事件
fireContainerEvent("Container Started", this);
}
public void addContainerListener(ContainerListener listener) {
// 添加一个新的容器监听器到监听器列表,并确保线程安全
synchronized (listeners) {
listeners.add(listener);
}
}
public void removeContainerListener(ContainerListener listener) {
// 移除指定的容器监听器,并确保线程安全
synchronized (listeners) {
listeners.remove(listener);
}
}
public void fireContainerEvent(String type, Object data) {
// 检查是否已经有监听器,如果没有则直接返回
if (listeners.size() < 1)
return;
ContainerEvent event = new ContainerEvent(this, type, data);
ContainerListener list[] = new ContainerListener[0];
synchronized (listeners) {
list = (ContainerListener[]) listeners.toArray(list);
}
// 遍历所有监听器并触发事件
for (int i = 0; i < list.length; i++)
((ContainerListener) list[i]).containerEvent(event);
}
public void addListenerDef(ContainerListenerDef listenererDef) {
synchronized (listenerDefs) {
listenerDefs.add(listenererDef);
}
}
public boolean listenerStart() {
System.out.println("Listener init..........");
boolean ok = true;
synchronized (listeners) {
listeners.clear();
Iterator<ContainerListenerDef> defs = listenerDefs.iterator();
while (defs.hasNext()) {
ContainerListenerDef def = defs.next();
ContainerListener listener = null;
try {
// ...
addContainerListener(listener);
} catch (Throwable t) {
t.printStackTrace();
ok = false;
}
}
}
return (ok);
}
}
这里listenerStart方法同过滤器的filterStart方法。定义监听器定义对象:
java
package monitomcat.server.core;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* listener 定义对象
*/
public final class ContainerListenerDef {
private String description = null;
private String listenerName = null;
private Map<String, String> parameters = new ConcurrentHashMap<>();
}
session中添加监听器相关代码:
java
package com.minit.session;
public class StandardSession implements HttpSession, Session {
private transient ArrayList<SessionListener> listeners = new ArrayList<>();
public void addSessionListener(SessionListener listener) {
synchronized (listeners) {
listeners.add(listener);
}
}
public void removeSessionListener(SessionListener listener) {
synchronized (listeners) {
listeners.remove(listener);
}
}
public void fireSessionEvent(String type, Object data) {
if (listeners.size() < 1)
return;
SessionEvent event = new SessionEvent(this, type, data);
SessionListener list[] = new SessionListener[0];
synchronized (listeners) {
list = (SessionListener[]) listeners.toArray(list);
}
for (int i = 0; i < list.length; i++)
((SessionListener) list[i]).sessionEvent(event);
}
public void setId(String sessionId) {
this.sessionid = sessionId;
fireSessionEvent(Session.SESSION_CREATED_EVENT, null);
}
}
最后在启动类Bootstrap中增加监听器注册相关代码:
java
package monitomcat.server.startup;
// ...
/**
* 总的服务器对象,负责管理类工作的对象(类似于公司的管理层,负责管理,但不负责具体干活,但管理本身不也是一种职责嘛!所以也可以用单一职责来进行说明)
*/
public class Bootstrap {
// public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";
public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "target" + File.separator + "classes" + File.separator + "webroot";
public static final String WEB_ROOT_SERVLET = System.getProperty("user.dir") + File.separator + "target" + File.separator + "classes" + File.separator + "monitomcat" + File.separator + "server";
public static void main(String[] args) {
// ...
ContainerListenerDef listenerDef = new ContainerListenerDef();
listenerDef.setListenerName("TestListener");
listenerDef.setListenerClass("monitomcat.server.test.TestListener");
servletContainer.addListenerDef(listenerDef);
servletContainer.listenerStart();
servletContainer.start();
connector.start();
}
}
监听器:
java
public class TestListener implements ContainerListener {
@Override
public void containerEvent(ContainerEvent event) {
System.out.println("test listener invoked...");
}
}
该监听器是容器启动的监听器,所以在启动时会执行,如下:
