首先在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的初始化以及访问大体完成了,剩下就是原路返回数据进行相关处理。