SpringFramework的核心:IOC容器的实现------ApplicationContext的特点以及Bean的Resource定位

版权声明: https://blog.csdn.net/qq1641530151/article/details/82384585

上次我解释了关于BeanFactory的一些功能。那么以BeanFactory的一个实现类为例,我们来看一下BeanFactory的工作原理。

private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
		this(resource, null);
	}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource);
	}

这是关于XmlBeanFactory的构造方法,从这里我们可以看到,我们需要自己定义Resource资源来创建这样一个IOC容器。总体而言这样的构造方法我们可以用编程的方式来声明出来

                ClassPathResource res = new ClassPathResource("beam.xml");
		DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
		XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
		reader.loadBeanDefinitions(res);

在使用IOC容器之前我们需要以下几个步骤

   1.创建IOC容器配置文件的抽象资源,这个抽象资源包括了BeanDefinition的定义信息

   2.创建一个BeanFactory,这里使用的是DefaultListableBeanFactory

   3.创建一个BeanDefinition的读取器,并设置入参factory(对应的DefaultListableBeanFactory)表示读取到的bean都要最终注册到这个factory中

   4..这个时候使用读取器来读取我们的resource资源并最终将resource注册到factory

接下来来说一下关于ApplicationContext的特点

   

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver

我们可以看到实际上ApplicationContext也是继承了BeanFactory的一些实现类,因此我们可以认为ApplicationContext也是一个BeanFactory,但是它有一些自己的特点。

     1.支持不同的信息源。

     2.访问资源,体现在对ResourceLoader和Resource的支持上,这样我们可以从不同地方法得到Bean资源。

     3.支持应用事件。继承了接口ApplicationEventPublisher,这样在上下文中引入了事件机制。

     4.在ApplicationContext中提供的附加服务。这些服务使得基本IOC容器的功能更丰富。

接下来我们来看一下关于IOC容器的初始化

   IOC容器的初始化包括BeanDefinition的Resource定位,载入和注册三个基本过程。现在我主要来讲一下关于BeanDefinition的Resource定位过程。

   我们以org.springframework.context.support.FileSystemXmlApplicationContext为例

首先来看这个类的继承关系图

首先我们来看这个类的构造方法

    

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {

		super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
	}

这个方法如果有父类容器,我们设置加载父类的容器,调用父类的有参构造方法。

之后setConfigLocations(configLocations);设置我们的xml文件的地址,这个方法是在一个配置加载类中

org.springframework.context.support.AbstractRefreshableConfigApplicationContext.setConfigLocations(String...)。调用的是父类的方法。之后它要进行容器的更新调用的方法是

org.springframework.context.support.AbstractApplicationContext.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) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

这个方法实现了BeanDefinition的Resource定位,载入和注册。首先来看关于Resource的定位,在

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

代码中的obtainFreshFactory()方法中,我们可以看到refreshBeanFactory()方法,但是这个方法是一个抽象方法,需要它的子类来实现,这个方法实现是在

org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory()中进行实现

在这个方法中,有这样的一行代码,将BeanDefinition加载到factory中

loadBeanDefinitions(beanFactory);

由于这个方法是一个抽象方法,我们来看这个AbstractRefreshableApplicationContext的子类

org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(DefaultListableBeanFactory)对方法的具体的实现

  

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

我们可以看到这个方法里面有两行代码和我们前面的编程式初始化IOC容器很相近

XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
loadBeanDefinitions(beanDefinitionReader);

这个地方是使用读取器来读取beanDefinition,但是BeanDefinition的读取方式有两种,一种是根据configLocations读取,另一种是根据resources进行读取,对于FileSystemXmlApplicationContext类来说,很显然由于构造方法里面的

setConfigLocations(configLocations);

这样一条语句,所以是根据configLocations,也就是路径获取xml文件来构造beanfinition。

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

之后我们再回到最开始的配置加载类中查找我们之前配置好的configLocations

org.springframework.context.support.AbstractRefreshableConfigApplicationContext.getConfigLocations()

protected String[] getConfigLocations() {
		return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
	}

这就是关于BeanDefinition的Resource资源定位,关于载入和注册我将会在之后的阅读学习中继续谈到。

猜你喜欢

转载自blog.csdn.net/qq1641530151/article/details/82384585