一、什么是IoC

IoC,Inversion of Control,控制反转。控制反转是一种通过描述(在java中可以使XML或者注解)并通过第三方去获取特定对象的方式。简单地说就是将对象由虚拟机主动创建变为从IoC容器中获取,它是面向对象编程的一种思想,主要作用是降低开发难度、对模块解耦、有利于测试,常见实现方式是依赖注入(DI)和依赖查找(DL)。

二、Spring IoC容器的设计

Spring IoC容器的设计主要是基于BeanFactory和ApplicationContext两个接口。BeanFactory是Spring IoC所定义的最底层的接口,ApplicationContext是其高级接口之一,是最常用的Spring IoC容器。Spring IoC容器设计图如下:

这里写图片描述

再来看看BeanFactory定义的方法:

这里写图片描述

  • getBean 用于过去配置给Spring IoC 容器的Bean

  • isSingleton 用于判断是否单例。默认返回true

  • isPrototype 判断是否为原型。默认返回false

  • getAliases 用于获取别名

三、Spring IoC容器的初始化和依赖注入

1、Bean的定义和初始化

Bean的定义和初始化在Spring IoC中是两个步骤,它是先定义然后初始化和依赖注入的。Bean的定义分为3步:

  • Resource定位,这步是Spring IoC根据开发者的配置,进行资源定位。定位的内容由开发者提供。

  • BeanDefinition的载入,这个时候是将Resource定位的信息保存到Bean定义(BeanDefinition)中,此时不会创建Bean的实例。

  • BeanDefinition的注册,这个过程是将BeanDefinition的信息发布到Spring IoC容器中,此时仍没有对应的Bean的实例创建。

做完这三步,Bean就在Spring IoC容器中定义了,还没有初始化,更没有完成依赖注入。对于初始化和依赖注入,Spring Bean还有一个配置项——lazy-init,其含义是是否延迟初始化Spring Bean,默认值false,也就是默认自动初始化Bean,如果设置成true,那么Bean的初始化和依赖注入将在执行getBean方法时进行。

2、依赖注入

Spring实现IoC主要采用依赖注入,一般而言,依赖注入分为以下三种方式:

  • 构造器注入:依赖于构造方法实现,构造方法可以使有参的和无参的。Spring内部采用反射的方式调用构造方法实现注入。XML方式对应c标签。

  • 设值注入:设值注入依赖setter方法,是Spring最主流的注入方式。灵活且可读性高。其原理也是通过反射实现,设值注入依赖于无参构造器,当bean类声明了带参构造器时必须同时声明无参构造器。XML方式对应p标签。

  • 接口注入:适用于来自于外界的资源,比如数据库连接资源可以在Tomcat下配置,然后通过JNDI的形式去获取它。此时可以使用借口注入。

四、Spring Bean的生命周期

学习Bean的生命周期主要是为了了解Spring IoC容器初始化到销毁Bean的过程,知道如何在Bean初始化和销毁的时候加入自定义的方法,以满足特定的需求。Spring Bean的生命周期如下图:
这里写图片描述
Spring IoC容器在执行初始化和依赖注入后,会执行一定的步骤来完成初始化。下面用代码实现bean生命周期的各方法实现:

  • BeanPostProcessor的实现类(bean后处理器),该接口是针对所有bean生效的
package com.yozzs.ioc.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class BeanPostProcessorImpl implements BeanPostProcessor{
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【"+bean.getClass().getSimpleName()+"】对象"
                +beanName+"开始实例化");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【"+bean.getClass().getSimpleName()+"】对象"
                +beanName+"实例化完成");
        return bean;
    }

}
  • Bean类
package com.yozzs.ioc.bean;

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;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class Role implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {

    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void init() {
        System.out.println("【" + this.getClass().getSimpleName() + "】" + "执行自定义初始化方法");
    }

    public void MyDestroy() {
        System.out.println("【" + this.getClass().getSimpleName() + "】" + "执行自定义销毁方法");
    }

    // 代表主业务方法
    public void doService() {
        System.out.println("Role [id=" + id + ", name=" + name + "]执行主要方法");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("【" + this.getClass().getSimpleName() + "】" + "调用InitializingBean接口的afterPropertiesSet方法");
    }

    @Override
    public void setApplicationContext(ApplicationContext arg0) throws BeansException {
        System.out.println(
                "【" + this.getClass().getSimpleName() + "】" + "调用ApplicationContextAware接口的setApplicationContext方法");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("【" + this.getClass().getSimpleName() + "】" + "调用BeanFactoryAware接口的setBeanFactory方法");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("【" + this.getClass().getSimpleName() + "】" + "调用BeanNameAware接口的setBeanName方法");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("【" + this.getClass().getSimpleName() + "】调用接口DisposableBean的destroy方法");
    }

}
  • spring配置文件,声明bean自定义初始化和销毁方法
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean id="beanPostProcessor" class="com.yozzs.ioc.bean.BeanPostProcessorImpl"/>
    <bean id="role" class="com.yozzs.ioc.bean.Role" init-method="init" destroy-method="MyDestroy">
        <property name="id" value="1"></property>
        <property name="name" value="柚子"></property>
    </bean>
</beans>
  • 测试类`
package com.yozzs.ioc.test;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.yozzs.ioc.bean.Role;

public class MyTest {
    @Test
    public void test01() {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Role role = (Role) ctx.getBean("role");
        role.doService();
        ctx.close();
    }
}
  • 测试结果
【Role】调用BeanNameAware接口的setBeanName方法
【Role】调用BeanFactoryAware接口的setBeanFactory方法
【Role】调用ApplicationContextAware接口的setApplicationContext方法
【Role】对象role开始实例化
【Role】调用InitializingBean接口的afterPropertiesSet方法
【Role】执行自定义初始化方法
【Role】对象role实例化完成
Role [id=1, name=柚子]执行主要方法
【Role】调用接口DisposableBean的destroy方法
【Role】执行自定义销毁方法

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