beanFactory与ApplicationContext在具体使用时,它们在使用以及对j2ee开发上,支持是不一样的。具体就表现在spring对两者的具体实现上。
前几天一个同事给我如下一段代码(大致如下):
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("classpath:applicationContext.xml")); BaseDomain b = new BaseDomain(); b.save();
其中,事务配置在b.save()上面(这个是已经确定了的,事务是正确的)。然而,在胡乱改了之后,这段代码又运行正确了。经仔细分析,代码修改成如下这样了:
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); BaseDomain b = new BaseDomain(); b.save();
就是将实例化容器的类由BeanFactory换成了ApplicationContext,但两个实现类一个支持事务而另一个不支持事务,经网上查找。找到一篇说明:
http://www.javaeye.com/problems/50602
其中列出一个表格说明两个的不同点:
特性 | BeanFactory | ApplicationContext |
Bean实例化/装配 | Yes | Yes |
自动BeanPostProcessor注册 | No | Yes |
自动BeanFactoryPostProcessor注册 | No | Yes |
便捷的MessageSource访问(i18n) | No | Yes |
ApplicaionEvent发送 | No | Yes |
其中,在spring的官方手册中(http://static.springsource.org/spring/docs/2.5.x/reference/beans.html),在这么一句话:
BeanFactoryor ApplicationContext? Users are sometimes unsure whether a BeanFactoryor an ApplicationContextis best suited for use in a particular situation. A BeanFactorypretty much just instantiates and configures beans. An ApplicationContextalso does that, and it provides the supporting infrastructure to enable lots of enterprise-specific features such as transactions and AOP. |
即是说,ApplicationContext除是提供BeanFactory已经提供的实例化和装配bean的功能之外,还提供了许多进行javaee开发的功能,比如aop和事务等。
当然,这也只是文档上这么说的,那到底为什么是这样的。我觉得还是应该从源码出手,去寻找相应的区别(源码能表示所有的文档,我们不能因为文档上这么说就相信它,当然没有源码另当别论)
以下源代码基于spring3.0.3版本。
首先是BeanFactory,我们看XmlBeanFactory的源代码,即new方法。
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { super(parentBeanFactory);//设置父类factory this.reader.loadBeanDefinitions(resource);//重要的加载bean定义 }
经过对loadBeanDefinitions方法的追踪,我们最终会看到spring如何来加载bean定义的xml文件。最终会走到DefaultBeanDefinitionDocumentReader类的parseBeanDefinitions方法,该方法会处理最终的bean定义以及自定义bean。
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { ...... parseDefaultElement(ele, delegate);//处理几个结点 ...... delegate.parseCustomElement(ele);//其它结节 }
在parseDefaultElement这个方法中,spring只处理了import,alias以及bean的结点,其它结点却并未处理,以及在创建documentHandler的时候,也没有处理相应的命名空间,所以并没有处理对于事务等信息的加载以及对aop的支持等。
接下来,我们来看ClasspathXmlApplicationContext:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
重点在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. //取得内部的beanFactory,即运用处理beanFactory的手法,已经简单地初始化了一个beanFactory起来了,其中会调用以先前已经说明的loadDocumentDefinition方法,调用堆栈为:obtainFreshBeanFactory->refreshBeanFactory(方法内部调用AbstractRefreshableApplicationContext类) ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. //设置一些特殊的BeanPostProcessor以及一些依赖设置 prepareBeanFactory(beanFactory); // Allows post-processing of the bean factory in context subclasses. //提供给其它的子类扩展点 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. //调用BeanFactoryPostProcessor以完成一些特殊对于beanFactory的设置 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. //将beanFactory中的所有BeanPostProcessor读取出来,以在进行bean初始化时使用 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. //初始化所有的单态bean finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. //分发application事件,以通知关注事件的类进行处理 finishRefresh(); } }
其实通过,这个方法中调用的各个方法上简单的注释,大家已经可以看到applicaionContext做了比beanFactory更多的工作,这其中就包括beanFactoryPostProcessor以及beanPostProcessor的支持。我们平时所说的事务支持(通常是使用aop实现),就是通过beanPostProcessor来实现的(具体如何实现,可以参照beanPostProcessor的一个实现类AbstractAutoProxyCreator)。
以上就是一个对beanFactory和ApplicationContext的简单区别的分析,其实只要打开源码,一切都明白了。只是刚碰到这个问题时,还真不知道是由于beanFactory和ApplicationContext两者在实现上的不同,导致了代码执行的不同。对于spring的了解还只是停留在文档以及手册上面,如果想要真正的了解spring,对照着文档,认真地从源码上理解一下,恐怕就会更加深刻了。
转载请标明出处:i flym
本文地址:https://www.iflym.com/index.php/code/beanfactory-applicationcontext-defference-between-transaction.html
非常的有帮助,谢谢了,看来还是太表象了
“不会写C++的JAVA人员不是一个好UI
不会用Linux的程序员不是一个好DBA” 赞一个