浏览 3735 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2012-07-12
先看一下这里的refresh()方法 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. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } } } 首先这个方法是同步的,以避免重复刷新。然后刷新的每个步骤,都放在单独的方法里,比较清晰,可以按顺序一个个看 首先是prepareRefresh()方法 protected void prepareRefresh() { this.startupDate = System.currentTimeMillis(); synchronized (this.activeMonitor) { this.active = 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 this.environment.validateRequiredProperties(); } 这个方法里做的事情不多,记录了开始时间,输出日志,另外initPropertySources()方法和validateRequiredProperties()方法一般都没有做什么事 然后是核心的obtainFreshBeanFactory()方法,这个方法是初始化BeanFactory,是整个refresh()方法的核心,其中完成了配置文件的加载、解析、注册,后面会专门详细说 这里要说明一下,ApplicationContext实现了BeanFactory接口,并实现了ResourceLoader、MessageSource等接口,可以认为是增强的BeanFactory。但是ApplicationContext并不自己重复实现BeanFactory定义的方法,而是委托给DefaultListableBeanFactory来实现。这种设计思路也是值得学习的 后面的prepareBeanFactory()、postProcessBeanFactory()、invokeBeanFactoryPostProcessors()、registerBeanPostProcessors()、initMessageSource()、initApplicationEventMulticaster()、onRefresh()、registerListeners()、finishBeanFactoryInitialization()、finishRefresh()等方法,是添加一些后处理器、广播、拦截器等,就不一个个细说了。 其中的关键方法是finishBeanFactoryInitialization(),在这个方法中,会对刚才注册的Bean(不延迟加载的),进行实例化,所以也是一个核心方法 从整体上介绍完了流程,接下来就重点看obtainFreshBeanFactory()方法,上文说到,在这个方法里,完成了配置文件的加载、解析、注册 protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; } 这个方法做了2件事,首先通过refreshBeanFactory()方法,创建了DefaultListableBeanFactory的实例,并进行初始化。然后返回 protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } } 首先如果已经有BeanFactory实例,就先清空。 然后通过createBeanFactory()方法,创建一个DefaultListableBeanFactory的实例 protected DefaultListableBeanFactory createBeanFactory() { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); } 接下来设置ID唯一标识 beanFactory.setSerializationId(getId()); 然后允许用户进行一些自定义的配置 protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { if (this.allowBeanDefinitionOverriding != null) { beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.allowCircularReferences != null) { beanFactory.setAllowCircularReferences(this.allowCircularReferences); } beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver()); } 最后,就是核心的loadBeanDefinitions()方法 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } 这里首先会创建一个XmlBeanDefinitionReader的实例,然后进行初始化 // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); 这里要说明一下,ApplicationContext并不自己负责配置文件的加载、解析、注册,而是将这些工作委托给XmlBeanDefinitionReader来做。 loadBeanDefinitions(beanDefinitionReader); 这行代码,就是Bean定义读取实际发生的地方。这里的工作,主要是XmlBeanDefinitionReader来完成的,下一篇博客会详细介绍这个过程 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2012-07-17
最后修改:2012-07-17
请教LZ个问题, 调用refresh方法之后以前实例化好的对象还在吗?
如果不在,那个我想通过XmlWebApplicationContext将新的xml中的bean,动态的往ioc容器里添加对象怎么做而不刷掉以前已经实例化好的bean? |
|
返回顶楼 | |
发表时间:2012-07-17
refresh方法会将以前已经实例化好的对象刷掉吗?
|
|
返回顶楼 | |
发表时间:2012-07-17
会
在obtainFreshBeanFactory()方法里,如果已经存在BeanFactory的实例,则会将其销毁 |
|
返回顶楼 | |
发表时间:2012-07-17
kyfxbl 写道 会
在obtainFreshBeanFactory()方法里,如果已经存在BeanFactory的实例,则会将其销毁 这样的问题就出现了,我只想往ioc容器里批量添加些新的bean,但是不想丢掉以前实例化好的bean, 请问应该怎么做? 我不想通过regedit一个一个注册,要根据xml或者注解批量的添加 |
|
返回顶楼 | |
发表时间:2012-07-18
你这个需求有点特殊
实际上,虽然会销毁掉已有的bean,但是稍后也会连同你新添加的bean一起,重新创建出来,所以是不需要用户额外做什么的 你不想丢掉已经实例化好的bean,我不太明白是为什么? |
|
返回顶楼 | |
发表时间:2012-07-20
kyfxbl 写道 你这个需求有点特殊
实际上,虽然会销毁掉已有的bean,但是稍后也会连同你新添加的bean一起,重新创建出来,所以是不需要用户额外做什么的 你不想丢掉已经实例化好的bean,我不太明白是为什么? 在做一个简单的平台,平台在启动时会加载一些bean 支持加载别人的jar包,jar包里有的类有注解,然后平台会把需要注入到ioc里的类的包名配置给我, 平台会帮他把所有带注解类全部加载到平台的ioc容器里,供他调用。 平台同时也可以对他人jar中的bean进行调用 所以需要动态的能给ioc容器中添加新的bean而不影响以前ioc容器中的bean。 |
|
返回顶楼 | |
发表时间:2012-07-20
我明白啊,那也不影响啊,整个刷新以后,你以前IOC容器中的bean,也又刷出来了啊
除非你ioc容器中的bean是有状态的? 那有一个解决方案,你可以自己写BeanPostProcessor,在初始化bean之后,还原bean的状态 |
|
返回顶楼 | |