(Spring源码解析)一步一步分析,springMVC项目启动过程(二)

 2019-11-02 21:06  阅读(1079)
文章分类:Spring boot

这篇来看下AbstractApplicationContext中的**refresh()**方法,这个方法初始化且启动整个spring容器的核心。方法名字理解起来就是刷新的意思,意味着刷新整个Spring容器,做好一切准备。 ``` public void refresh() throws BeansException, IllegalStateException { //初始化容器需要加锁,防止并发加载,startupShutdownMonitor锁对象 synchronized (this.startupShutdownMonitor) { // 预加载刷新,里面包含初始化准备工作 prepareRefresh(); // 创建bean工厂,加载初始化beanDefinitionMap、依赖关系、注入属性等等对象,注入对象解析的实现在里面 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 准备beanFactory绑定到context容器 prepareBeanFactory(beanFactory); try { // 允许在context子类中对bean工厂进行后处理 postProcessBeanFactory(beanFactory); // 实例化并调用所有已注册的beanfactorypostprocessor bean对象 invokeBeanFactoryPostProcessors(beanFactory); // 注册拦截bean创建的bean处理器. registerBeanPostProcessors(beanFactory); // 初始化国际化消息资源 initMessageSource(); // 初始化应用事件广播器,用来触发事件监听 initApplicationEventMulticaster(); // 初始化context子类的特殊bean对象 onRefresh(); // 注册监听器和事件类型,就是把所有对应的监听器和事件类型保存到应用容器里 registerListeners(); // 实例化所有剩下的(非惰性初始化)单例. finishBeanFactoryInitialization(beanFactory); // 最后一步:发布刷新完毕相应的事件ContextRefreshedEvent finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // 出现刷新异常,则销毁已经创建的单例以避免占用资源。 destroyBeans(); // 重置激活标志 cancelRefresh(ex); // 抛出异常 throw ex; } finally { // 清楚部分加载解析用到的beanmeta缓存,因为我们已经在spring核心容器里重置了常见的内部缓存 可能不再需要单身bean的元数据了 resetCommonCaches(); } } } ``` 咋一看这个方法的代码很少,其实里面调用很多层框架所需要的实现,(初略总结)大概做了如下事情: 加载PropertySources、环境参数、初始化并构建BeanFactory、解析注册XmlBeanDefinition,初始化创建装载bean、解析Bean之间的依赖关系、国际化消息初始化、初始化监听事件广播、注册所有监听器、事件发布通知结束等。 预加载方法: ``` protected void prepareRefresh() { this.startupDate = System.currentTimeMillis();//记录启动时间 this.closed.set(false);//容器没有关闭标识 this.active.set(true);//容器启动激活标识 if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // 初始化加载系统上下文环境属性参数资源,在ContextLoader可能已加载 initPropertySources(); // 校验所有的设置Required的Properties,在ConfigurablePropertyResolver#setRequiredProperties设置 getEnvironment().validateRequiredProperties(); // 初始化容器早期事件Set集合 this.earlyApplicationEvents = new LinkedHashSet(); } ``` 本章重点分析BeanFactory初始化过程: ### ### ### ### 1. 预准备 初始化环境property sources 2. 初始化BeanFactory,解析xml注册配置和bean对象 3. 创建并刷新BeanFactory,解析注册Bean ``` AbstractRefreshableApplicationContext#refreshBeanFactory方法实现 protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory();//创建BeanFactory对象 beanFactory.setSerializationId(getId());//序列化id customizeBeanFactory(beanFactory);// loadBeanDefinitions(beanFactory);//加载资源解析BeanDefinition synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } } ``` 可以看到refreshBeanFactory中的方法loadBeanDefinitions加载资源并去解析xml,然后创建BeanDefinition等操作 XmlWebApplicationContext的具体实现loadBeanDefinitions方法,第一个参数location就是web.xml配置的configLocations路径,第二参数actualResources的资源Set ``` public int loadBeanDefinitions(String location, Set actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } } else { // Can only load single resources by absolute URL. Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } } ``` ------- 来源:[http://ddrv.cn](http://ddrv.cn)

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> (Spring源码解析)一步一步分析,springMVC项目启动过程(二)

相关推荐