BeanFactory与ApplicationContext对事务等的支持的不同

     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

相关文章:

作者: flym

I am flym,the master of the site:)

《BeanFactory与ApplicationContext对事务等的支持的不同》有一个想法

  1. 非常的有帮助,谢谢了,看来还是太表象了
    “不会写C++的JAVA人员不是一个好UI
    不会用Linux的程序员不是一个好DBA” 赞一个

发表评论

邮箱地址不会被公开。 必填项已用*标注