IoC 容器:Spring’s Inversion of Control (IoC) container
Spring 的核心功能是
IoC 容器
。spring-beans
和spring-context
这两个库是 Spring IoC 容器的基础。
spring-core
是 Spring 的核心库,其他所有的 Spring 家族的库都会依赖spring-core
。
BeanFactory
什么是
Bean
:由 Spring IoC 容器管理的对象叫做Bean
。Bean
是由 Spring IoC 容器 实例化、组装、管理 的对象;否则的话Bean
只是应用中的一个普通对象。Bean
及其之间的依赖关系反映在容器使用的配置元数据中。
Spring 官方文档 中有介绍:BeanFactory
接口提供了一种高级的配置机制,能够管理任何类型的对象。
ApplicationContext
ApplicationContext
是 BeanFactory
的子接口,添加了更多功能:
- Easier integration with Spring’s AOP features(更容易与 Spring AOP 特性集成)
- Message resource handling (for use in internationalization)(消息资源处理(国际化))
- Event publication(事件发布)
- Application-layer specific contexts such as the WebApplicationContext for use in web applications.(应用层特定的上下文,例如用于 web 应用的 WebApplicationContext)
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
}
BeanFactory
提供了配置框架和基本功能,ApplicationContext
添加了更多企业级的功能,是前者的超集。
配置 IoC 容器
的元数据
一个类是如何加入到 IoC 容器
中的呢,换句话说:IoC 容器
是怎么识别一个类是普通类还是 Bean
呢?
传统的方式是使用 xml 配置文件(还可以使用 Java 注解 或 Java 代码)来声明各种 元数据
(声明为 Bean
及其之间的依赖关系),之后在 IoC 容器创建并初始化的时候,会读取配置的 元数据
来 初始化、配置、装配 这些 Bean
。
在 web 应用程序中,我们通常会 在 web.xml 中配置 IoC 容器的加载器(org.springframework.web.context.ContextLoaderListener)来实例化
ApplicationContext
。
初始化 IoC 容器
Spring 提供了几种
ApplicationContext
的几种实现:
ConfigurableApplicationContext
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {}
ConfigurableApplicationContext
作为 ApplicationContext
的派生接口,定义了一些非通用的方法。符合面向对象的7大设计原则之一的接口隔离原则。
注意:这里定义的
refresh
方法,不支持多次调用。实现类中的这个方法自然也不支持多次调用
,但是AbstractRefreshableApplicationContext
中提供了多次调用的方法。
AbstractApplicationContext
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {}
ConfigurableApplicationContext
接口的抽象实现类。
其中的 refresh
方法,是 IoC 容器启动的骨架实现,使用了 模板设计模式
。提供对 ConfigurableApplicationContext
接口的 refresh
方法的模板实现,即:定义了 ApplicationContext 的启动步骤,但是不提供具体每一步的实现,由子类实现。
比如其中的 postProcessBeanFactory
方法:
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
AbstractRefreshableApplicationContext
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
@Nullable
// 允许重复Bean定义覆盖
private Boolean allowBeanDefinitionOverriding;
@Nullable
// 允许循环引用
private Boolean allowCircularReferences;
...
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
...
}
继承 AbstractApplicationContext
抽象类,主要提供可多次重复调用 refresh
方法,刷新容器,销毁之前的 BeanFactory
和 Beans
,重新创建。ConfigurableApplicationContext
接口的定义,默认是不支持多次调用 refresh
方法的,多次调用则抛 IllegalStateException
异常。
AbstractRefreshableConfigApplicationContext
public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext
implements BeanNameAware, InitializingBean {
@Nullable
private String[] configLocations;
...
}
继承 AbstractRefreshableApplicationContext
抽象类,主要作用是定义数组类型的 configLocations
变量,用于加载多个 xml 文件来配置 IoC 容器。
AbstractXmlApplicationContext
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {}
继承 AbstractRefreshableConfigApplicationContext
,指定使用 xml 文件保存配置,有两个实现类:
- ClassPathXmlApplicationContext:指定从类路径下加载 xml 配置文件
- FileSystemXmlApplicationContext:指定从文件系统加载 xml 配置文件
// 通过加载类路径下的 xml 配置文件创建并初始化 IoC 容器
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("services.xml");
// 获取 IoC 容器中定义的 Beans 的 name
String[] beanNames = applicationContext.getBeanDefinitionNames();
for (String beanName : beanNames) {
System.out.println(beanName);
}
GenericApplicationContext
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {}
继承 AbstractApplicationContext
,故不具备上面的 Config,Refreshable 功能。而 Bean 的注册,是通过实现 BeanDefinitionRegistry
接口来提供往内部的 beanFactory
注入 beanDefinitions
,而 beanDefinitions
的来源则是通过 BeanDefinitionParser
解析,如 xml 文件来获取的。不支持重复调用 refresh
。
GenericXmlApplicationContext
:继承于 GenericApplicationContext
,比 ClassPathXmlApplicationContext
,FileSystemXmlApplicationContext
更加通用的基于 xml 配置文件的 ApplicationContext
。即可以在构造函数中指定配置数来源,使用的 Resource
类型的数组参数。而前两者都是使用String
类型的 configLocations
数组,即路径数组。
AnnotationConfigApplicationContext
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {}
这个也是用来处理我们项目中使用的注解的类,即将标注了 @Controller
, @Component
等注解的类注册成 bean
。继承于 GenericApplicationContext
,并实现 AnnotationConfigRegistry
接口(AnnotationConfigRegistry
接口主要实现将给定的 beanDefinition
注册到绑定的 beanFactory
中)。