Spring3.2 IoC 分析

Spring3.2 IoC个人分析:

  • Ioc乃Spring核心的核心,后面每个组件都会用到没办法,只得从这里开工,Let's go.

  • 说起Ioc(Inverse of Control), 即控制反转,依赖注入DI(Dependency Inject)就是其实现之一,就是建议我们通过push方式组装我们的组件;

  • 要说IoC还得从容器说起,这个容器就是来装我们需要Spring来管理的组件,不然怎么来管理那么多大大小小的组件呢,总得有个管家吧,那么这个管家怎么在Spring中体现得呢?那就从老祖宗BeanFactory开始讲起:

    Spring3.2 IoC 分析

     可见,有这么几个比较简单实用的东西,Spring中各种组件基本都会已叫做Bean的实体来描述,体现为类就是BeanDefinition, 上面这些方法,基本都是获取bean实例为主,很显然就是当我们需要bean时,可以通过这些方法来达到目的,详述可见spring源码,稍微注意这里有一个唯一的属性FACTORY_BEAN_PREFIX=“&”这里有一种叫FactoryBean的Bean, 它也是一种bean, 不过它可以产生其他bean,所以为了区分普通bean和工厂bean,我们对这种工厂bean会在前面加“&”这么个前缀,Spring源码这样解释到:

if the bean named myJndiObject is a FactoryBean, getting &myJndiObject will return the factory, not the instance returned by the factory

相当清晰。

  • BeanFactory只是一个接口,那么其实现怎么样,我们一看便知:     

    Spring3.2 IoC 分析

   靠,这么多,是不是有一种想吐血的感觉,我也想,整这么干嘛,让我怎么看,坑爹阿,没办法,只有拣着看,搞明白一条路,其他路也异曲同工,我们还是先拣ClassPathXmlApplicationContext这条路来开吧,可能要熟悉点。

  • 第一个下来的接口是HierarchicalBeanFactory,它并没做什么太多,就扩展了两个方法:     

	BeanFactory getParentBeanFactory();
	boolean containsLocalBean(String name);public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext, DisposableBean {}

    所以spring容器是有层级关系的,不是一杆子包干,containsLocalBean则和containsBean作用一样,判断当前容器中是否有某bean。

  • 第二个接口是ApplicationContext这个接口,它就比较多的特性了,请看:

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,MessageSource, ApplicationEventPublisher, ResourcePatternResolver {  ... }

那么ApplicationContext继承的这些接口干什么呢?Spring这样描述ApplicationContext:

An ApplicationContext provides:Bean factory methods for accessing application components. Inherited from org.springframework.beans.factory.ListableBeanFactory.The ability to load file resources in a generic fashion. Inherited from the org.springframework.core.io.ResourceLoader interface.The ability to publish events to registered listeners. Inherited from the ApplicationEventPublisher interface.The ability to resolve messages, supporting internationalization. Inherited from the MessageSource interface.Inheritance from a parent context. Definitions in a descendant context will always take priority. This means, for example, that a single parentcontext can be used by an entire web application, while each servlet has its own child context that is independent of that of any other servlet
  • EnvironmentCapable: 使我们可以与ApplicationContext进行交互,比如一些配置文件或者配置属性等;

  • ListableBeanFactory: 使ApplicationContext能够访问管理的bean集合,而不是像BeanFactory那样只能每次通过getBean()获取一个Bean;

  • MessageSource: 支持国际化功能,实现主要是ResourceBundleMessageSource和ReloadableResrouceBundleMessageSource;

  • ApplicationEventPublisher: 发布ApplicationEvent事件的功能;

  • ResourcePatternResolver: 具备资源加载能力, 比如加载我们xml配置文件

继续往下走,ConfigurableApplicationContext, 提供了配置ApplicationContext和ApplicationContext生命周期管理功能:

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {}

继续AbstractApplicationContext, 这里通过DefaultResourceLoader实现了资源加载功能,

DisposableBean接口扩展了一个资源销毁的功能destroy(), 以便ApplicationContext销毁时释放资源,如一些缓存的单例Bean:

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext, DisposableBean {}

那么AbstractApplicationContext自己做了些什么呢?说重点:(有个refresh模版方法很重要, 它定义了加载我们资源的过程):

public void refresh() throws BeansException, IllegalStateException {
	prepareRefresh();// 主要设置一些属性,如启动时间,激活状态,Environment对象的创建,初始化属性源,及必须属性的检查;
	ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //让子类也初始化自己内部的BeanFactory
	prepareBeanFactory(beanFactory); //配置beanFactory的标准上下文,如ClassLoader,后处理器,注册一些默认的环境所需的Bean
        postProcessBeanFactory(beanFactory); //允许ApplicationContext内部的BeanFactory可以注册BeanFactoryPostProcesser
	invokeBeanFactoryPostProcessors(beanFactory); //调用注册的BeanFactoryPostProcessors
	registerBeanPostProcessors(beanFactory); //注册BeanPostProcesses
        initMessageSource(); //初始化MessageSource对象
        initApplicationEventMulticaster(); //初始化事件广播器
        onRefresh(); //给子类重写的一个模版方法,可做一些特定的初始化工作
	registerListeners(); //注册ApplicationLister
	finishBeanFactoryInitialization(beanFactory); //初始化所有单例bean(非懒加载)
	finishRefresh(); // 初始化LifecycleProcesser, 并发布事件
}

几句话是说不清的,先继续往下走吧,AbstractRefreshableApplicationContext, 它支持多次调用上面我们讲的refresh()方法,每次调用refresh()方法会创建一个新的beanfactory,并且创建默认的BeanFactory的实现DefaultListableBeanFactory:

