zoukankan      html  css  js  c++  java
  • Spring 学习记录8 初识XmlWebApplicationContext(2)

    主题

    接上文Spring 学习记录7 初识XmlWebApplicationContext

    refresh方法

    refresh方法是定义在父类AbstractApplicationContext中的.它内部会调用很多方法.有一些是在子类中实现的.算是模板方法的设计模式吧.主要作用就是初始化wac加载各种bean等作用.

     1 @Override
     2     public void refresh() throws BeansException, IllegalStateException {
     3         synchronized (this.startupShutdownMonitor) {
     4             // Prepare this context for refreshing.
     5             // 记录开始wac开始初始化的时间,设置激活标记,servlet的相关param设置到env(之前做过1次),校验env中必须的props
     6             prepareRefresh();
     7 
     8             // Tell the subclass to refresh the internal bean factory.
     9             // 刷新初始化BF并获取它,将旧的BF里的bean删掉,新建1个BF,加载XML配置文件
    10             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    11 
    12             // Prepare the bean factory for use in this context.
    13             prepareBeanFactory(beanFactory);
    14 
    15             try {
    16                 // Allows post-processing of the bean factory in context subclasses.
    17                 postProcessBeanFactory(beanFactory);
    18 
    19                 // Invoke factory processors registered as beans in the context.
    20                 invokeBeanFactoryPostProcessors(beanFactory);
    21 
    22                 // Register bean processors that intercept bean creation.
    23                 registerBeanPostProcessors(beanFactory);
    24 
    25                 // Initialize message source for this context.
    26                 initMessageSource();
    27 
    28                 // Initialize event multicaster for this context.
    29                 initApplicationEventMulticaster();
    30 
    31                 // Initialize other special beans in specific context subclasses.
    32                 onRefresh();
    33 
    34                 // Check for listener beans and register them.
    35                 registerListeners();
    36 
    37                 // Instantiate all remaining (non-lazy-init) singletons.
    38                 finishBeanFactoryInitialization(beanFactory);
    39 
    40                 // Last step: publish corresponding event.
    41                 finishRefresh();
    42             } catch (BeansException ex) {
    43                 logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
    44 
    45                 // Destroy already created singletons to avoid dangling resources.
    46                 destroyBeans();
    47 
    48                 // Reset 'active' flag.
    49                 cancelRefresh(ex);
    50 
    51                 // Propagate exception to caller.
    52                 throw ex;
    53             }
    54         }
    55     }
    View Code

    prepareRefresh方法

    第一个被调用的方法就是它

    主要作用:

    记录开始wac开始初始化的时间,设置激活标记,servlet的相关param设置到env(之前做过1次),校验env中必须的props

     1     /**
     2      * Prepare this context for refreshing, setting its startup date and
     3      * active flag as well as performing any initialization of property sources.
     4      * 记录开始wac开始初始化的时间,设置激活标记,servlet的相关param设置到env(之前做过1次),校验env中必须的props
     5      */
     6     protected void prepareRefresh() {
     7         this.startupDate = System.currentTimeMillis();
     8         this.active.set(true);
     9 
    10         if (logger.isInfoEnabled()) {
    11             logger.info("Refreshing " + this);
    12         }
    13 
    14         // Initialize any placeholder property sources in the context environment
    15         // 讲servlet的config和context里的params赋值给env..之前已经做过一次了,这个wac可能会由servlet初始化,这样的话ServletConfig就不会为空
    16         initPropertySources();
    17 
    18         // Validate that all properties marked as required are resolvable
    19         // see ConfigurablePropertyResolver#setRequiredProperties
    20         // 在env中有一些properties是必须的,校验这些props.没有就抛出异常
    21         getEnvironment().validateRequiredProperties();
    22     }

    L16..这个方法做了什么直接看注释吧..

     1     /**
     2      * {@inheritDoc}
     3      * <p>Replace {@code Servlet}-related property sources.
     4      */
     5     @Override
     6     protected void initPropertySources() {
     7         ConfigurableEnvironment env = getEnvironment();
     8         if (env instanceof ConfigurableWebEnvironment) {
     9             ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, this.servletConfig);
    10         }
    11     }

    就是拿servletContext和servletConfig去填充env....和之前做的一样....如果是listener初始化的话这里servletConfig肯定是空的.

    L21 对env里的必须的属性进行校验.如果这些属性不存在的话就报错.(但是我源码里搜索了一下并没有找到调用设置必须属性的地方...不知道怎么使用才能标记属性为必须....)

    obtainFreshBeanFactory方法

    主要作用:

    刷新初始化BF并获取它,将旧的BF里的bean删掉,新建1个BF,加载XML配置文件

     1     /**
     2      * Tell the subclass to refresh the internal bean factory.
     3      * 刷新初始化BF并获取它,将旧的BF里的bean删掉,新建1个BF,加载XML配置文件
     4      *
     5      * @return the fresh BeanFactory instance
     6      * @see #refreshBeanFactory()
     7      * @see #getBeanFactory()
     8      */
     9     protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    10         refreshBeanFactory(); // 刷新BF
    11         ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    12         if (logger.isDebugEnabled()) {
    13             logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    14         }
    15         return beanFactory;
    16     }

    L10 refreshBeanFactory(); 

     1     /**
     2      * This implementation performs an actual refresh of this context's underlying
     3      * bean factory, shutting down the previous bean factory (if any) and
     4      * initializing a fresh bean factory for the next phase of the context's lifecycle.
     5      */
     6     @Override
     7     protected final void refreshBeanFactory() throws BeansException {
     8         if (hasBeanFactory()) {
     9             destroyBeans(); // 删除所有单例bean
    10             closeBeanFactory(); // wac中的BF成员域=null.
    11         }
    12         try {
    13             DefaultListableBeanFactory beanFactory = createBeanFactory(); // 创建1个新的DefaultListableBeanFactory
    14             beanFactory.setSerializationId(getId()); // 设置ID
    15             customizeBeanFactory(beanFactory); // wac 中的属性 allowBeanDefinitionOverriding allowCircularReferences 覆盖BF
    16             loadBeanDefinitions(beanFactory); // 加载BeanDefinitions.
    17             synchronized (this.beanFactoryMonitor) {
    18                 this.beanFactory = beanFactory;
    19             }
    20         } catch (IOException ex) {
    21             throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    22         }
    23     }
    View Code

    主要作用就是先把之前的beanfactory里创建的bean都销毁,然后销毁beanfactory.

    然后新建1个DefaultListableBeanFactory,并配置一些通过wac配置的属性.

    再加载一下bean的配置.在这里因为wac是XmlWebApplicationContext,所以bean的配置肯定是写在XML里的了.

    最后把bf对象设置到wac的成员域上.

    L11得到之前设置的新的BF并在L15返回...

    prepareBeanFactory方法

    主要作用:

    1.设置BF解析bean配置需要用到的一些对象比如env. 2.注册一些BeanPostProcessor比如ApplicationContextAwareProcessor去设置Aware需要的对象 3.忽略一些特定class注入的对象,设置一些特定class注入的对象为指定值 4.将一些env中的properties map当做bean注册到BF中

     1 /**
     2      * Configure the factory's standard context characteristics,
     3      * such as the context's ClassLoader and post-processors.
     4      *
     5      * @param beanFactory the BeanFactory to configure
     6      */
     7     protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
     8         // Tell the internal bean factory to use the context's class loader etc.
     9         // BF需要解析属性或者转化需要用到env和其他相关的类.从wac中设置进去
    10         beanFactory.setBeanClassLoader(getClassLoader());
    11         beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    12         beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
    13 
    14         // Configure the bean factory with context callbacks.
    15         // 因为bean是在BF中创建的,所以如果他们需要用到wac的callback比如ApplicationEventPublisherAware的方法或者ApplicationContextAware,
    16         // 那就需要再BF生成bean的时候注入applicationcontext或者它的相关类.比如env
    17         beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    18         beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    19         beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    20         beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    21         beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
    22         beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    23 
    24         // BeanFactory interface not registered as resolvable type in a plain factory.
    25         // MessageSource registered (and found for autowiring) as a bean.
    26         // 如果要注入以下类型的bean,直接使用这些对象
    27         beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    28         beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    29         beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    30         beanFactory.registerResolvableDependency(ApplicationContext.class, this);
    31 
    32         // Detect a LoadTimeWeaver and prepare for weaving, if found.
    33         if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
    34             beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
    35             // Set a temporary ClassLoader for type matching.
    36             beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    37         }
    38 
    39         // Register default environment beans.
    40         // 将一些properties当做bean放到BF中
    41         if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
    42             beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    43         }
    44         if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
    45             beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    46         }
    47         if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
    48             beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    49         }
    50     }

    第一个代码块就是设置一些BF解析bean需要用到的对象.比如env.

    第二个代码块就是add了一些XXXAwareProcess.比如applicationContextAware...BF在创建这个bean以后会调用ApplicationContextAwareProcessor的回调函数去注入applicationContext.

    然后忽略了一些接口,他们不会被注入实现类.

    第三个代码块配置了一些接口的注入的实现类.

    第四个代码又注入了一个BeanPostProcessor,这个似乎和AOP有关系.没研究过.

    第五个代码块就是把env中的一些props当做bean注册到BF中去.

    postProcessBeanFactory方法

    又是1个模板方法.可以对BF进行一些加工定制.

    在web环境下有重写过.

    主要作用:

    1.设置一个BeanPostProcess为ServletContextAware的实现类注入servlet相关对象
    2.在BF中增加requetsScope等Scope
    3.把servletContext,Config,ServletInitParams,ServletAttribute当做Bean注册到BF中
     1     /**
     2      * Register request/session scopes, a {@link ServletContextAwareProcessor}, etc.
     3      * 1.设置一个BeanPostProcess为ServletContextAware的实现类注入servlet相关对象
     4      * 2.在BF中增加requetsScope等Scope
     5      * 3.把servletContext,Config,ServletInitParams,ServletAttribute当做Bean注册到BF中
     6      *
     7      */
     8     @Override
     9     protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    10         // 设置一个BeanPostProcess为ServletContextAware的实现类注入servlet相关对象
    11         beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
    12         beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    13         beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
    14 
    15         // 在BF中增加requetsScope等Scope
    16         WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
    17         // 把servletContext,Config,ServletInitParams,ServletAttribute当做Bean注册到BF中
    18         WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
    19     }

    invokeBeanFactoryPostProcessors方法

    初始化并调用配置的BeanFactoryPostProcessor..具体比较复杂.等后续更多学习以后再分享.

    registerBeanPostProcessors方法

    基本同invokeBeanFactoryPostProcessors方法,这是这里不会调用BeanPostProcess只是向BF里注册而已.具体比较复杂.等后续更多学习以后再分享.

  • 相关阅读:
    golang 使用 os/exec
    golang调用 exec命令 出现too many open files
    nginx: [error] invalid PID number “” in “/usr/local/var/run/nginx/nginx.pid”
    Docker 实时查看docker容器日志
    curl 查看HTTP 响应头信息
    go -- go 程序 启动docker容器
    go -- 测试
    Linux /var/log下各种日志文件
    LDAP -- ldap 的cn, ou, dc的含义
    一条命令 杀死某个端口 所有程序
  • 原文地址:https://www.cnblogs.com/abcwt112/p/7755066.html
Copyright © 2011-2022 走看看