在前面博客中介绍什么是依赖注入时有提到: 依赖注入是组件之间依赖关系由容器在运行期决定, 即由容器动态的将某个依赖关系注入到组件之中. 那什么是容器? 既然 Spring 框架实现了 IOC, 那 Spring 中的容器是什么呢?
一, 容器介绍
在日常生活中容器是指用以容纳物料并以壳体为主的基本装置, 它是用来盛放东西的. 在编程中容器是用来存储和组织其他对象的对象, 首先要确定容器也是对象, 也可以当做 bean, 只是这个对象是用来存储和组织其他对象, 那其他对象是什么呢? 其他对象其实就是 bean 对象, 这也是面向对象编程的一种体现, 万物皆对象. 在 Spring 提供了 BeanFactory,ApplicationContext 两个 IOC 容器, 来管理众多的 bean 对象.
二, BeanFactory
一提到工厂我们生活当中可能会想到富某康, 工厂是一类用以生产货物的大型工业建筑物. 而 BeanFactory 不是用来生产货物的而是用来生产管理 bean 的. BeanFactory 会在 bean 的生命周期的各个阶段中对 bean 进行各种管理, 并且 Spring 将这些阶段通过各种接口暴露给我们, 让我们可以对 bean 进行各种处理, 我们只要让 bean 实现对应的接口, 那么 Spring 就会在 bean 的生命周期调用我们实现的接口来处理该 bean. 那它是怎么实现的呢? 它主要分两个阶段.
1),Bean 容器的启动
工厂要生产货物那首先得把工厂运转起来之后才能生产货物. 同样 bean 容器要管理 bean 也需要先把容器启动起来, 获取到 bean 的定义信息之后才能管理.
1. 读取 bean 的 xml 配置文件, 然后将 xml 中每个 bean 元素分别转换成 BeanDefinition 对象.
- public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
- implements BeanDefinition, Cloneable {
- private volatile Object beanClass;
- private String scope = SCOPE_DEFAULT;
- private boolean abstractFlag = false;
- private boolean lazyInit = false;
- private int autowireMode = AUTOWIRE_NO;
- private int dependencyCheck = DEPENDENCY_CHECK_NONE;
- private String[] dependsOn;
- private ConstructorArgumentValues constructorArgumentValues;
- private MutablePropertyValues propertyValues;
- private String factoryBeanName;
- private String factoryMethodName;
- private String initMethodName;
- private String destroyMethodName;
BeanClass 保存 bean 的 class 属性, scop 保存 Bean 的作用域, abstractFlag 保存该 bean 是否抽象, lazyInit 保存是否延迟初始化, autowireMode 保存是否自动装配, dependencyCheck 保存是否坚持依赖, dependsOn 保存该 bean 依赖于哪些 bean(这些 bean 必须提取初始化),constructorArgumentValues 保存通过构造函数注入的依赖, propertyValues 保存通过 setter 方法注入的依赖, factoryBeanName 和 factoryMethodName 用于 factorybean, 也就是工厂类型的 bean,initMethodName 和 destroyMethodName 分别对应 bean 的 init-method 和 destory-method 属性. 后面会对这些内容进行详细介绍.
2. 通过 BeanDefinitionRegistry 将 bean 注册到 beanFactory 中
上面获取到 bean 的信息之后, 是怎么注册到 BeanFactory 中的呢? 其实是通过 BeanDefinitionRegistry 将 bean 注册到 beanFactory 中. 因为 BeanFactory 的实现类, 需要实现 BeanDefinitionRegistry 接口.
- public interface BeanDefinitionRegistry extends AliasRegistry {
- void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException;
- void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
- BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
- boolean containsBeanDefinition(String beanName);
- String[] getBeanDefinitionNames();
- int getBeanDefinitionCount();
- boolean isBeanNameInUse(String beanName);
- }
BeanDefinitionRegistry 接口提供了根据 beanName 注册对应 beanDefinition 的方法, 而在 DefaultListableBeanFactory 中实现了该方法, 并将 beanDefinition 保存在了 ConcurrentHashMap 中.
- @SuppressWarnings("serial")
- public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
- implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
- /** Map of bean definition objects, keyed by bean name */
- private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
- @Override
- public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
- throws BeanDefinitionStoreException {
- // ... ...
- this.beanDefinitionMap.put(beanName, beanDefinition);
- }
另外 Spring 还对外暴露了一些接口用来对 bean 初始化, 例如 BeanFactoryPostProcessor.
- public interface BeanFactoryPostProcessor {
- /**
- * Modify the application context's internal bean factory after its standard
- * initialization. All bean definitions will have been loaded, but no beans
- * will have been instantiated yet. This allows for overriding or adding
- * properties even to eager-initializing beans.
- * @param beanFactory the bean factory used by the application context
- * @throws org.springframework.beans.BeansException in case of errors
- */
- void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
- }
我们可以翻译一下 postProcessBeanFactory 的注释信息, postProcessBeanFactory 可以修改应用上下文中已经进行 standard 初始化的 beanFactory, 此时所有 bean 的定义信息已经加载完成, 但还未实例化, 允许覆盖, 新增甚至重新初始化 bean 信息, 一个典型的例子就是属性覆盖器 PropertyOverrideConfigurer. 对于一些参数可以配置在 properties 中, 而不用配置在 Spring 的 XML 配置文件中.
2), 容器 Bean 的实例化
上面把 bean 容器启动之后, 工厂算是运转起来了, 配方 (beanDefinition) 也已经准备充分, 然后就是生产 (实例化), 管理货物(bean) 了. 实例化 bean 主要通过反射和 CGLIB 两种方式, 在 bean 的实例化过程中, Spring 也暴露了一些接口.
BeanNameAware 获取该 bean 在配置文件中对应的 id
BeanFactoryAware 获取实例化该 bean 的 BeanFactory
InitializingBean bean 实例化, 所有属性设置后调用初始化方法
DisposableBean 在 bean 丢弃的时候调用销毁方法
我们可以通过示例演示一下这几个接口的使用.
1. 首先创建了 Maven project,pom.xml 引入 spring-core,spring-context.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.demo</groupId>
<artifactId>BeanFactoryDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BeanFactoryDemo</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>5.0.0.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2. 创建 bean 对象, 实现上面列出的接口
- package com.demo.model;
- import org.springframework.beans.BeansException;
- import org.springframework.beans.factory.BeanFactory;
- import org.springframework.beans.factory.BeanFactoryAware;
- import org.springframework.beans.factory.BeanNameAware;
- import org.springframework.beans.factory.DisposableBean;
- import org.springframework.beans.factory.InitializingBean;
- public class UserBean implements BeanNameAware,BeanFactoryAware,InitializingBean,DisposableBean {
- public void setBeanName(String name) {
- System.out.println(name);
- }
- public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
- System.out.println(beanFactory);
- }
- public void afterPropertiesSet() throws Exception {
- System.out.println("InitializingBean");
- }
- public void destroy() throws Exception {
- System.out.println("DisposableBean");
- }
- }
3. bean 配置
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
- <bean id="user" class="com.demo.model.UserBean"></bean>
- </beans>
4. 测试
使用 ApplicationContext 获取 BeanFactory, 再通过 getBean 方法获取到对应的 bean, 最后调用 destroy 方法进行销毁, 从输出结果可以看到依次调用了 BeanNameAware,BeanFactoryAware,InitializingBean,DisposableBean 接口.
- public static void main( String[] args ) throws Exception
- {
- ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
- BeanFactory factory=context;
- UserBean user=(UserBean)factory.getBean("user");
- user.destroy();
- }
输出结果: user
- org.springframework.beans.factory.support.DefaultListableBeanFactory@6bf256fa: defining beans [user]; root of factory hierarchy
- InitializingBean
- DisposableBean
三, ApplicationContext
在上面的示例中使用了 ApplicationContext 获取 bean 的配置, 然后直接将 ApplicationContext 接口 对象赋值给了 BeanFactory 接口对象, 为什么可以赋值呢? 其实 ApplicationContext 接口实现了 BeanFactory 接口.
- public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
- MessageSource, ApplicationEventPublisher, ResourcePatternResolver
从上面 ApplicationContext 接口的继承关系可以看到, 它还通过继承其他接口扩展了 BeanFactory 的功能. MessageSource: 为应用提供国际化访问功能. ResourceLoader: 提供资源 (如 URL 和文件系统) 的访问支持. ApplicationEventPublisher: 引入事件机制, 包括启动事件, 关闭事件等, 让容器在上下文中提供了对应用事件的支持. 它代表的是一个应用的上下文环境. beanFactory 主要是面对与 spring 框架的基础设施, 面对 spring 自己. 而 Applicationcontex 主要面对与 spring 使用的开发者. 基本都会使用 Applicationcontex 并非 beanFactory . 所以在上面实例使用的 ApplicationContext 获取 BeanFactory 接口对象.
来源: https://www.cnblogs.com/5ishare/p/9498533.html