一、什么是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步:
![](/qrcode.jpg)
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】执行自定义销毁方法