protected DefaultListableBeanFactory createBeanFactory() {
		return new DefaultListableBeanFactory(getInternalParentBeanFactory());
	}

再往下走, AbstractRefreshableConfigApplicationContext(主要扩展了一些处理配置文件的功能),实现了两个接口BeanNameAware(可以知道beanfactory中的beanname),InitializingBean则可以用来指定Bean的init-method属性配置:

public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext
		implements BeanNameAware, InitializingBean {
}

继续前进,AbstractXmlApplicationContext,算得上是AbstractApplicationContext的基础实现,其还实现了一个真正开始加载xml中的bean定义的方法,具体加载bean,交给了XmlBeanDefinitionReader去完成:

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);
	}

终于到了,到了,ClassPathXmlApplicationContext,我们平时能碰到可能就是它了,这个类基本就成了一站式服务,我就配置下xml文件位置就足够了,终于走完这条路了,顺着走了一遍,还得逆水行舟一番。

逆行而上:

ClassPathXmlApplicationContext context = 
				new ClassPathXmlApplicationContext("configs/beans.xml");
就简单一句,Spring已经为我们做了太多, 最终会落到构造方法:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {
	super(parent);
	setConfigLocations(configLocations);
	if (refresh) {
		refresh();
	}
}

super(parent)初始化父级上下文, 最终到了AbstractApplicationContext, 但parent始终null, getResourcePatternResolver()构造一个默认的资源路径解析器

PathMatchingResourcePatternResolver,用来解析我们的xml文件路径,支持ant风格

public AbstractApplicationContext(ApplicationContext parent) {
	this.parent = parent;
	this.resourcePatternResolver = getResourcePatternResolver();
}
接下来设置xml配置文件, 会调用AbstractRefreshableConfigApplicationContext的 resolvePath(), 这个方法首先是将System.getProperties()和System.getEnv()拿来自己存放着,
setConfigLocations(configLocations);

完成配置文件等解析后,就正式进入前面提到的很重要refresh()模版方法,记得还在AbstractApplicationContext吧,可以自己去研究每步:

重点讲下这步obtainFreshBeanFactory(), 该方法最终会调用到AbstractRefreshableApplicationContext的refreshBeanFactory()方法,该方法就创建了ApplicationContext的内部BeanFactory了, 并加载了xml中定义的bean:

DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
	this.beanFactory = beanFactory;
}

createBeanFactory()创建了DefaultListableBeanFactory的实例,最重要还是loadBeanDefinitions(), 告诉我们spring怎么来加载我们xml中的bean定义的,这里就用我们传的构造参数开始用XmlBeanDefinitionReader对象进行读取了:

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
	Resource[] configResources = getConfigResources();
	if (configResources != null) {
		reader.loadBeanDefinitions(configResources);
	}
	String[] configLocations = getConfigLocations();
	if (configLocations != null) {
		reader.loadBeanDefinitions(configLocations);
	}
}

XmlBeanDefinitionReader是怎么进行读取的呢,后来落到其doLoadBeanDefinitions()上,这时已经构建xml Document对象了:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
    try {
	int validationMode = getValidationModeForResource(resource);
	Document doc = this.documentLoader.loadDocument(
				inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
	return registerBeanDefinitions(doc, resource);
}

往下看registerBeanDefinitions(), 真正读取xml文件的使BeanDefinitionDocumentReader, 其默认实现DefaultBeanDefinitionDocumentReader,它会通过spring-beans的DTD文档去读取xml,

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
	documentReader.setEnvironment(this.getEnvironment());
	int countBefore = getRegistry().getBeanDefinitionCount();
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
	return getRegistry().getBeanDefinitionCount() - countBefore;
}
那我们再看看 DefaultBeanDefinitionDocumentReader怎么registerBeanDefinitions(), 又交由doRegisterBeanDefinitions():
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
	this.readerContext = readerContext;
	logger.debug("Loading bean definitions");
	Element root = doc.getDocumentElement();
	doRegisterBeanDefinitions(root);
}

doRegisterBeanDefinitions(), 可以在真正解析xml前后,子类定制一些xml元素什么的,

preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
parseBeanDefinition(), 会根据上面是否预处理XML来解析元素

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
	if (delegate.isDefaultNamespace(root)) {
		NodeList nl = root.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (node instanceof Element) {
				Element ele = (Element) node;
				if (delegate.isDefaultNamespace(ele)) {
					parseDefaultElement(ele, delegate);
				}
				else {
					delegate.parseCustomElement(ele);
				}
			}
		}
	}
	else {
		delegate.parseCustomElement(root);
	}
}
看看parseDefaultElement(), 其会解析alias, import, bean, beans元素:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
	if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
		importBeanDefinitionResource(ele);
	}
	else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
		processAliasRegistration(ele);
	}
	else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
		processBeanDefinition(ele, delegate);
	}
	else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
		// recurse
		doRegisterBeanDefinitions(ele);
	}
}

直接看最单纯的bean的解析, processBeanDefinition():

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); //解析Bean元素
	if (bdHolder != null) {
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); //解析我们自己定制的Bean属性
		try {
			// Register the final decorated instance.
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to register bean definition with name '" +
					bdHolder.getBeanName() + "'", ele, ex);
		}
		// Send registration event.
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

这上面refresh()方法通过obtainFreshBeanFactory创建ApplicationContext内部BeanFactory过程粗略就这样了。

记住这里ApplicationContext默认的BeanFactory实现为DefaultListableBeanFactory, 里面就保存了我们的xml定义的bean对应的实体BeanDefinition,由map属性beanDefinitionMap来保存, 具体可以自己慢慢研究。

收工。

你可能感兴趣的:(spring,IOC)