webx3.0-容器初始化

概念介绍

Contexts

WebxComponentsContext

----类介绍:所有组件的共有上下文,即父容器,对应的默认spring配置文件为“webx.xml”

----成员变量

WebxComponentsLoader:因为beanFactory的行为均定义在WebxComponentsLoader中,故持有此变量

----成员函数

getWebxComponents:从加载器中取得webxComponents

postProcessBeanFactory:拓展点之一,使用该拓展点旨在合理的时间内创建components和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:

<?xml version="1.0" encoding="GBK"?>
<web-app version="2.4" xmlns="<a href="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="
        http://java.sun.com/xml/ns/j2ee  http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd
    ">
 
    <context-param>
        <param-name>loggingRoot</param-name>
        <param-value>/Users/apple/workspace/3.0/petstore/logs</param-value>
    </context-param>
    <context-param>
        <param-name>loggingLevel</param-name>
        <param-value>warn</param-value>
    </context-param>
    <context-param>
        <param-name>loggingCharset</param-name>
        <param-value>UTF-8</param-value>
    </context-param>
 
    <listener>
        <listener-class>com.alibaba.citrus.logconfig.LogConfiguratorListener</listener-class>
    </listener>
 
    <!-- װ��/WEB-INF/webx.xml, /WEB-INF/webx-*.xml -->
    <listener>
        <listener-class>com.alibaba.citrus.webx.context.WebxContextLoaderListener</listener-class>
    </listener>
 
    <filter>
        <filter-name>mdc</filter-name>
        <filter-class>com.alibaba.citrus.webx.servlet.SetLoggingContextFilter</filter-class>
    </filter>
 
    <filter>
        <filter-name>webx</filter-name>
        <filter-class>com.alibaba.citrus.webx.servlet.WebxFrameworkFilter</filter-class>
    </filter>
 
    <filter-mapping>
        <filter-name>mdc</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
 
    <filter-mapping>
        <filter-name>webx</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
 
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
 
</web-app>

在这里,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
        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;
    }
 
    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<? extends RequestContext> requestContextInterface = info.getRequestContextInterface();
            Class<? extends RequestContext> 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的初始化


你可能感兴趣的:(webx)