阅读了struts2的部分源码, 才知道, 原来struts2是不用servlet的, 只用了filter就可以实现所有的功能, 包括action和interceptor.
首先, 一个请求过来, filter会拦截到, 通过解析请求URL, 得到请求的target(哪个类的哪个方法), 放在actionMapping里边, 这个通过actionMapping可以得到要执行的类的方法, 然后作为对象放到DefaultActionInvocation这个类中, 这个类是实现了ActionInvocation的类, 没错, 就是在struts2的拦截器方法intercept(ActionInvocation invocation)的参数类型.把代码罗列出来比较容易看.
先看看FilterDispatcher这个filter的doFilter方法
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
ServletContext servletContext = getServletContext();
String timerKey = "FilterDispatcher_doFilter: ";
try {
// FIXME: this should be refactored better to not duplicate work with the action invocation
ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
//这里就是为什么我们可以在action中直接使用ActionContext.getContext().getRequest()
//来得到当前的request等对象了. 用的是ThreadLocal的存储.
ActionContext ctx = new ActionContext(stack.getContext());
ActionContext.setContext(ctx);
UtilTimerStack.push(timerKey);
request = prepareDispatcherAndWrapRequest(request, response);
ActionMapping mapping;
try {
mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());
} catch (Exception ex) {
log.error("error getting ActionMapping", ex);
dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
return;
}
if (mapping == null) {
// there is no action in this request, should we look for a static resource?
String resourcePath = RequestUtils.getServletPath(request);
if ("".equals(resourcePath) && null != request.getPathInfo()) {
resourcePath = request.getPathInfo();
}
if (staticResourceLoader.canHandle(resourcePath)) {
staticResourceLoader.findStaticResource(resourcePath, request, response);
} else {
// this is a normal request, let it pass through
chain.doFilter(request, response);
}
// The framework did its job here
return;
}
dispatcher.serviceAction(request, response, servletContext, mapping);
} finally {
try {
ActionContextCleanUp.cleanUp(req);
} finally {
UtilTimerStack.pop(timerKey);
}
}
}