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的初始化以及访问大体完成了,剩下就是原路返回数据进行相关处理。
- Webx MVC
- Webx mvc 源码
- Webx MVC实现机制的详细分析
- webX
- Webx
- webx
- miniwebx 基于webx设计思想的轻量级mvc框架
- 结合Spring IOC 看Webx & HSF & Spring MVC
- webx- webx framework
- Webx-webx turbine
- webx解析
- Webx SpringExt
- webx概念
- WebX基础知识
- webx学习
- webx 学习
- webx入门
- webx小结
- runtime在应用国际化上的实践
- 详细的Log4j使用教程
- Permission denied, please try again.
- 附件上传大小限制-拦截器方法
- Jquery中选择器的使用笔记2
- Webx MVC
- linux系统下安装两个或多个tomcat
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
- 让windows和linux安全共存
- 【Java并发编程】(一)——Java内存模型
- 关于Android 电话接通的时候,将proximity sensor开启的源码分析
- druid
- SSL VPN和IPsec VPN的比较和选择
- windbg使用