webx扩展了spring的容器加载机制,首先在结构上扩展了component层,构造出不同应用模块bean之间的隔离机制。
1.解析web.xml
和spring web程序一样,容器的加载是通过在web.xml中配置的listener实现的。servlet容器在实例化servlet context的时候会触发contextInitialized方法从而开启实例化容器的流程。
根据servlet规范,listener按照观察者模式设计,一旦监听到某个事件就执行某个方法。而web.xml文件中有WebxContextLoaderListener继承了ServletContextListener接口,就会调用contextInitialized方法。
2.分析WebxContextLoaderListener
该类的功能:监听ServletContext事件,加载Spring容器;
类的继承结构:
@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; } }; }
ContextLoaderListener中调用上面创建的contextLoader进行初始化webx容器
public void contextInitialized(ServletContextEvent event) { this.contextLoader = createContextLoader(); if (this.contextLoader == null) { this.contextLoader = this; } this.contextLoader.initWebApplicationContext(event.getServletContext()); }
3.应用上下文结构
相对于Spring上下文中以bean为单位进行加载,webx新增加了组件的结构。在容器加载的时候webx默认会扫描web-info目录下的webx.xml 文件和webx-*xml文件,进行资源加载,创建容器。
webx将一个web应用分解成多个小应用模块:app1,app2等。将一个大的应用变成若干个小应用模块,并且配置文件相互隔离。
- 所有小应用模块共享一个Spring Root Context( 根容器 ),对应 webx.xml ,根容器的bean可以被注入到子容器中;反过来不行。
- 每个小应用独享一个Spring Sub Context( 子容器 ),对应 webx-*.xml ,子容器之间相互隔离,不可相互注入bean。
需要注意的是,即使web应用很简单,也至少配置一个子容器。
如何实现刚才所说的组件容器加载的呢?WebxComponentsContext继承了AbstractApplicationContext并对 postProcessBeanFactory 方法和 finishRefresh方法进行了覆写,也正是这两个方法实现了webx独特的component。这一点非常重要!
在配置文件中,例如webx-*.xml中导入其他的xml加载bean的时候,从根上下文中是加载不到这些bean的,要通过获取该模块的component对应的上下文才能获取。
WebApplicationContext context = WebApplicationContextUtils .getWebApplicationContext(getServletContext()); WebxComponentsContext webxComponentsContext = (WebxComponentsContext)context; WebxComponents components = webxComponentsContext.getWebxComponents(); WebxComponent component = components.getComponent("home"); playService = (PlayService) component.getApplicationContext().getBean("playServiceImpl");
扩展加载component的结构图:
1)覆写postProcessBeanFactory方法,实际上是实例化WebxComponentsCreator内部类,用于初始化root component和sub component,并且将所有的sub component的父容器设置成root component,形成级联结构。
/** 初始化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 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()); } WebxComponentImpl component = new WebxComponentImpl(components, componentName, componentPath, componentName.equals(componentsConfig.getDefaultComponent()), controller, getWebxConfigurationName()); components.addComponent(component); prepareComponent(component, componentNamesAndLocations.get(componentName)); } return components; }
2)- 覆写finishRefresh方法,遍历地所有的sub component,通过wcc.refresh方法初始化每个sub component中的bean。
/** 初始化所有components。 */ public void finishRefresh() { components.getWebxRootController().onFinishedProcessContext(); for (WebxComponent component : components) { logInBothServletAndLoggingSystem("Initializing Spring sub WebApplicationContext: " + component.getName()); WebxComponentContext wcc = (WebxComponentContext) component.getApplicationContext(); WebxController controller = component.getWebxController(); wcc.refresh(); controller.onFinishedProcessContext(); } logInBothServletAndLoggingSystem("WebxComponents: initialization completed"); }