这个filter是struts中最重要的filter,主要完成以下四个功能:
1、处理action
2、清理ActionContext
3、处理静态资源
4、触发指定请求生命周期内的拦截器链
这个filter是武断性的,也就是说它通过ActonMapper来寻找特定的action,如果找到了,那么其他剩下的filter就不会再被引用,转而去处理action,这意味着其他过滤器需要放置到这个filter前面,否则将不会被引用到。
public void setDevMode(String mode) {
devMode = "true".equals(mode);
}
这样的set方法还是值得我们借鉴的。
public void init(FilterConfig filterConfig) throws ServletException {
try {
this.filterConfig = filterConfig;
initLogging();
dispatcher = createDispatcher(filterConfig);
dispatcher.init();
dispatcher.getContainer().inject(this);
staticResourceLoader.setHostConfig(new FilterHostConfig(filterConfig));
} finally {
ActionContext.setContext(null);
}
}
在初始化方法中,会初始化log,创建调度者,并对静态资源做一些处理。
初始化log
private void initLogging() {
//查看web.xml中filter的初始化参数中有无配置loggerFactory
String factoryName = filterConfig.getInitParameter("loggerFactory");
if (factoryName != null) {
try {
Class cls = ClassLoaderUtils.loadClass(factoryName, this.getClass());
LoggerFactory fac = (LoggerFactory) cls.newInstance();
LoggerFactory.setLoggerFactory(fac);
} catch (InstantiationException e) {
System.err.println("Unable to instantiate logger factory: " + factoryName + ", using default");
e.printStackTrace();
} catch (IllegalAccessException e) {
System.err.println("Unable to access logger factory: " + factoryName + ", using default");
e.printStackTrace();
} catch (ClassNotFoundException e) {
System.err.println("Unable to locate logger factory class: " + factoryName + ", using default");
e.printStackTrace();
}
}
log = LoggerFactory.getLogger(FilterDispatcher.class);
}
接下来,是初始化dispatcher的方法
/**
*加载配置文件,包括xml和一些默认的配置,
*更新一些配置,包括是否重新加载一些配置或资源.
*/
public void init() {
//struts.xml是配置文件的入口
if (configurationManager == null) {
configurationManager = createConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
}
//初始化配置,添加到configurationManager#containerProviders List中
try {
//加载org/apache/struts2/default.properties struts常量
init_DefaultProperties(); // [1]
//web.xml中的config
//若没有则加载struts-default.xml,struts-plugin.xml,struts.xml
init_TraditionalXmlConfigurations(); // [2]
init_LegacyStrutsProperties(); // [3]
//用户自定义的ConfigurationProvider web.xml 中 configProviders
init_CustomConfigurationProviders(); // [5]
//web.xml中配置的init-param参数
init_FilterInitParameters() ; // [6]
//根据我们在struts.xml中配置的常量,初始化一些插件类
//比如我们设置的devmode
init_AliasStandardObjects() ; // [7]
Container container = init_PreloadConfiguration();
container.inject(this);
init_CheckConfigurationReloading(container);
init_CheckWebLogicWorkaround(container);
if (!dispatcherListeners.isEmpty()) {
for (DispatcherListener l : dispatcherListeners) {
l.dispatcherInitialized(this);
}
}
} catch (Exception ex) {
if (LOG.isErrorEnabled())
LOG.error("Dispatcher initialization failed", ex);
throw new StrutsException(ex);
}
}
Container container = init_PreloadConfiguration(),这个方法负责解析xml
//方法调用了configurationManager的getConfiguration方法
private Container init_PreloadConfiguration() {
Configuration config = configurationManager.getConfiguration();
Container container = config.getContainer();
boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));
LocalizedTextUtil.setReloadBundles(reloadi18n);
return container;
}
//defaultFrameworkBeanName==“struts”
//方法又调用了configuration.reloadContainer(getContainerProviders());
public synchronized Configuration getConfiguration() {
if (configuration == null) {
setConfiguration(createConfiguration(defaultFrameworkBeanName));
try {
configuration.reloadContainer(getContainerProviders());
} catch (ConfigurationException e) {
setConfiguration(null);
throw new ConfigurationException("Unable to load configuration.", e);
}
} else {
conditionalReload();
}
return configuration;
}
然后会load在struts.xml中配置的package信息。
在源码中,我们发现这样一段代码:includeFileName.indexOf('*') != -1
说明在struts.xml中的include中,可以配置*进行模糊匹配
默认的,会在org.apache.struts2.static template中寻找,如果你想添加自己的静态资源包,可以在filter的init中传name为packages的值,用逗号隔开(还没搞明白)
在prepareDispatcherAndWrapRequest方法中,会对请求进行封装,包括设置字符编码,并对multipart/form-data的请求进行封装
在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();
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 {
dispatcher.cleanUpRequest(request);
try {
ActionContextCleanUp.cleanUp(req);
} finally {
UtilTimerStack.pop(timerKey);
}
devModeOverride.remove();
}
}
在filter中,先看请求的是不是action,如果不是,就返回相应的资源,如果是的话,继续执行。注意,继续执行不会寻找下一个filter,而是转向action的代理,开始处理action。
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,
ActionMapping mapping) throws ServletException {
Map<String, Object> extraContext = createContextMap(request, response, mapping, context);
// If there was a previous value stack, then create a new copy and pass it in to be used by the new Action
ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
boolean nullStack = stack == null;
if (nullStack) {
ActionContext ctx = ActionContext.getContext();
if (ctx != null) {
stack = ctx.getValueStack();
}
}
if (stack != null) {
extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));
}
String timerKey = "Handling request from Dispatcher";
try {
UtilTimerStack.push(timerKey);
String namespace = mapping.getNamespace();
String name = mapping.getName();
String method = mapping.getMethod();
Configuration config = configurationManager.getConfiguration();
ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
namespace, name, method, extraContext, true, false);
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
// if the ActionMapping says to go straight to a result, do it!
if (mapping.getResult() != null) {
Result result = mapping.getResult();
result.execute(proxy.getInvocation());
} else {
proxy.execute();
}
// If there was a previous value stack then set it back onto the request
if (!nullStack) {
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
}
} catch (ConfigurationException e) {
// WW-2874 Only log error if in devMode
if(devMode) {
String reqStr = request.getRequestURI();
if (request.getQueryString() != null) {
reqStr = reqStr + "?" + request.getQueryString();
}
LOG.error("Could not find action or result\n" + reqStr, e);
}
else {
LOG.warn("Could not find action or result", e);
}
sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);
} catch (Exception e) {
sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
} finally {
UtilTimerStack.pop(timerKey);
}
}
我们注意到在serviceAction方法中,会创建ActionProxy,如果有拦截器那么就继续执行拦截器,否则返回结果。
分享到:
相关推荐
这个"深入浅出Struts2源码-例子程序(完整版)"的资源包含了一个全面的学习材料,旨在帮助开发者理解Struts2的核心工作原理和实际应用。 Struts2的源代码分析是提升开发技能的关键,它让你能深入了解框架如何处理...
通过对Struts2源码的学习,我们可以更深入地理解MVC模式在实际应用中的实现,了解如何设计可扩展和可维护的框架。同时,也能帮助我们更好地调试和优化应用程序,提升开发效率。在研究struts-2.2.1.1 src这个源码包时...
通过分析提供的源码,可以更好地了解Struts2的工作流程,学习如何组织Action、Interceptor、配置文件等,从而提升开发能力。在实践中不断探索,可以逐步熟练运用Struts2进行高效、稳定的Web应用开发。
通过对Struts2的源码学习,我们可以更深入地理解其内部工作流程,如Action的调度、拦截器的执行顺序、OGNL的解析过程等,这对于优化性能、调试问题或者开发自定义组件都非常有帮助。源码阅读不仅可以提高我们的编程...
6. **源码学习价值**: 分析Struts2的源码可以帮助我们理解MVC框架的设计思想,学习如何处理HTTP请求,以及如何实现拦截器机制。这对于提升自己的Java Web开发技能,尤其是框架设计和优化能力非常有帮助。 7. **...
Struts2.3.8是Apache ...以上是关于Struts2.3.8源码的一些主要知识点,理解并掌握这些内容有助于深入学习和开发基于Struts2的应用程序。通过阅读源码,开发者可以更直观地了解其内部工作原理,进一步提升自己的技能。
- **web.xml**:Web容器的配置文件,配置了Struts2的前端控制器FilterDispatcher。 #### 3. Struts2的拦截器 - **内置拦截器**:Struts2提供了一系列内置拦截器,如`params`(参数填充)、`token`(防止重复提交)...
6. **生命周期与请求处理**:当一个HTTP请求到达时,Struts2如何从DispatcherServlet开始,通过FilterDispatcher或StrutsPrepareAndExecuteFilter来处理请求,然后如何找到对应的Action并执行,这些都是源码分析的...
Struts2是一个基于MVC(Model-View-Controller)设计模式的...同时,源码学习也有助于了解软件设计模式和Java编程的最佳实践。对于希望成为高级Java开发人员或者框架开发者的人来说,理解Struts2源码是必不可少的一环。
Struts2是一个非常著名的Java Web框架,用于构建和维护可扩展且易于管理的企业级应用程序。它的源码提供了深入了解其工作原理的机会...同时,源码学习也能帮助开发者遇到问题时更快速地定位并解决问题,提高开发效率。
这个压缩包文件包含了关于Struts2.0的经典书籍、源码以及标签的学习资源,对于想要深入理解和使用Struts2.0的人来说,是一份非常宝贵的资料。 首先,让我们从"经典书籍"入手。Struts2.0的书籍通常会涵盖以下知识点...
Struts2是一个基于MVC(Model-View-...阅读Struts2源码有助于提升对Java Web开发的理解,学习优秀的设计模式和编程实践,对于成为一名专业的Java开发者非常有益。同时,它也有助于你在遇到问题时能更深入地分析和解决。
Struts2.0.9是该框架的一个早期版本,尽管现在已经有了更新的版本,但对于学习和理解Struts2的基本概念和工作原理,这个版本仍然是有价值的。 **Struts2的核心组件:** 1. **Action类**:它是业务逻辑处理的主要...
Struts2 HelloWorld ... 创建一个简单的Struts2应用,我们需要在项目的web.xml文件中配置Struts2的核心过滤器`org.apache.struts2.dispatcher.FilterDispatcher`或更现代的`org.apache.struts2.dispatcher.ng.filter....
对于源码学习,了解Struts2的内部工作原理非常重要。主要关注以下几个部分: 1. ActionInvocation:它是执行Action的核心接口,包含了调用Action方法和遍历Interceptor链的过程。 2. Interceptor栈:每个Action执行...
在深入探讨Struts2.0核心源码之前,我们需要对MVC模式有一个基本的理解。MVC模式将应用分为三个部分:模型(Model)负责业务逻辑,视图(View)处理用户界面,控制器(Controller)协调模型和视图的交互。 Struts...
Struts2是一个基于MVC(Model-View-Controller)设计模式的Java Web应用程序框架,它在Web开发领域具有广泛的应用。Struts2的核心是Action,它负责处理HTTP请求,并通过配置文件或注解来指定业务逻辑。源码包...