首页 > 编程笔记 > Java笔记 阅读:6

Spring IoC容器简介(新手必看)

IoC 容器是一个管理 Bean 的容器,在 Spring 的定义中,所有 IoC 容器都需要实现接口 BeanFactory,它是一个顶级容器接口。

为了增加对它的理解,我们首先阅读其源码,并讨论几个重要的方法,其源码如下:
package org.springframework.beans.factory;
 
/**** imports ****/
public interface BeanFactory {
    // 前缀
   String FACTORY_BEAN_PREFIX = "&";
 
   // 多个getBean()方法
   Object getBean(String name) throws BeansException;
 
   <T> T getBean(String name, Class<T> requiredType) throws BeansException;
 
   <T> T getBean(Class<T> requiredType) throws BeansException;
 
   Object getBean(String name, Object... args) throws BeansException;
 
   <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
 
   // 两个获取Bean的提供器
   <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
 
   <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
 
   // 是否包含Bean
   boolean containsBean(String name);
 
   // Bean是否为单例
   boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
 
   // Bean是否为原型
   boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
 
   // 是否类型匹配
   boolean isTypeMatch(String name, ResolvableType typeToMatch)
      throws NoSuchBeanDefinitionException;
 
   boolean isTypeMatch(String name, Class<?> typeToMatch)
      throws NoSuchBeanDefinitionException;
 
   // 获取Bean的类型
   Class<?> getType(String name) throws NoSuchBeanDefinitionException;
 
   Class<?> getType(String name, boolean allowFactoryBeanInit)
      throws NoSuchBeanDefinitionException;
 
   // 获取Bean的别名
   String[] getAliases(String name);
}
上述源码中加入了中文注释,通过这些中文注释就可以理解这些方法的含义了,下面我们再介绍一些重要的方法:
1) getBean():这是 IoC 容器最重要的方法之一,它的作用是从 IoC 容器中获取 Bean。从多个 getBean() 方法中可以看到,有按名称(by name)获取 Bean 的,也有按类型(by type)获取 Bean 的,这就意味着在 IoC 容器中,允许我们按名称或者类型获取 Bean,这对理解 Spring 的依赖注入(dependency injection,DI)是十分重要的。

2) isSingleton():判断 Bean 是否在 IoC 容器中为单例。这里需要记住的是,在 IoC 容器中, Bean 默认都是以单例存在的,也就是使用 getBean() 方法根据名称或者类型获取的对象,在默认的情况下,返回的都是同一个对象。

3) isPrototype():与 isSingleton() 方法是相反的,如果它返回的是 true,那么当我们使用 getBean() 方法获取 Bean 的时候,IoC 容器就会创建一个新的 Bean 返回给调用者,这些与 Bean 的作用域相关。

由于 BeanFactory 接口定义的功能还不够强大,因此 Spring 在 BeanFactory 的基础上,还设计了一个更为高级的接口 ApplicationContext,它是 BeanFactory 的子接口之一。

在 Spring 的体系中,BeanFactory 和 ApplicationContext 是最为重要的接口设计,在现实中我们使用的大部分 IoC 容器是 ApplicationContext 接口的实现类。

BeanFactory 和 ApplicationContext 的关系如下图所示:


图 1 IoC 容器的接口设计

在图 1 中可以看到,ApplicationContext 接口通过扩展上级接口,进而扩展了 BeanFactory 接口,但是在 BeanFactory 的基础上,扩展了消息国际化接口(MessageSource)、环境可配置化接口(EnvironmentCapable)、应用事件发布接口(ApplicationEventPublisher)和资源模式解析器接口(ResourcePatternResolver),所以 ApplicationContext 的功能会更为强大。

Spring Boot 主要通过注解来将 Bean 装配到 IoC 容器中,为了贴近 Spring Boot 的需要,这里不再介绍与 XML 相关的 IoC 容器,而主要介绍一个基于注解的 IoC 容器——AnnotationConfigApplicationContext。从这个类的名称就可以看出,它是一个基于注解的 IoC 容器,之所以研究它,是因为 Spring Boot 装配和获取 Bean 的方式如出一辙。

下面来看一个最为简单的例子。首先定义一个 Java简 单对象(plain ordinary Java object,POJO)文件 User.java:
package com.learn.chapter.pojo;
/**** imports ****/
public class User {
 
   private Long id; // 编号
   private String userName; // 用户名
   private String note; // 备注
   /**setters and getters **/
}

然后定义一个 Java 配置文件 AppConfig.java,代码如下:
@Configuration
public class AppConfig {
    @Bean(name = "user")
    public User initUser() {
        return new User();
    }
}

做好了这些,就可以使用 AnnotationConfigApplicationContext 来构建自己的 IoC 容器了,代码如下:
package com.learn.chapter.main;
/**** imports ****/
public class IoCTest {
   public static void main(String[] args) {
      // 使用配置文件AppConfig.java创建IoC容器
      var ctx = new AnnotationConfigApplicationContext(AppConfig.class);
      try {
         // 通过getBean()方法获取Bean
         var user = ctx.getBean(User.class);
         System.out.println(user.getUserName());
      } finally {
         // 关闭IoC容器
         ctx.close();
      }
   }
}

上述代码将 Java 配置文件 AppConfig.java 传递给 AnnotationConfigApplicationContext 的构造方法,这样就能创建 IoC 容器了。IoC 容器会根据 AppConfig 创建 Bean,然后将 Bean 装配进来,这样就可以使用 getBean() 方法获取对应的 Bean 了。

注意,Spring 在默认的情况下,扫描到 Bean 后就创建 Bean 并将 Bean 装配到 IoC 容器中,而不是使用 getBean() 方法后才创建和装配 Bean。运行代码后,可以打印出下面的日志:

......
16:11:04.110 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory –
Creating shared instance of singleton bean 'appConfig'
16:11:04.115 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory –
Creating shared instance of singleton bean 'user'
user_name_1

从日志中可以看到,配置文件中的名称为 user 的 Bean 已经被装配到 IoC 容器中,我们可以通过 getBean() 方法获取对应的 Bean,并将 Bean 的属性信息输出出来。这个例子比较简单,注解 @Bean 也不是唯一装配 Bean 的方法,还有其他的方法可以让 IoC 容器装配 Bean,Bean 之间的依赖关系也需要进一步处理。

相关文章