概念介绍
Contexts
WebxComponentsContext
----类介绍:所有组件的共有上下文,即父容器,对应的默认spring配置文件为“webx.xml”
----成员变量
WebxComponentsLoader:因为beanFactory的行为均定义在WebxComponentsLoader中,故持有此变量
----成员函数
getWebxComponents:从加载器中取得webxComponents
postProcessBeanFactory:拓展点之一,使用该拓展点旨在合理的时间内创建compone nts和component
finishRefresh:拓展点之一,使用该拓展点旨在合理的时间内refresh组件的beanFactory
WebxComponentContext
---类介绍:组件的上下文,对应的默认spring配置文件为"webx*.xml"
----成员变量
WebxComponent:组件
Components
WebxComponentsImpl
----成员变量
parentConfiguration:父容器的配置,对应于“webx.xml”中"name"为"webx_configuration"的bean,这是一个VO
parentContext:即父容器
components:一个map,保存所有的component的映射
rootComponent:根组件,对应的context即parentContext
defaultComponentName:默认组件名,根据"webx_configuration"得出
rootController:父组件的控制器
RootComponent
TODO
WebxComponent
----成员变量
components:持有所属的conponents
name:组件名
componentPath:组件路径
controller:组件的控制器
webxConfiurationName:为了获取各组件configuration的bean的name
context:顾名思义,即各个组件的上下文
Controllers
TODO
Configurations
TODO
初始化概述
1、servlet容器启动
web.xml:
loggingRoot /Users/apple/workspace/3.0/petstore/logs loggingLevel warn loggingCharset UTF-8 com.alibaba.citrus.logconfig.LogConfiguratorListener com.alibaba.citrus.webx.context.WebxContextLoaderListener mdc com.alibaba.citrus.webx.servlet.SetLoggingContextFilter webx com.alibaba.citrus.webx.servlet.WebxFrameworkFilter mdc /* webx /* index.html index.jsp
在这里,WebxContextLoaderListener负责框架的初始化,而WebxFrameworkFilter则是框架的入口
2、实例化加载器ContextLoader
重写了spring提供的加载器,应用WebxComponentsLoader,充血模型,定义了大多数的行为
3、加载ComponentsContext
对应的配置文件为"webx.xml",为所有组件context的父容器
4、加载Components,Component,ComponentsController,ComponentController
通过spring的拓展点postProcessBeanFactory植入了创建components的bean,在后续的invoke中执行该bean的post方法
5、初始化单例Bean
ApplicationContext的特点之一
6、初始化ComponentsController
通过spring的事件监听机制,注册Components观察者,实现成员变量ComponetsController的初始化
7、初始化Component
通过spring容器的finishRefresh拓展实现组件的初始化
8、初始化ComponentController
依旧通过观察者模式利用spring的事件监听机制实现pipeline等的初始化
9、初始化FilterChain
至此bean容器初始化完成,接下来初始化FilterChain的每个filter,这里将从servletContext取出上一步骤生成的Components等参数来初始化filter
初始化详解
从initWebApplicationContext入口点开始
【ContextLoader】public WebApplicationContext initWebApplicationContext(ServletContext servletContext) throws IllegalStateException, BeansException { if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { throw new IllegalStateException( "Cannot initialize context because there is already a root application context present - " + "check whether you have multiple ContextLoader* definitions in your web.xml!"); } servletContext.log("Initializing Spring root WebApplicationContext"); if (logger.isInfoEnabled()) { logger.info("Root WebApplicationContext: initialization started"); } long startTime = System.currentTimeMillis(); try { // Determine parent for root web application context, if any. ApplicationContext parent = loadParentContext(servletContext); // Store context in local instance variable, to guarantee that // it is available on ServletContext shutdown. this.context = createWebApplicationContext(servletContext, parent); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context); ......
接下来看下CreateWebApplicationContext,这里有个拓展点
【ContextLoader】protected WebApplicationContext createWebApplicationContext( ServletContext servletContext, ApplicationContext parent) throws BeansException { Class contextClass = determineContextClass(servletContext); if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]"); } ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); wac.setParent(parent); wac.setServletContext(servletContext); wac.setConfigLocation(servletContext.getInitParameter(CONFIG_LOCATION_PARAM)); customizeContext(servletContext, wac); wac.refresh(); return wac; }
【WebxComponentsLoader】protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext componentsContext) { this.componentsContext = componentsContext; if (componentsContext instanceof WebxComponentsContext) { ((WebxComponentsContext) componentsContext).setLoader(this); } }
了解下refresh做了哪些事
【AbstractContextApplication】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这一步
【WebxComponentsContext】protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { super.postProcessBeanFactory(beanFactory); getLoader().postProcessBeanFactory(beanFactory); }
这里已经可以看到webxComponentsContext持有loader是为了调用loader的行为;
【WebxComponentsLoader】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); }
接下来就是执行这些BeanFactoryProcessor,个人觉得这个需要深入研究下
【AbstractApplicationContext】protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // Invoke factory processors registered with the context instance. for (Iterator it = getBeanFactoryPostProcessors().iterator(); it.hasNext();) { BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor) it.next(); factoryProcessor.postProcessBeanFactory(beanFactory); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the bean factory post-processors apply to them! String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); // Separate between BeanFactoryPostProcessors that implement PriorityOrdered, // Ordered, and the rest. List priorityOrderedPostProcessors = new ArrayList(); List orderedPostProcessorNames = new ArrayList(); List nonOrderedPostProcessorNames = new ArrayList(); for (int i = 0; i < postProcessorNames.length; i++) { if (isTypeMatch(postProcessorNames[i], PriorityOrdered.class)) { priorityOrderedPostProcessors.add(beanFactory.getBean(postProcessorNames[i])); } else if (isTypeMatch(postProcessorNames[i], Ordered.class)) { orderedPostProcessorNames.add(postProcessorNames[i]); } else { nonOrderedPostProcessorNames.add(postProcessorNames[i]); } } // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered. Collections.sort(priorityOrderedPostProcessors, new OrderComparator()); invokeBeanFactoryPostProcessors(beanFactory, priorityOrderedPostProcessors); ......
这里有两个看点:1、BeanFactory第一次初始化Bean貌似就是这里,当然这个是题外话;2、一共有3个Bean需要被post,第一个是占位符(在webx.xml配置了该bean),第二个是RequestContextBeanFactoryPostProcessor,第三个是WebxComponentsCreator。主要分析后面两个,第一个是现存的,不做分析。
WebxComponentsCreator
【WebxComponentsLoader】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) { //loader.getParentConfiguration()为第一次执行getBean操作,configuration是什么,下面有分析 WebxComponentsImpl components = loader.createComponents(loader.getParentConfiguration(), beanFactory); AbstractApplicationContext wcc = (AbstractApplicationContext) components.getParentApplicationContext(); wcc.addApplicationListener(new SourceFilteringListener(wcc, components)); loader.components = components; } } private WebxComponentsImpl createComponents(WebxConfiguration parentConfiguration, ConfigurableListableBeanFactory beanFactory) { //从VO中取出Bean ComponentsConfig componentsConfig = getComponentsConfig(parentConfiguration); // 假如isAutoDiscoverComponents==true,试图自动发现components MapcomponentNamesAndLocations = findComponents(componentsConfig, getServletContext()); // 取得特别指定的components Map specifiedComponents = componentsConfig.getComponents(); // 实际要初始化的comonents,为上述两种来源的并集 Set 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; } private void prepareComponent(WebxComponentImpl component, String componentLocation) { String componentName = component.getName(); WebxComponentContext wcc = new WebxComponentContext(component); wcc.setServletContext(getServletContext()); wcc.setNamespace(componentName); wcc.addApplicationListener(new SourceFilteringListener(wcc, component)); if (componentLocation != null) { wcc.setConfigLocation(componentLocation); } component.setApplicationContext(wcc); // 将context保存在servletContext中 String attrName = getComponentContextAttributeName(componentName); getServletContext().setAttribute(attrName, wcc); log.debug("Published WebApplicationContext of component {} as ServletContext attribute with name [{}]", componentName, attrName); }
RequestContextBeanFactoryPostProcessor
【RequestContextBeanFactoryPostProcessor】public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // 先注册request/response/session,再从beanFactory中取得requestContexts。 // 创建全局的request实例。 register(beanFactory, ServletRequest.class, createProxy(HttpServletRequest.class, beanFactory.getBeanClassLoader(), new RequestObjectFactory())); // 创建全局的session实例。 register(beanFactory, HttpSession.class, createProxy(HttpSession.class, beanFactory.getBeanClassLoader(), new SessionObjectFactory())); // 创建全局的response实例。 register(beanFactory, ServletResponse.class, createProxy(HttpServletResponse.class, beanFactory.getBeanClassLoader(), new ResponseObjectFactory())); // 取得requestContexts时会激活requestContexts的初始化。 // 由于request/response/session已经被注册,因此已经可被注入到requestContexts的子对象中。 RequestContextChainingService requestContexts = (RequestContextChainingService) beanFactory.getBean( requestContextsName, RequestContextChainingService.class); // 创建全局的request context实例。 for (RequestContextInfo info : requestContexts.getRequestContextInfos()) { Class requestContextInterface = info.getRequestContextInterface(); Class requestContextProxyInterface = info.getRequestContextProxyInterface(); register( beanFactory, requestContextInterface, createProxy(requestContextProxyInterface, beanFactory.getBeanClassLoader(), new RequestContextObjectFactory(requestContextProxyInterface))); } }
【RequestContextBeanFactoryPostProcessor&RequestObjectFactory】private static class RequestObjectFactory implements ObjectFactory { public Object getObject() { RequestAttributes requestAttrs = RequestContextHolder.currentRequestAttributes(); if (!(requestAttrs instanceof ServletRequestAttributes)) { throw new IllegalStateException("Current request is not a servlet request"); } HttpServletRequest request = ((ServletRequestAttributes) requestAttrs).getRequest(); if (request == null) { throw new IllegalStateException("Current request is not a servlet request"); } return request; } }
【RequestContextHolder】public abstract class RequestContextHolder { private static final boolean jsfPresent = ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader()); private static final ThreadLocal requestAttributesHolder = new NamedThreadLocal("Request attributes"); private static final ThreadLocal inheritableRequestAttributesHolder = new NamedInheritableThreadLocal("Request context"); public static RequestAttributes getRequestAttributes() { RequestAttributes attributes = (RequestAttributes) requestAttributesHolder.get(); if (attributes == null) { attributes = (RequestAttributes) inheritableRequestAttributesHolder.get(); } return attributes; } public static RequestAttributes currentRequestAttributes() throws IllegalStateException { RequestAttributes attributes = getRequestAttributes(); if (attributes == null) { if (jsfPresent) { attributes = FacesRequestAttributesFactory.getFacesRequestAttributes(); } if (attributes == null) { throw new IllegalStateException("No thread-bound request found: " + "Are you referring to request attributes outside of an actual web request, " + "or processing a request outside of the originally receiving thread? " + "If you are actually operating within a web request and still receive this message, " + "your code is probably running outside of DispatcherServlet/DispatcherPortlet: " + "In this case, use RequestContextListener or RequestContextFilter to expose the current request."); } } return attributes; }
BeanFactoryPostProcessor终于结束了,看下finishRefresh,这也是个拓展点,主要是用来初始化controller和componentContext
【WebxComponentsContext】protected void finishRefresh() { super.finishRefresh(); getLoader().finishRefresh(); }
【WebxComponentsLoader】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"); }
容器初始化至此结束了,最后介绍下filter的初始化