这两天利用空余时间学习了webx3.0,基于spring mvc开发的一款mvc;由于对webx2.0以及spring mvc没有进行过深入的研究,在学习webx3.0的时候,肯定会出现理解上的偏差甚至错误,希望大家积极提出,有问题才是进步的动力;以前很少写文章,文笔不好,还请大家见谅,:)!无废话,开始:
Web.xml,tomcat加载war包开始:
<!-- 装载/WEB-INF/webx.xml, /WEB-INF/webx-*.xml --> <listener> <listener-class>com.alibaba.citrus.webx.context.WebxContextLoaderListener</listener-class> </listener>
其中WebxContextLoaderListener 信息如下:
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.ContextLoaderListener;
public class WebxContextLoaderListener extends ContextLoaderListener {
……
WebxContextLoaderListener继承了spring mvc的监听类:ContextLoaderListener;
可想而知,容器启动时,将调用: contextInitialized(ServletContextEvent event) 该方法,如下:
public void contextInitialized(ServletContextEvent event) {
//1.初始化加载类
this.contextLoader = createContextLoader();
//2.出示话web上下文
this.contextLoader.initWebApplicationContext(event.getServletContext());
}
由于WebxContextLoaderListener覆盖了createContextLoader()方法,
@Override
protected final ContextLoader createContextLoader() {
return new WebxComponentsLoader() {
@Override
protected Class<?> getDefaultContextClass() {
Class<?> defaultContextClass = WebxContextLoaderListener.this.getDefaultContextClass();
if (defaultContextClass == null) {
defaultContextClass = super.getDefaultContextClass();
}
return defaultContextClass;
}
};
}
contextLoader已经是这个了:WebxComponentsLoader 重点关注这个类,
public class WebxComponentsLoader extends ContextLoader
将负责加载webx中的componet组件,还继承了spring mvc的加载类 ContextLoader,
所以initWebApplicationContext 就在子类WebxComponentsLoader中执行了:
@Override
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) throws IllegalStateException,
BeansException {
this.servletContext = servletContext;
init();
//开始spring mvc加载…
return super.initWebApplicationContext(servletContext);
}
经过自己的init后
super.initWebApplicationContext(servletContext);
又回到父类里面去了:
public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
throws IllegalStateException, BeansException {
//.....先忽略
long startTime = System.currentTimeMillis();
try {
// Determine parent for root web application context, if any.
//1.先找parent,一般是空的吧
ApplicationContext parent = loadParentContext(servletContext);
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
//2.创建
this.context = createWebApplicationContext(servletContext, parent);
//3.设为root
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context);
//再忽略...
return this.context;
}
catch (RuntimeException ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
catch (Error err) {
logger.error("Context initialization failed", err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
throw err;
}
}
createWebApplicationContext方法主要包括下面4步:
1.找到上下文类
Class contextClass = determineContextClass(servletContext);
定位上下文class,这个class可配置;这个方法被WebxContextLoaderListener覆盖,最后返回的class:
return WebxComponentsContext.class;
第二个重要的类出现:WebxComponentsContext
WebxComponentsContext
继承
WebxApplicationContext(webx重写)
继承
XmlWebApplicationContext(spring原生)
2.实例化上下文类
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setParent(parent);
wac.setServletContext(servletContext);
wac.setConfigLocation(servletContext.getInitParameter(CONFIG_LOCATION_PARAM));
3.可以自定义操作上下文
customizeContext(servletContext, wac);
//被子类覆盖
此方法也被WebxContextLoaderListener覆盖:
protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext componentsContext) {
this.componentsContext = componentsContext;
if (componentsContext instanceof WebxComponentsContext) {
// componentsContext就是上面实例化的上下文,铁定是WebxComponentsContext类
((WebxComponentsContext) componentsContext).setLoader(this);
//为load webx组件配置文件而准备
}
}
4.初始化IOC容器
wac.refresh();
看到熟悉的refush方法了,ConfigurableWebApplicationContext是没有refush方法,AbstractApplicationContext这个类有refush方法:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
//被覆盖,重点关注
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
//被覆盖,重点关注
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
beanFactory.destroySingletons();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
postProcessBeanFactory(beanFactory);有覆盖吗?有!
实例化前,webx覆盖了此方法来,进行把webx组件实例放入spring中,怎么放?哪里执行?
((WebxComponentsContext) componentsContext).setLoader(this);
这里看出是WebxComponentsLoader来进行这个工作:
/**
* 在创建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:
/**
* 初始化components。
*/
private WebxComponentsImpl createComponents(WebxConfiguration parentConfiguration,
ConfigurableListableBeanFactory beanFactory) {
//1.取得一组关于components的配置,也就是component的配置文件,ComponentsConfigImpl中
ComponentsConfig componentsConfig = getComponentsConfig(parentConfiguration);
// 2.假如isAutoDiscoverComponents==true,试图自动发现components
Map<String, String> componentNamesAndLocations = findComponents(componentsConfig, getServletContext());
// 3.取得特别指定的components
Map<String, ComponentConfig> specifiedComponents = componentsConfig.getComponents();
// 4.实际要初始化的comonents,为上述两种来源的并集
Set<String> componentNames = createTreeSet();
componentNames.addAll(componentNamesAndLocations.keySet());
componentNames.addAll(specifiedComponents.keySet());
// 5.创建root controller
WebxRootController rootController = componentsConfig.getRootController();
if (rootController == null) {
rootController = (WebxRootController) BeanUtils.instantiateClass(componentsConfig.getRootControllerClass());
}
// 6.创建并将components对象置入resolvable dependencies,以便注入到需要的bean中
WebxComponentsImpl components = new WebxComponentsImpl(componentsContext, componentsConfig
.getDefaultComponent(), rootController, parentConfiguration);
beanFactory.registerResolvableDependency(WebxComponents.class, components);
// 7.初始化每个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());
}
WebxComponentImpl component = new WebxComponentImpl(components, componentName, componentPath, componentName
.equals(componentsConfig.getDefaultComponent()), controller, getWebxConfigurationName());
components.addComponent(component);
prepareComponent(component, componentNamesAndLocations.get(componentName));
}
return components;
}
怎么找到components,只要找到对应配置项即可
public String getComponentConfigurationLocationPattern() {
return componentConfigurationLocationPattern == null ? "/WEB-INF/webx-*.xml"
: componentConfigurationLocationPattern;
}
//找到了配置文件,接下去要解析了,里面实现比较啰嗦,@#¥#@¥@#¥一大堆,返回
未完待续......
学习了webx3.0和spring mvc如何结果工作,对于定制web mvc有帮助!