Webx MVC

来源:互联网 发布:统一接口管理源码 编辑:程序博客网 时间:2024/04/29 06:37

首先在Webx中,使用WebxContextLoaderListener替代Spring的ContextLoaderListener:

    <listener>        <listener-class>com.alibaba.citrus.webx.context.WebxContextLoaderListener</listener-class>    </listener>    <filter>        <filter-name>webx</filter-name>        <filter-class>com.alibaba.citrus.webx.servlet.WebxFrameworkFilter</filter-class>    </filter>

其中因为在Servlet定义中,listener的初始化先于filter,所以先从WebxContextLoaderListener看起:
首先ContextLoaderListener的功能是初始化IoC容器,那么WebxContextLoaderListener也应该具有初始化IoC容器的功能:

/** * 用来启动root context的listener。 * <p> * 和Spring {@link ContextLoaderListener}类似,listener将读取 * <code>/WEB-INF/web.xml</code>中context param <code>contextClass</code> * 所指定的类名,作为root <code>ApplicationContext</code>的实现类。假如未明确指定,则使用默认值 * {@link WebxApplicationContext}。 * </p> * <p> * 默认值可以通过覆盖<code>getDefaultContextClass()</code>来改变。 * </p> * * @author Michael Zhou */public class WebxContextLoaderListener extends ContextLoaderListener {    @Override    protected final ContextLoader createContextLoader() {        return new WebxComponentsLoader() {            @Override            protected Class<? extends WebxComponentsContext> getDefaultContextClass() {                Class<? extends WebxComponentsContext> defaultContextClass = WebxContextLoaderListener.this                        .getDefaultContextClass();                if (defaultContextClass == null) {                    defaultContextClass = super.getDefaultContextClass();                }                return defaultContextClass;            }        };    }    protected Class<? extends WebxComponentsContext> getDefaultContextClass() {        return null;    }}

从源码可以看出:WebxContextLoaderListener 继承于ContextLoaderListener ,所以也具有ContextLoaderListener的功能

// 继承自ServletContextListener public class ContextLoaderListener implements ServletContextListener {    private ContextLoader contextLoader;    // Spring初始化IoC容器的入口:    public void contextInitialized(ServletContextEvent event) {        // WebxContextLoaderListener 重写了createContextLoader方法,其返回类型为WebxComponentsLoader,说明WebxComponentsLoader为ContextLoader的派生类。        this.contextLoader = createContextLoader();        // 执行WebxComponentsLoader的初始化ApplicationContext操作        this.contextLoader.initWebApplicationContext(event.getServletContext());    }    ...}

