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,如果有拦截器那么就继续执行拦截器,否则返回结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值