`
wang7839186
  • 浏览: 42064 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

struts2源码学习一 FilterDispatcher

阅读更多

 这个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的源代码分析是提升开发技能的关键,它让你能深入了解框架如何处理...

    Struts2源码

    通过对Struts2源码的学习,我们可以更深入地理解MVC模式在实际应用中的实现,了解如何设计可扩展和可维护的框架。同时,也能帮助我们更好地调试和优化应用程序,提升开发效率。在研究struts-2.2.1.1 src这个源码包时...

    struts2框架源码

    通过分析提供的源码,可以更好地了解Struts2的工作流程,学习如何组织Action、Interceptor、配置文件等,从而提升开发能力。在实践中不断探索,可以逐步熟练运用Struts2进行高效、稳定的Web应用开发。

    struts2源码下载啦

    通过对Struts2的源码学习,我们可以更深入地理解其内部工作流程,如Action的调度、拦截器的执行顺序、OGNL的解析过程等,这对于优化性能、调试问题或者开发自定义组件都非常有帮助。源码阅读不仅可以提高我们的编程...

    struts2权威指南源码

    6. **源码学习价值**: 分析Struts2的源码可以帮助我们理解MVC框架的设计思想,学习如何处理HTTP请求,以及如何实现拦截器机制。这对于提升自己的Java Web开发技能,尤其是框架设计和优化能力非常有帮助。 7. **...

    struts2.3.8源码

    Struts2.3.8是Apache ...以上是关于Struts2.3.8源码的一些主要知识点,理解并掌握这些内容有助于深入学习和开发基于Struts2的应用程序。通过阅读源码,开发者可以更直观地了解其内部工作原理,进一步提升自己的技能。

    15年9月传智播客视频struts2

    - **web.xml**:Web容器的配置文件,配置了Struts2的前端控制器FilterDispatcher。 #### 3. Struts2的拦截器 - **内置拦截器**:Struts2提供了一系列内置拦截器,如`params`(参数填充)、`token`(防止重复提交)...

    浪曦struts2源码第5课

    6. **生命周期与请求处理**:当一个HTTP请求到达时,Struts2如何从DispatcherServlet开始,通过FilterDispatcher或StrutsPrepareAndExecuteFilter来处理请求,然后如何找到对应的Action并执行,这些都是源码分析的...

    struts2源码

    Struts2是一个基于MVC(Model-View-Controller)设计模式的...同时,源码学习也有助于了解软件设计模式和Java编程的最佳实践。对于希望成为高级Java开发人员或者框架开发者的人来说,理解Struts2源码是必不可少的一环。

    struts2的源码

    Struts2是一个非常著名的Java Web框架,用于构建和维护可扩展且易于管理的企业级应用程序。它的源码提供了深入了解其工作原理的机会...同时,源码学习也能帮助开发者遇到问题时更快速地定位并解决问题,提高开发效率。

    struts2.0 经典书籍 源码 标签学习合集

    这个压缩包文件包含了关于Struts2.0的经典书籍、源码以及标签的学习资源,对于想要深入理解和使用Struts2.0的人来说,是一份非常宝贵的资料。 首先,让我们从"经典书籍"入手。Struts2.0的书籍通常会涵盖以下知识点...

    struts-2.3.14.1源码

    Struts2是一个基于MVC(Model-View-...阅读Struts2源码有助于提升对Java Web开发的理解,学习优秀的设计模式和编程实践,对于成为一名专业的Java开发者非常有益。同时,它也有助于你在遇到问题时能更深入地分析和解决。

    struts2 struts2.0.9 最全包下载

    Struts2.0.9是该框架的一个早期版本,尽管现在已经有了更新的版本,但对于学习和理解Struts2的基本概念和工作原理,这个版本仍然是有价值的。 **Struts2的核心组件:** 1. **Action类**:它是业务逻辑处理的主要...

    Struts2 HelloWorld

    Struts2 HelloWorld ... 创建一个简单的Struts2应用,我们需要在项目的web.xml文件中配置Struts2的核心过滤器`org.apache.struts2.dispatcher.FilterDispatcher`或更现代的`org.apache.struts2.dispatcher.ng.filter....

    struts2的学习之

    对于源码学习,了解Struts2的内部工作原理非常重要。主要关注以下几个部分: 1. ActionInvocation:它是执行Action的核心接口,包含了调用Action方法和遍历Interceptor链的过程。 2. Interceptor栈:每个Action执行...

    struts2.0核心源码包

    在深入探讨Struts2.0核心源码之前,我们需要对MVC模式有一个基本的理解。MVC模式将应用分为三个部分:模型(Model)负责业务逻辑,视图(View)处理用户界面,控制器(Controller)协调模型和视图的交互。 Struts...

    struts-2.3.32-src源码包

    Struts2是一个基于MVC(Model-View-Controller)设计模式的Java Web应用程序框架,它在Web开发领域具有广泛的应用。Struts2的核心是Action,它负责处理HTTP请求,并通过配置文件或注解来指定业务逻辑。源码包...

Global site tag (gtag.js) - Google Analytics