Spring源码解析一:Spring IOC容器的设计

1,IOC接口的设计

在这里插入图片描述
这里的接口设计有两条主线:BeanFactory和ApplicationContext

1、BeanFactory–>HierarchicalBeanFactory–>ConfigurableBeanFactory:这是BeanFactory的设计路线,BeanFactory定义了基本的IOC容器规范,HierarchicalBeanFactory中增加了getParentBeanFactory方法,具备了双亲IOC容器的管理功能;ConfigurableBeanFactory中新增一些配置功能。

2、ApplicationContext应用上下文接口:继承了HierarchicalBeanFactory、ListableBeanFactory等BeanFactory的子接口,这条分支使得ApplicationContext具备了IOC容器的基本功能;在继承MessageSource、ApplicationEventPublisher等接口的时候,使得ApplicationContext这个简单的IOC容器添加了许多高级容器的特性。ApplicationContext的子接口有ConfigurableApplicationContext以及在WEB环境下使用的WebApplicationContext。

2,BeanFactory接口的设计

public interface BeanFactory {

	/**
	 * Used to dereference a {@link FactoryBean} instance and distinguish it from
	 * beans <i>created</i> by the FactoryBean. For example, if the bean named
	 * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
	 * will return the factory, not the instance returned by the factory.
	 */
	String FACTORY_BEAN_PREFIX = "&";

	Object getBean(String name) throws BeansException;

	<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;

	Object getBean(String name, Object... args) throws BeansException;

	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	boolean containsBean(String name);

	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	String[] getAliases(String name);

}

  1. 用户使用容器的时候,可使用“&”来得到FactoryBean本身,用来区分FactoryBean产生的对象和FactoryBean本身。举例来说userObject是一个FactoryBean,那么&userObject得到的是FactoryBean ,而不是得到userObject这个FactoryBean所产生的对象
  2. BeanFactory接口设计了getBean()这个方法,这个方法是IOC容器api的方法,通过这个方法可以取得IOC容器中管理的Bean,bean的取得是通过指向名字来索引的。
  3. 通过接口方法containsBean让用户能够判断容器中是否含有指定名字的bean。
  4. 通过接口方法isSingleton可以让用户查询指定名字的bean是否是singleton属性 的bean,对于singleton属性,用户可在BeanDefinition中去指定。
  5. 通过接口方法isPrototype可以让用户查询指定名字的bean是否是prototype属性 的bean,对于prototype属性,用户可在BeanDefinition中去指定。
  6. 通过接口方法isTypeMatch,查询指定名字的bean的Class类型是否是特定的Class类型
  7. 通过接口方法getType查询指定名字bean的Class类型
  8. 通过接口方法getAliases查询指定名字bean所以的别名,别名是在BeanDefinition中定义的

3,XmlBeanFactory的解读

在这里插入图片描述
XmlBeanFactory是IOC容器系列最底层的实现,它继承自DefaultListableBeanFactory这个类。而后者是Spring中非常重要的一个类,它是Spring容器中一个基本产品,可以把它当做一个默认的功能完整的IOC容器来使用。

XmlBeanFactory除了从DefaultListableBeanFactory继承到IOC容器基本功能之外,还新增了一些其他功能,从名称就可以猜测出来,它是一个可以读取以XML文件方式定义BeanDefinition的容器。

XmlBeanFactory源码如下:

public class XmlBeanFactory extends DefaultListableBeanFactory
{
  private final XmlBeanDefinitionReader reader;

  public XmlBeanFactory(Resource resource)
    throws BeansException
  {
    this(resource, null);
  }

  public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory)
    throws BeansException
  {
    super(parentBeanFactory);

    this.reader = new XmlBeanDefinitionReader(this);

    this.reader.loadBeanDefinitions(resource);
  }
}

实际上,实现XML读取功能并不是直接由XmlBeanFactory来完成的。而是由XmlBeanFactory内部定义的XmlBeanDefinitionReader来进行处理的。在构造XmlBeanFactory容器的时候,需要给出BeanDefinition的信息来源,而这个信息来源需要封装成Spring中的Resource类的形式给出。

来看下一个基本的IOC容器的初始化过程:

1、创建IOC配置文件的抽象资源,也就是源码中的Resource,这个Resource中包含了BeanDefinition的定义信息。

2、通过构造函数创建一个BeanFactory。

3、创建一个载入BeanDefinition的读取器,即源码中的reader。这里使用XmlBeanDefinitionReader来载入XML文件形式的BeanDefinition。

4、调用reader的loadBeanDefinitions方法,来完成从Resource中载入BeanDefinition信息,从而完成IOC容器的初始化。

我们可以将上面的源码做简化,使用编程式的方式来表达IOC容器的初始化:

ClassPathResource resource = new ClassPathResource("applicationContext.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(resource);

DefaultListableBeanFactory是IOC容器的一个基类,XmlBeanFactory是在其基础上扩展而来的。而其他的IOC容器,例如ApplicationContext,它的实现原理和XmlBeanFactory类似,也是通过扩展DefaultListableBeanFactory来获取基本的IOC容器功能的。

4,ApplicationContext的设计原理

在这里插入图片描述
1、ApplicationContext继承接口ListableBeanFactory、HierarchicalBeanFactory,实现了IOC容器的基本功能。

2、继承接口MessageSource:支持不同信息源,支持国际化的实现。

3、继承接口ResourceLoader:支持该容器可以从不同I/O途径得到Bean的定义信息。

4、继承接口ApplicationEventPublisher:在上下文中引入了事件机制。这些事件机制和Bean的生命周期结合为Bean的管理提供了便利。

ApplicationContext增加了这些附加功能,使得基本IOC容器的功能更加丰富,所以建议在开发应用的时候使用ApplicationContext作为IOC容器的基本形式。

以子类FileSystemXmlApplicationContext的实现为例说明其设计原理。接口设计图如下:
在这里插入图片描述
这个接口设计中,ApplicationContext应用上下文的主要功能已经在FileSystemXmlApplicationContext的基类AbstractXmlApplicationContext中实现了,而FileSystemXmlApplicationContext作为一个具体的IOC容器,只需要实现和其本身相关的功能即可,源码如下:

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
    throws BeansException
  {
    super(parent);
    setConfigLocations(configLocations);
    if (refresh)
      refresh();
  }

  protected Resource getResourceByPath(String path)
  {
    if ((path != null) && (path.startsWith("/"))) {
      path = path.substring(1);
    }
    return new FileSystemResource(path);
  }
}

这里面有两个主要的方法:refresh()、getResourceByPath(String path)

1、refresh涉及到IOC容器启动的一系列操作,由于这个启动过程对于不同类型的容器来说都是相似的,所以这个启动过程被封装在基类中,具体的容器只需要调用即可。refresh方法后面会有详细介绍。

2、getResourceByPath这个方法是跟FileSystemXmlApplicationContext区别于其他具体容器的功能。通过这个方法可以让容器在文件系统中读取以XML形式存在的BeanDefinition。

猜你喜欢

转载自blog.csdn.net/qq_39513430/article/details/105523665