Spring之IOC容器

在前面博客中介绍什么是依赖注入时有提到:依赖注入是组件之间依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中。那什么是容器?既然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.s[email protected]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

时间: 2024-10-17 04:16:05

Spring之IOC容器的相关文章

Spring之IOC容器加载初始化的方式

引言 我们知道IOC容器时Spring的核心,可是如果我们要依赖IOC容器对我们的Bean进行管理,那么我们就需要告诉IOC容易他需要管理哪些Bean而且这些Bean有什么要求,这些工作就是通过通过配置文件告诉Spring 的IOC容器.在我们的完成这些配置文件以后,如果IOC容易要实现对这些Bean的管理,除了资源的定位还有一个很重要的一步就是完成IOC加载初始化,也就是配置文件的载入过程.完成IOC容器加载初始化的方式只要有三种,第一种就是通过File文件加载,第二种是通过Classpath

Spring核心技术IoC容器(八)

本文针对自动装载的一些注解进行描述. 基于注解的容器配置 @Required注解 @Required注解需要应用到Bean的属性的setter方法上面,如下面的例子: public class SimpleMovieLister { private MovieFinder movieFinder; @Required public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } //

Spring的IOC容器—依赖注入

前面一篇博客大致讲了一下Spring的IOC容器的原理,IOC即控制反转主要是依靠依赖注入的方式来实现的.依赖注入是指所依赖的对象不是由自己new出来的,而是用别的方式像打针似的注入进来. 其实说白了不管是控制反转还是依赖注入都说明了Spring采用动态.灵活的方式来管理各种对象. Spring的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对POJO之间依赖关系的管理.有以下几种注入方式: 1. Setter 注入 因为对于javaBean来说,我们可以通过setter和getter方法

好莱坞原则—Spring的IOC容器

IOC容器的概念,之前在学习SSH的时候,就有接触过.但那时候也仅仅是知道这么个概念,认为它非常难理解.事实上并非它难理解,而是我并没有停下来好好对它总结梳理过. IOC(Inversion of Control)简单介绍: 控制反转",并非一种技术.而是一种思想.一种主动提供服务的思想.所谓IOC,就是由Spring负责控制对象的生命周期和对象间的关系,与我们传统的在对象内部直接控制背道而驰. 在传统的程序开发中,完毕一个业务逻辑至少须要两个或两个以上的对象协助完毕.通常一个对象要使用另外一个

Spring框架IOC容器和AOP解析

主要分析点: 一.Spring开源框架的简介  二.Spring下IOC容器和DI(依赖注入Dependency injection) 三.Spring下面向切面编程(AOP)和事务管理配置  一.Spring开源框架的简介  Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来.它是为了解决企业应用开

Spring的IOC容器—scope作用域

Scope 简介: Scope用来声明容器中的对象的存货时间.即容器在对象在进入其相应的scope之前,生成并装配这些对象,在该对象不再处于这些scope的限定之后,容器通常会销毁这些对象. Sprign容器最初提供了两种bean的scope类型:singletoon和prototype.自Spring2.0之后,引入了另外三种scope类型,即request.session和global session类型.这三种类型只能再web中使用. 1.Singleton 代表在Spring的IOC容器

Spring 核心技术 IoC容器(一)

IoC 容器 IoC容器和Bean简介 这章包括了Spring框架对于IoC规则的实现.Ioc也同DI(依赖注入).而对象是通过构造函数,工厂方法,或者一些Set方法来定义对象之间的依赖的.容器在创建这些Bean对象的时候同时就会注入这些依赖.这个过程是根本上的反转了,不再由Bean本身来控制实例化和定位依赖,而是通过服务定位来控制这个过程,也是IoC(控制反转)的由来. org.springframework.beans和org.springframework.context包是Spring框

Spring核心技术IoC容器(六)

前文已经描述了Bean的作用域,本文将描述Bean的一些生命周期作用,配置还有Bean的继承. 定制Bean 生命周期回调 开发者通过实现Spring的InitializeingBean和DisposableBean接口,就可以让容器来管理Bean的生命周期.容器会调用afterPropertiesSet()前和destroy()后才会允许Bean在初始化和销毁Bean的时候执行一些操作. JSR-250的@PostConstruct和@PreDestroy注解就是现代Spring应用生命周期回

Spring核心技术IoC容器(五)

前文概述了Spring的容器,Bean,以及依赖的一些信息,本文将描述一下Bean的作用域 Bean的作用域 当开发者定义Bean的时候,同时也会定义了具体如何创建Bean实例的步骤.这些步骤是很重要的,因为只有通过这些配置,开发者才能创建实例对象. 开发者不仅可以控制多种多样的依赖到Bean之中,也可以配置Bean的作用域.这种方法是非常强大而且弹性也非常好,开发者可以通过配置来指定对象的作用域,而不用在Java类层次上来配置.Bean可以配置多种作用域.Spring框架支持5中作用域,有三种

spring在IoC容器中装配Bean详解

1.Spring配置概述 1.1.概述 Spring容器从xml配置.java注解.spring注解中读取bean配置信息,形成bean定义注册表: 根据bean定义注册表实例化bean: 将bean实例放入bean缓存池: 应用程序使用bean. 1.2.基于xml的配置 (1)xml文件概述 xmlns------默认命名空间 xmlns:xsi-------标准命名空间,用于指定自定义命名空间的schema文件 xmlns:xxx="aaaaa"-------自定义命名空间,xx