Spring 中 IoC 容器简介
ioc 是一种通过描述来生成或者获取对象的技术,可以说 spring 是一种基于 ioc 容器编程的框架
在一个系统中可以生成各种对象,并且这些对象都需要进行管理。为了描述这些对象关系,我们需要一个容器。在 spring 中把每一个需要管理的对象称为 spring bean ,而管理这些 bean 的容器就被称为 spring ioc 容器。
ioc 容器需要具备两个基本的功能:
- 通过描述管理 bean ,包括发布和获取 bean
- 通过描述完成 bean 之间的依赖关系
介绍
spring ioc 容器是一个管理 bean 的容器,在 spring 的定义中,它要求所有的 ioc 容器都需要实现接口 beanfactory,它是一个*容器接口。
如下是部分源码:
import org.springframework.beans.beansexception; import org.springframework.core.resolvabletype; import org.springframework.lang.nullable; public interface beanfactory { //前缀 string factory_bean_prefix = "&"; // 多个 getbean 方法 object getbean(string var1) throws beansexception; <t> t getbean(string var1, class<t> var2) throws beansexception; object getbean(string var1, object... var2) throws beansexception; <t> t getbean(class<t> var1) throws beansexception; <t> t getbean(class<t> var1, object... var2) throws beansexception; <t> objectprovider<t> getbeanprovider(class<t> var1); <t> objectprovider<t> getbeanprovider(resolvabletype var1); //是否包含 bean boolean containsbean(string var1); //是否是单例 boolean issingleton(string var1) throws nosuchbeandefinitionexception; //是否是原型 boolean isprototype(string var1) throws nosuchbeandefinitionexception; //是否类型匹配 boolean istypematch(string var1, resolvabletype var2) throws nosuchbeandefinitionexception; boolean istypematch(string var1, class<?> var2) throws nosuchbeandefinitionexception; //获取bean 类型 @nullable class<?> gettype(string var1) throws nosuchbeandefinitionexception; //获取bean别名 string[] getaliases(string var1); }
从源码中可以看到多个 getbean 方法,这也是 ioc 容器最重要的方法之一,它的意义就是从 ioc 容器中获取 bean 。而从多个 getbean 方法中可以看出在 spring ioc 容器中,允许我们从多种途径获取 bean,这对后面理解依赖注入(di)十分重要。
issingleton 方法则判断 bean 是否在 spring ioc 中为单例。这里需要记住的是 在 spring ioc 容器中,默认情况下,bean 都是单例存在的,也就是说使用 getbean 方法返回的都是同一个对象。
与 issingleton 方法相反的是 isprototype 方法。如果它返回的是 true,那么当我们使用 getbean 方法获取 bean 的时候, spring ioc 容器就会创建一个新的 bean 返回给调用者。
但是 beanfactory 方法功能还不够强大,因此 spring 在beanfactory 基础上,还设计了一个更高级的接口 applicationcontext 。 在现实中我们使用的大部分 spring ioc 容器都是 applicationcontext 接口的实现类。
在 spring boot 中,我们主要是通过注解来装配 bean 到 spring ioc 容器中,我们主要介绍一个基于注解的 ioc 容器—— annotationconfigapplicationcontext。
示例
下面来看一个简单例子。首先定义一个java简单对象 user:
public class user { private long id; private string username; private string note; /**setter and getter**/ }
然后再定义一个java配置文件 appconfig.java
import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; @configuration public class appconfig { @bean(name = "user") public user inituser(){ user user = new user(); user.setid(1l); user.setusername("name"); user.setnote("note"); return user; } }
这里需要注意注解 @configuration 和注解 @bean。
前者代表这是一个 java 配置文件,spring 容器会根据它来生成 ioc 容器去装配bean。
后者代表将 inituser 方法返回的 pojo 装配到 ioc 容器中,而其 属性 name 定义这个bean 的名称,如果没有配置它,那么则将方法名 inituser 作为bean的名称并保存到 spring ioc 容器中。
做好这些 ,就可以使用 annotationconfigapplicationcontext 来构建自己的 ioc 容器了:
import org.apache.logging.log4j.logmanager; import org.apache.logging.log4j.logger; import org.springframework.context.applicationcontext; import org.springframework.context.annotation.annotationconfigapplicationcontext; public class ioctest { private static logger logger = logmanager.getlogger(logmanager.root_logger_name); public static void main(string[] args){ applicationcontext ctx = new annotationconfigapplicationcontext(appconfig.class); user user = ctx.getbean(user.class); logger.info("user' id is " + user.getnote()); } }
代码中将 java 配置文件 appconfig 传递给 annotationconfigapplicationcontext 的构造方法,这样它就能读取配置了。 然后将配置中的 bean 装配到 ioc 容器中,于是就可以使用 getbean 方法获取对应的 pojo ,你可能会看到如下的日志打印:
…… 16:15:22.404 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'appconfig' 16:15:22.410 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'user' 16:15:22.453 [main] info - user' id is note
显然,配置在配置文件中的名称为 user 的 bean 已经被装配到了 ioc 容器中,并且可以通过 getbean 方法获取对应的 bean ,并将 bean 的属性信息输出出来。