zoukankan      html  css  js  c++  java
  • Spring ApplicationContext 简介

    ApplicationContext是对BeanFactory的扩展,实现BeanFactory的所有功能,并添加了事件传播,国际化,资源文件处理等。
     
    configure locations:(CONFIG_LOCATION_DELIMITERS = ",; " )分割多个配置文件。
     
    refresh()执行所有逻辑。
    @Override
    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) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                      "cancelling refresh attempt: " + ex);
            }
    
            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();
    
            // Reset 'active' flag.
            cancelRefresh(ex);
    
            // Propagate exception to caller.
            throw ex;
          }
    
          finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
          }
      }
    }

    prepareRefresh():准备需要刷新的资源。

    /**
    * Prepare this context for refreshing, setting its startup date and
    * active flag as well as performing any initialization of property sources.
    */
    protected void prepareRefresh() {
      this.startupDate = System.currentTimeMillis(); //启动日期
      this.closed.set(false); //激活标志
      this.active.set(true); //激活标志
    
      if (logger.isInfoEnabled()) {
          logger.info("Refreshing " + this);
      }
    
      // Initialize any placeholder property sources in the context environment
      initPropertySources(); //供扩展使用
    
      // Validate that all properties marked as required are resolvable
      // see ConfigurablePropertyResolver#setRequiredProperties
      getEnvironment().validateRequiredProperties(); 
    
      // Allow for the collection of early ApplicationEvents,
      // to be published once the multicaster is available...
      this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
    }
     
    initPropertySources()扩展使用如下:
    class MyACTX extends ClassPathXmlApplicationContext {
    
        @Override
        protected void initPropertySources() {
            super.initPropertySources();
            //TODO
        }
    }
    一般不直接实现ApplicationContext(过多接口),可以继承ClassPathXmlApplicationContext类,然后重写相应的方法。做相关操作。
     
    加载BeanFactory:ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(),(原有功能==配置读取,解析...)。
     
    prepareBeanFactory():
    /**
    * Configure the factory's standard context characteristics,
    * such as the context's ClassLoader and post-processors.
    * @param beanFactory the BeanFactory to configure
    */
    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
      // Tell the internal bean factory to use the context's class loader etc.
      beanFactory.setBeanClassLoader(getClassLoader());
      //表达式语言处理器,Spring3 SpEL表达式,#{xx.xx}支持。
      beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
      //属性编辑器支持 如处理Date注入
      beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
    
      // Configure the bean factory with context callbacks. 
      beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
      //忽略自动装配的接口
      beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
      beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
      beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
      beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
      beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    
      // BeanFactory interface not registered as resolvable type in a plain factory.
      // MessageSource registered (and found for autowiring) as a bean.
      //设置自动装配规则
      beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
      beanFactory.registerResolvableDependency(ResourceLoader.class, this);
      beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
      beanFactory.registerResolvableDependency(ApplicationContext.class, this);
    
      // Detect a LoadTimeWeaver and prepare for weaving, if found.
      //AspectJ支持
      if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
          beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
          // Set a temporary ClassLoader for type matching.
          beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
      }
    
      // Register default environment beans.
      if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
          beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
      }
      if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
          beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
      }
      if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
          beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
      }
    }

    SpEL:Spring Expression Language,运行时构造复杂表达式,存取对象图属性,对象方法调用等。SpEL为单独模块,只依赖于core模块。

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
          <property name="driverClassName" value="${dataSource.driverClassName}"/>
          <property name="url" value="${dataSource.url}"/>
          <property name="username" value="${dataSource.username}"/>
          <property name="password" value="${dataSource.password}"/>
          <property name="maxActive" value="${dataSource.maxActive}"/>
          <property name="minIdle" value="${dataSource.minIdle}" />
          <property name="initialSize" value="${dataSource.initialSize}"></property>
          <property name="validationQuery" value="${dataSource.validationQuery}"/>
    </bean>
    PropertyEditor:自定义属性编辑器。
    Spring中Date类型无法注入,需要注册相应的属性编辑器来做处理。Spring处理自定义属性编辑器类
    org.springframework.beans.factory.config.CustomEditorConfigurer
    /**
    * {@link BeanFactoryPostProcessor} implementation that allows for convenient
    * registration of custom {@link PropertyEditor property editors}.
    * 注册
    *
    */
    public class CustomEditorConfigurer implements BeanFactoryPostProcessor, Ordered {
    
      protected final Log logger = LogFactory.getLog(getClass());
    
      private int order = Ordered.LOWEST_PRECEDENCE;  // default: same as non-Ordered
    
      private PropertyEditorRegistrar[] propertyEditorRegistrars;
    
      private Map<Class<?>, Class<? extends PropertyEditor>> customEditors;
    
      ... ...
    通过注册propertyEditorRegistrars或者customEditors。
     
    customEditors(推荐):
    自定义Date属性编辑器MyDateEditor:
    
    class MyDateEditor extends PropertyEditorSupport {
    
        private String format = "yyyy-MM-dd";
    
        public void setFormat(String format){
            this.format = format;
        }
    
        @Override
        public void setAsText(String text) throws IllegalArgumentException {
            SimpleDateFormat sp = new SimpleDateFormat(format);
            try{
                this.setValue(sp.parse(text));
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
    }
    
    配置:
    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
      <property name="customEditors">
        <map>
          <entry key="java.util.Date">
            <bean class="com.xxx.MyDateEditor">
              <property name="format" value="yyyy-MM-dd HH:mm:ss"/>
            </bean>
          </entry>
        </map>
      </property>
    </bean>

    propertyEditorRegistrars:

    自定义Date EditorRegister:
    
    class MyDateRegister implements PropertyEditorRegistrar{
        private String format = "yyyy-MM-dd";
    
        public void setFormat(String format){
            this.format = format;
        }
    
        @Override
        public void registerCustomEditors(PropertyEditorRegistry registry) {
            registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat(format), true));
        }
    }
    
    配置:
    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
      <property name="propertyEditorRegistrars">
        <list>
          <bean class="com.xxx.MyDateRegister">
            <property name="format" value="yyyy-MM-dd HH:mm:ss"/>
          </bean>
        </list>
      </property>
    </bean>
    属性编辑器应用于Bean实例化属性填充阶段。
     
    invokeBeanFactoryPostProcessors():容器级别的bean后置处理。
     
    典型应用:PropertyPlaceholderConfigure。
     
    PlaceholderConfigurerSupport extends PropertyResourceConfigurer .. implements BeanFactoryPostProcessor,间接实现BeanFactoryPostProcessor,会在BeanFacty载入bean配置之后进行属性文件的处理 :mergeProperties、convertProperties、processProperties,供后续bean的实例化使用。
     
    可以注册自定义的BeanFactoryPostProcessor。
     
    initMessageSource():初始化消息资源,国际化应用。
     
    两个message资源文件message_en.properties, message_zh_CN.properties。
    添加Spring配置:messageSource id固定。
    <!-- 国际化资源文件 -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames">
            <value>lang/message</value>
        </property>
    </bean>

    读取:

    ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/lang-resource.xml");
    String msg = ctx.getMessage("xxx", null, Locale.CHINA);
    System.out.println(msg);

    nitApplicationEventMulticaster():

    /**
    * Add beans that implement ApplicationListener as listeners.
    * Doesn't affect other listeners, which can be added without being beans.
    */
    protected void registerListeners() {
      // Register statically specified listeners first.
      for (ApplicationListener<?> listener : getApplicationListeners()) {
          getApplicationEventMulticaster().addApplicationListener(listener);
      }
    
      // Do not initialize FactoryBeans here: We need to leave all regular beans
      // uninitialized to let post-processors apply to them!
      String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
      for (String listenerBeanName : listenerBeanNames) {
          getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
      }
    
      // Publish early application events now that we finally have a multicaster...
      Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
      this.earlyApplicationEvents = null;
      if (earlyEventsToProcess != null) {
          for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
          }
      }
    }

    ... ...

  • 相关阅读:
    spring 配置多个properties
    redis 一些使用过的命令
    ftpclient 遇到的一些问题
    tomcat+nginx 横向扩展
    easyui 刷新页面
    tomcat 发布本地文件
    java httpclient 跳过证书验证
    https增加临时证书,tomcat配置
    echarts getAttribute”的值: 对象为 null 或未定义 错误解决方法,
    数据的导入导出
  • 原文地址:https://www.cnblogs.com/niejunlei/p/6054713.html
Copyright © 2011-2022 走看看