接下来看看contextLoader的initWebApplicationContext方法执行了什么步骤

    /**     * Initialize Spring's web application context for the given servlet context     * 在指定Servlet上下文中初始化Spring的应用上下文     */    public WebApplicationContext initWebApplicationContext(ServletContext servletContext)            throws IllegalStateException, BeansException {        ...        try {            ApplicationContext parent = loadParentContext(servletContext);            this.context = createWebApplicationContext(servletContext, parent);            //指定Spring上下文名称            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);            currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context);            ...            return this.context;        }        catch (...) {            ...        }    }

现在看一下WebxComponentsContext 的实现代码:

/** * 用来初始化<code>WebxComponents</code>。 * * @author Michael Zhou */public class WebxComponentsContext extends WebxApplicationContext {    private WebxComponentsLoader componentsLoader;    public WebxComponentsLoader getLoader() {        return assertNotNull(componentsLoader, ILLEGAL_STATE, "no WebxComponentsLoader set");    }    public void setLoader(WebxComponentsLoader loader) {        this.componentsLoader = loader;    }    /** 取得所有的components。 */    public WebxComponents getWebxComponents() {        return getLoader().getWebxComponents();    }    // Webx重写Spring方法    @Override    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {        super.postProcessBeanFactory(beanFactory);        getLoader().postProcessBeanFactory(beanFactory);    }    // Webx重写Spring方法    @Override    protected void finishRefresh() {        super.finishRefresh();        getLoader().finishRefresh();    }    /** 在创建子容器时,给parent一个设置子context的机会。 */    protected void setupComponentContext(WebxComponentContext componentContext) {    }}

在刚才的createContextLoader方法中,生成WebxComponentsContext 实例,其继承了WebxApplicationContext,而WebxApplicationContext->ResourceLoadingXmlWebApplicationContext->XmlWebApplicationContext->org.springframework.web.context.support.XmlWebApplicationContext,对于这么一条继承关系,
在Spring的WebApplicationContext 中,比较重要的refresh函数,是整个IoC容器资源加载以及注册的关键,先回顾一下refresh函数:

public void refresh() throws BeansException, IllegalStateException {        //refresh过程是同步的,线程安全        synchronized (this.startupShutdownMonitor) {            //容器启动的预先准备,设置startup date等            prepareRefresh();            //创建BeanFactory,如果已存在就先销毁。BeanFactory装载BeanDefinition            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();            //配置BeanFactory的标准上下文特性            prepareBeanFactory(beanFactory);            try {                //在bean开始装载后,提供一个修改BeanFactory的接口                postProcessBeanFactory(beanFactory);                //调用postBeanBeanFactory                invokeBeanFactoryPostProcessors(beanFactory);                //注册BeanPostProcessor,可以再bean初始化前后定制一些功能                registerBeanPostProcessors(beanFactory);                //初始化消息源                initMessageSource();                //初始化事件监听器集合                initApplicationEventMulticaster();                //用于扩展实现一些特殊的bean的初始化,默认什么都不做                onRefresh();                //注册监听器                registerListeners();                //初始化其余非延迟加载的bean                finishBeanFactoryInitialization(beanFactory);                //最后一步:调用onRefresh方法,并发布ContextRefreshedEvent事件                finishRefresh();            }            catch (BeansException ex) {            ...            }        }    }

回到Webx重写Spring的方法,都先执行了Spring的WebApplicationContext方法,然后执行了Webx定义的getLoader得到的WebxComponentsLoader的postProcessBeanFactory方法

    @Override    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {        super.postProcessBeanFactory(beanFactory);        getLoader().postProcessBeanFactory(beanFactory);    }    @Override    protected void finishRefresh() {        super.finishRefresh();        getLoader().finishRefresh();    }

进入WebxComponentsLoader ,其实它继承自ContextLoader :

/** * 用来装载webx components的装载器。 * * @author Michael Zhou */public class WebxComponentsLoader extends ContextLoader {    ...    private ServletContext        servletContext;    private WebApplicationContext componentsContext;    private WebxComponentsImpl    components;    ...    /**     * 在创建beanFactory之初被调用。     *     * @param webxComponentsContext     */    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {        // 由于初始化components依赖于webxConfiguration,而webxConfiguration可能需要由PropertyPlaceholderConfigurer来处理,        // 此外,其它有一些BeanFactoryPostProcessors会用到components,        // 因此components必须在PropertyPlaceholderConfigurer之后初始化,并在其它BeanFactoryPostProcessors之前初始化。        //        // 下面创建的WebxComponentsCreator辅助类就是用来确保这个初始化顺序:        // 1. PriorityOrdered - PropertyPlaceholderConfigurer        // 2. Ordered - WebxComponentsCreator        // 3. 普通 - 其它BeanFactoryPostProcessors        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(WebxComponentsCreator.class);        builder.addConstructorArgValue(this);        BeanDefinition componentsCreator = builder.getBeanDefinition();        componentsCreator.setAutowireCandidate(false);        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;        String name = SpringExtUtil.generateBeanName(WebxComponentsCreator.class.getName(), registry);        registry.registerBeanDefinition(name, componentsCreator);    }    // WebxComponentsCreator 辅助类    public static class WebxComponentsCreator implements BeanFactoryPostProcessor, Ordered {        private final WebxComponentsLoader loader;        public WebxComponentsCreator(WebxComponentsLoader loader) {            this.loader = assertNotNull(loader, "WebxComponentsLoader");        }        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {            if (loader.components == null) {                WebxComponentsImpl components = loader.createComponents(loader.getParentConfiguration(), beanFactory);                AbstractApplicationContext wcc = (AbstractApplicationContext) components.getParentApplicationContext();                wcc.addApplicationListener(new SourceFilteringListener(wcc, components));                loader.components = components;            }        }        public int getOrder() {            return Ordered.LOWEST_PRECEDENCE;        }    }    /** 初始化所有components。 */    public void finishRefresh() {        components.getWebxRootController().onFinishedProcessContext();        // 遍历子模块,并且执行refresh,相当于每个子模块都有一个ApplicationContext        for (WebxComponent component : components) {            ...            WebxComponentContext wcc = (WebxComponentContext) component.getApplicationContext();            WebxController controller = component.getWebxController();            // refresh就是刚才提到的WebApplicationContext的那个重要的函数            wcc.refresh();            controller.onFinishedProcessContext();        }        ...    }    /** 初始化components。 */    private WebxComponentsImpl createComponents(WebxConfiguration parentConfiguration,                                                ConfigurableListableBeanFactory beanFactory) {        ComponentsConfig componentsConfig = getComponentsConfig(parentConfiguration);        // 假如isAutoDiscoverComponents==true,试图自动发现components        Map<String, String> componentNamesAndLocations = findComponents(componentsConfig, getServletContext());        // 取得特别指定的components        Map<String, ComponentConfig> specifiedComponents = componentsConfig.getComponents();        // 实际要初始化的comonents,为上述两种来源的并集        Set<String> componentNames = createTreeSet();        componentNames.addAll(componentNamesAndLocations.keySet());        componentNames.addAll(specifiedComponents.keySet());        // 创建root controller,WebxRootController 在后面会分析到        WebxRootController rootController = componentsConfig.getRootController();        if (rootController == null) {            rootController = (WebxRootController) BeanUtils.instantiateClass(componentsConfig.getRootControllerClass());        }        // 创建并将components对象置入resolvable dependencies,以便注入到需要的bean中        WebxComponentsImpl components = new WebxComponentsImpl(componentsContext,                                                               componentsConfig.getDefaultComponent(), rootController, parentConfiguration);        beanFactory.registerResolvableDependency(WebxComponents.class, components);        // 初始化每个component        for (String componentName : componentNames) {            ComponentConfig componentConfig = specifiedComponents.get(componentName);            String componentPath = null;            WebxController controller = null;            if (componentConfig != null) {                componentPath = componentConfig.getPath();                controller = componentConfig.getController();            }            if (controller == null) {                controller = (WebxController) BeanUtils.instantiateClass(componentsConfig.getDefaultControllerClass());            }            // 每个WebxComponent就是一个子模块            // 子模块的初始化            WebxComponentImpl component = new WebxComponentImpl(components, componentName, componentPath,                                                                componentName.equals(componentsConfig.getDefaultComponent()), controller,                                                                getWebxConfigurationName());            components.addComponent(component);            prepareComponent(component, componentNamesAndLocations.get(componentName));        }        return components;    }    ...}

然后还有几个静态内部类:
1. WebxComponentsImpl(Root+子模块的集合)
2. RootComponentImpl(特殊的Component,公有共享)
3. WebxComponentImpl(子模块的Component,私有,每个子模块对应着特定的path模式)

到此,Spring初始化完成,Webx的子模块以及相关的实例也初始化完成

接下来看一下WebxFrameworkFilter的源码:

/** * 初始化spring容器的filter。 * * @author Michael Zhou */public class WebxFrameworkFilter extends FilterBean {    private final Logger log = LoggerFactory.getLogger(getClass());    private String           parentContextAttribute;    private WebxComponents   components;    private RequestURIFilter excludeFilter;    private RequestURIFilter passthruFilter;    private String           internalPathPrefix;    ...    /** 初始化filter。 */    @Override    protected final void init() throws Exception {        WebApplicationContext parentContext = findParentContext();        if (parentContext instanceof WebxComponentsContext) {            components = ((WebxComponentsContext) parentContext).getWebxComponents();            WebxConfiguration configuration = components.getParentWebxConfiguration();            if (configuration != null) {                internalPathPrefix = configuration.getInternalPathPrefix();                internalPathPrefix = normalizeAbsolutePath(internalPathPrefix, true); // 规格化成/internal            }        }        WebxRootController rootController = components.getWebxRootController();        if (passthruFilter != null) {            if (rootController instanceof PassThruSupportable) {                ((PassThruSupportable) rootController).setPassthruFilter(passthruFilter);            } else {                log.warn(                        "You have specified Passthru Filter in /WEB-INF/web.xml.  "                        + "It will not take effect because the implementation of WebxRootController ({}) does not support this feature.",                        rootController.getClass().getName());            }        }    }    // 过滤器过滤的逻辑    @Override    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)            throws IOException, ServletException {        String path = getResourcePath(request);        ...        try {            // root+subModule->RootController->Service            // 上面提到的WebxRootController被实例化,在此产生了作用            getWebxComponents().getWebxRootController().service(request, response, chain);        } catch (...) {            ...        }    }}

WebxRootControllerImpl 继承自 AbstractWebxRootController

/** * 对<code>WebxRootController</code>的默认实现。 * * @author Michael Zhou */public class WebxRootControllerImpl extends AbstractWebxRootController {    @Override    protected boolean handleRequest(RequestContext requestContext) throws Exception {        HttpServletRequest request = requestContext.getRequest();        // Servlet mapping有两种匹配方式:前缀匹配和后缀匹配。        // 对于前缀匹配,例如:/servlet/aaa/bbb,servlet path为/servlet,path info为/aaa/bbb        // 对于前缀匹配,当mapping pattern为/*时,/aaa/bbb,servlet path为"",path info为/aaa/bbb        // 对于后缀匹配,例如:/aaa/bbb.html,servlet path为/aaa/bbb.html,path info为null        //        // 对于前缀匹配,取其pathInfo;对于后缀匹配,取其servletPath。        String path = ServletUtil.getResourcePath(request);        // 再根据path查找component(子模块)        WebxComponent component = getComponents().findMatchedComponent(path);        boolean served = false;        if (component != null) {            try {                WebxUtil.setCurrentComponent(request, component);                // 获取handleRequest执行结果                served = component.getWebxController().service(requestContext);            } finally {                WebxUtil.setCurrentComponent(request, null);            }        }        return served;    }}

先到AbstractWebxRootController 看一下Service方法的实现:

    public final void service(HttpServletRequest request, HttpServletResponse response, FilterChain chain)            throws Exception {        RequestContext requestContext = null;        try {            requestContext = assertNotNull(getRequestContext(request, response), "could not get requestContext");            // 如果请求已经结束,则不执行进一步的处理。例如,当requestContext已经被重定向了,则立即结束请求的处理。            if (isRequestFinished(requestContext)) {                return;            }            // 请求未结束,则继续处理...            request = requestContext.getRequest();            response = requestContext.getResponse();            // 如果是一个内部请求,则执行内部请求            if (handleInternalRequest(request, response)) {                return;            }            // 如果不是内部的请求,并且没有被passthru,则执行handleRequest            if (isRequestPassedThru(request) || !handleRequest(requestContext)) {                // 如果请求被passthru,或者handleRequest返回false(即pipeline放弃请求),                // 则调用filter chain,将控制交还给servlet engine。                giveUpControl(requestContext, chain);            }        } catch (...) {            ...        }    }

查看子模块源码:

public class WebxControllerImpl extends AbstractWebxController {    // 管道    private Pipeline pipeline;    @Override    public void onRefreshContext() throws BeansException {        super.onRefreshContext();        initPipeline();    }    private void initPipeline() {        pipeline = getWebxConfiguration().getPipeline();        ...    }    public boolean service(RequestContext requestContext) throws Exception {        PipelineInvocationHandle handle = pipeline.newInvocation();        handle.invoke();        // 假如pipeline被中断,则视作请求未被处理。filter将转入chain中继续处理请求。        return !handle.isBroken();    }}

查看一下Pipeline的实现:

/** * 代表一组顺序执行的操作,好象液体流过一根管道一样。 * * @author Michael Zhou */public interface Pipeline {    /** 特殊的label,用来中断整个pipeline的执行。 */    String TOP_LABEL = "#TOP";    /**     * 取得pipeline的标签。     * <p>     * 这是一个可选的参数,用来方便break中断指定label的pipeline。     * </p>     */    String getLabel();    /** 创建一次新的执行。 */    PipelineInvocationHandle newInvocation();    /** 创建一次新的执行,并将此次执行看作另一个执行的子过程。 */    PipelineInvocationHandle newInvocation(PipelineContext parentContext);}

Pipline实现:

/** * 对<code>Pipeline</code>的实现。 * * @author Michael Zhou */public class PipelineImpl extends AbstractService<Pipeline> implements Pipeline {    // 管道里面的元素    private Valve[] valves;    private String  label;    @Override    protected void init() {        if (valves == null) {            valves = new Valve[0];        }        for (int i = 0; i < valves.length; i++) {            assertNotNull(valves[i], "valves[%d] == null", i);        }    }    /** 实现<code>PipelineContext</code>。 */    private final class PipelineContextImpl implements PipelineContext, PipelineInvocationHandle {        // pipline上下文        private final PipelineContext parentContext;        private final int             level;        private int executedIndex  = -1;        private int executingIndex = -1;        private boolean             broken;        private Map<String, Object> attributes;        // 执行下一个value        public void invokeNext() {            assertInitialized();            if (broken) {                return;            }            try {                // 横向的下标自增                executingIndex++;                ...                // 暂不清楚这个记录什么                executedIndex++;                if (executingIndex < valves.length) {                    Valve valve = valves[executingIndex];                    try {                        ...                        // 执行value                        valve.invoke(this);                    } catch (...) {                       ...                    } finally {                       ...                    }                    ...                } else {                    ...                }            } finally {                // 横向的下标自减                executingIndex--;            }        }        ...        public void invoke() throws IllegalStateException {            // 初始化下标,每次请求只初始化一次            executingIndex = executedIndex = -1;            invokeNext();        }        ...    }}

引入官网描述的一张图:
这里写图片描述

/** * 代表pipeline中的一个“阀门”。 * <p> * 如同真实世界里的水管中的阀门,它可以控制和改变液体的流向,<code>Valve</code> 也可以控制pipeline中后续valves的执行。 * <code>Valve</code>可以决定是否继续执行后续的valves,或是中断整个pipeline的执行。 * </p> * * @author Michael Zhou */public interface Valve {    void invoke(PipelineContext pipelineContext) throws Exception;}

通过上面的pipline的相关结构,其实和配置文件反应出来的是一样的,这是个有序的执行结构,而且可以通过配置文件的配置,改变其执行的顺序:

    <services:pipeline xmlns="http://www.alibaba.com/schema/services/pipeline/valves">        <!-- 初始化turbine rundata,并在pipelineContext中设置可能会用到的对象(如rundata、utils),以便valve取得。 -->        <prepareForTurbine />        <!-- 设置日志系统的上下文,支持把当前请求的详情打印在日志中。 -->        <setLoggingContext />        <!-- 分析URL,取得target。 -->        <analyzeURL homepage="homepage" />        <!-- 检查csrf token,防止csrf攻击和重复提交。 -->        <checkCsrfToken />        <loop>            <choose>                <when>                    <!-- 执行带模板的screen,默认有layout。 -->                    <pl-conditions:target-extension-condition extension="null, vm, jsp" />                    <performAction />                    <performTemplateScreen />                    <renderTemplate />                </when>                <when>                    <!-- 执行不带模板的screen,默认无layout。 -->                    <pl-conditions:target-extension-condition extension="do" />                    <performAction />                    <performScreen />                </when>                <otherwise>                    <!-- 将控制交还给servlet engine。 -->                    <exit />                </otherwise>            </choose>            <!-- 假如rundata.setRedirectTarget()被设置,则循环,否则退出循环。 -->            <breakUnlessTargetRedirected />        </loop>    </services:pipeline>

从配置文件,我们可以看到checkCsrfToken,那么它就是对应着一个Value,可以看看Value的实现:
这里写图片描述
直接找一个比较容易理解的Value,那就是performActionValue,执行访问Screen/Module/的类的execute方法:

/** * 执行action module,通常用来处理用户提交的表单。 * * @author Michael Zhou */public class PerformActionValve extends AbstractValve {    @Autowired    private HttpServletRequest request;    @Autowired    private ModuleLoaderService moduleLoaderService;    public void invoke(PipelineContext pipelineContext) throws Exception {        TurbineRunData rundata = getTurbineRunData(request);        // 检查重定向标志,如果是重定向,则不需要将页面输出。        if (!rundata.isRedirected()) {            String action = rundata.getAction();            // 如果找到action,则执行之。            if (!StringUtil.isEmpty(action)) {                String actionKey = "_action_" + action;                // 防止重复执行同一个action。                if (rundata.getRequest().getAttribute(actionKey) == null) {                    rundata.getRequest().setAttribute(actionKey, "executed");                    try {                        moduleLoaderService.getModule(ACTION_MODULE, action).execute();                    } catch (...) {                        ...                    }                }            }        }        // 执行接下面的Value,对应着上面的配置文件就是performScreenValue        pipelineContext.invokeNext();    }    ...}

看看module是什么:

/** * 代表一个模块。 * * @author Michael Zhou */public interface Module {    /** 执行模块。 */    void execute() throws Exception;}

看看exeute的实现:

public abstract class AbstractModuleEventAdapter extends AbstractDataBindingAdapter        implements InitializingBean, ModuleEvent {    private final Map<String, MethodInvoker> handlers;    private final MethodInvoker              preHandler;    private final MethodInvoker              postHandler;    @Autowired    private HttpServletRequest request;    ...    /** 执行一个module。 */    public void execute() throws ModuleEventException, ModuleEventNotFoundException {        executeAndReturn();    }    /** 执行一个module,并返回值。 */    public Object executeAndReturn() throws ModuleEventException, ModuleEventNotFoundException {        Object result = null;        String event = getEventName(request);        MethodInvoker handler = null;        // 查找精确匹配的方法        if (event != null) {            handler = handlers.get(event);        }        // 查找fallback method        if (handler == null) {            handler = handlers.get(null);        }        ...        // 执行preHandler        if (preHandler != null) {            ...            try {                preHandler.invoke(moduleObject, log);            } catch (...) {               ...            }        }        ModuleEventException exception = null;        try {            // 执行event handler            ...            try {                result = handler.invoke(moduleObject, log);            } catch (Exception e) {            // 捕获异常                exception = new ModuleEventException("Failed to execute handler: " + handler, e);            }        } finally {            // 执行postHandler            if (postHandler != null) {                ...                try {                    postHandler.invoke(moduleObject, log);                } catch (Exception e) {                    if (exception == null) {                    // 捕获异常                        exception = new ModuleEventException("Failed to execute post-handler: " + postHandler, e);                    }                }            }        }        if (exception != null) {        // 抛出异常            throw exception;        }        return result;    }    ...}

整个Webx MVC的初始化以及访问大体完成了,剩下就是原路返回数据进行相关处理。

0 0
原创粉丝点击