完成IoC容器

廖雪峰
资深软件开发工程师,业余马拉松选手。

现在,我们已经完成了IoC容器的基本功能。最后的收尾工作主要是提取接口。先定义给用户使用的ApplicationContext接口:

public interface ApplicationContext extends AutoCloseable {

    // 是否存在指定name的Bean?
    boolean containsBean(String name);

    // 根据name返回唯一Bean,未找到抛出NoSuchBeanDefinitionException
    <T> T getBean(String name);

    // 根据name返回唯一Bean,未找到抛出NoSuchBeanDefinitionException
    <T> T getBean(String name, Class<T> requiredType);

    // 根据type返回唯一Bean,未找到抛出NoSuchBeanDefinitionException
    <T> T getBean(Class<T> requiredType);

    // 根据type返回一组Bean,未找到返回空List
    <T> List<T> getBeans(Class<T> requiredType);

    // 关闭并执行所有bean的destroy方法
    void close();
}

再定义一个给Framework级别的代码用的ConfigurableApplicationContext接口:

public interface ConfigurableApplicationContext extends ApplicationContext {

    List<BeanDefinition> findBeanDefinitions(Class<?> type);

    @Nullable
    BeanDefinition findBeanDefinition(Class<?> type);

    @Nullable
    BeanDefinition findBeanDefinition(String name);

    @Nullable
    BeanDefinition findBeanDefinition(String name, Class<?> requiredType);

    Object createBeanAsEarlySingleton(BeanDefinition def);
}

AnnotationConfigApplicationContext实现接口:

public class AnnotationConfigApplicationContext implements ConfigurableApplicationContext {
    ...
}

顺便在close()方法中把Bean的destroy方法执行了。

最后加一个ApplicationUtils类,目的是能通过getRequiredApplicationContext()方法随时获取到ApplicationContext实例。

搞定summer-context模块!

有的同学可能会问,为什么我们用了不到1000行核心代码,就实现了ApplicationContext?如果查看Spring的源码,可以看到,光是层次结构,就令人眼花缭乱:

BeanFactory
  HierarchicalBeanFactory
    ConfigurableBeanFactory
      AbstractBeanFactory
        AbstractAutowireCapableBeanFactory
          DefaultListableBeanFactory
    ApplicationContext
      ConfigurableApplicationContext
        AbstractApplicationContext
          AbstractRefreshableApplicationContext
            AbstractXmlApplicationContext
              ClassPathXmlApplicationContext
              FileSystemXmlApplicationContext
          GenericApplicationContext
            AnnotationConfigApplicationContext
            GenericXmlApplicationContext
            StaticApplicationContext

其实根本原因是我们大幅简化了需求。Spring最早提供了BeanFactoryApplicationContext两种容器,前者是懒加载,后者是立刻初始化所有Bean。懒加载的特性会导致依赖注入变得更加复杂,虽然BeanFactory在实际项目中并没有什么卵用。然而一旦发布了接口,处于兼容性考虑,就没法再收回去了。再考虑到Spring最早采用XML配置,后来采用Annotation配置,还允许混合配置,这样一来,早期发布的XmlApplicationContext不能动,新的Annotation配置就必须添加新的实现类,所以,代码的复杂度随着需求增加而增加,保持兼容性又会导致需要更多的代码来实现新功能。

所以,没事不要瞎提需求。

参考源码

可以从GitHubGitee下载源码。

GitHub



Comments

Loading comments...