Spring IOC
欢迎光临我的博客[http://poetize.cn],前端使用Vue2,聊天室使用Vue3,后台使用Spring Boot
前言
IOC 全称为 Inversion of Control(控制反转),通过反射技术,将 Bean 注入 IOC容器,由 Spring IOC 容器来负责管理对象的生命周期和对象之间的依赖关系
依赖注入(DI),就是由 IOC容器 在运行期间,动态地将某种依赖关系注入到对象之中
依赖注入(DI)和控制反转(IOC)是从不同的角度的描述同一件事情:通过将 Bean 引入 IOC容器,利用依赖关系注入的方式,实现对象之间的解耦
IOC 是把以前工厂方法里写死的对象生成代码,改变为由配置文件来定义,把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性
主要依赖源码是 spring-beans 和 spring-context 两个包
ContextLoaderListener
Spring 初始化的入口在 ContextLoaderListener。Spring 为我们提供的 IOC容器,需要指定容器的配置文件,然后由该监听器初始化并创建该容器。
Spring 通常可以在 web.xml 配置:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
ContextLoaderListener 本质上是创建了一个 WebApplicationContext,自动装载 ApplicationContext 的配置信息。
ContextLoaderListener 是实现了 javax.servlet.ServletContextListener 接口的服务器端程序,
随 web 应用的启动而启动,只初始化一次,随 web 应用的停止而销毁。
Spring IOC 容器先根据监听初始化 WebApplicationContext,然后再初始化 web.xml 中其他配置的 servlet,
并加载其设置的配置信息和参数信息到上下文中(初始化上下文信息 servletContext),
然后将 WebApplicationContext 设置为 servletContext 的父容器。
依赖注入三种方法
构造器注入:
index 是索引,指定注入的属性,从0开始
type 是指该属性所对应的类型
ref 是指引用的依赖对象
value 当注入的不是依赖对象,而是基本数据类型时,就用value
被注入的对象通过在其构造方法中声明依赖对象的参数列表,让外部知道它需要哪些依赖对象。
YoungMan(BeautifulGirl beautifulGirl){
this.beautifulGirl = beautifulGirl;
}
xml方式:
<!-- 注册A -->
<bean id="a" class="spring.A">
<constructor-arg ref="b"></constructor-arg>
<constructor-arg index="0">
<list>
<ref bean="user1"/>
<ref bean="user2"/>
<value>张三</value>
</list>
</constructor-arg>
</bean>
<!-- 注册B -->
<bean id="b" class="spring.B"></bean>
构造器注入方式比较直观,对象构造完毕后就可以直接使用。
解决循环依赖问题:一个构造器注入,一个setter注入。
setter 方法注入:
对于 JavaBean 对象而言,我们一般都是通过 getter 和 setter 方法来访问和设置对象的属性。
通过set方法注入属性,那么Spring会通过默认的无参构造方法来实例化对象,
所以如果在类中重写带有参数的构造方法,一定要把无参构造方法也写上,否则spring没有办法实例化对象,导致报错。
public class YoungMan {
private BeautifulGirl beautifulGirl;
public void setBeautifulGirl(BeautifulGirl beautifulGirl) {
this.beautifulGirl = beautifulGirl;
}
}
<!-- 注册A -->
<bean id="a" class="spring.A">
<!-- 写法一 -->
<!-- <property name="UserName" ref="b"></property> -->
<!-- 写法二 -->
<property name="userName" ref="b"></property>
<property name="cars">
<list>
<ref bean="car1"/>
</list>
</property>
</bean>
<!-- 注册B -->
<bean id="b" class="spring.B"></bean>
基于注解的注入:
bean的属性autowire,autowire主要有三个属性值:byName,byType。
byName:
被注入bean的id<名称>必须与set方法后半截匹配,并且id名称的第一个单词的首字母必须小写。
byType:
查找所有的set方法,将符合参数<类型>的bean注入。
注册bean的注解有以下几种:
@Component:用于注册所有的bean
@Repository:用于注册dao层的bean
@Controller:用于注册控制层的bean
@Service:用于注册服务层的bean
@Resource和@Autowired之间的区别
@Resource(name="userDao"):
java的注解,如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
如果既没有指定name,又没有指定type,则自动按照byName方式进行装配,
如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配
@Autowired:
spring注解,默认是以byType的方式去匹配类型相同的bean,
如果匹配到一个,那么就直接注入该bean,
如果byType查找到多个的话,使用@Qualifier("userDao")注解指定某个具体名称的bean,
没有找到的话就抛出异常。
依赖对象必须存在,如果允许null值,可以设置它的required属性为false(@Autowired(required=false))
启动 Spring 容器
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
FileSystemXmlApplicationContext:
构造函数需要一个 xml 配置文件在系统中的路径,其他和 ClassPathXmlApplicationContext 基本上一样。
AnnotationConfigApplicationContext:
基于注解来使用的,它不需要配置文件,采用 java 配置类和各种注解来配置。
ClassPathXmlApplicationContext 源码分析
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
//如果已经有 ApplicationContext,并需要配置成父子关系
public ClassPathXmlApplicationContext(ApplicationContext parent) {
super(parent);
}
public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, @Nullable ApplicationContext parent) throws BeansException {
super(parent);
Assert.notNull(paths, "Path array must not be null");
Assert.notNull(clazz, "Class argument must not be null");
this.configResources = new Resource[paths.length];
for(int i = 0; i < paths.length; ++i) {
this.configResources[i] = new ClassPathResource(paths[i], clazz);
}
this.refresh(); //核心方法
}
}
refresh() 初始化 Bean容器
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
/**
* 初始化 Bean容器
*/
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
//准备工作,准备新的上下文环境、记录下容器的启动时间、标记“已启动”状态、执行一些属性的初始化。
this.prepareRefresh();
/**
* 创建 BeanFactory:DefaultListableBeanFactory
* 读取 Spring 配置文件,验证配置文件的内容,并封装成 Resource,根据 Resource 加载 XML 配置文件,并解析成 Document 对象
* 拿到 Document 中的根节点,遍历根节点和所有子节点。根据命名空间,进行不同的解析,将 bean 节点内容解析成 BeanDefinition
* 加载到 BeanFactory 中(将 BeanDefinition 注册到注册表中(也就是beanDefinitionNames、beanDefinitionMap、aliasMap缓存))
*/
/**
* "加载到 BeanFactory 中"的内容主要指的是添加到以下3个缓存:
* beanDefinitionNames缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 集合
* beanDefinitionMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和 BeanDefinition 映射
* aliasMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和别名映射。
*/
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//设置 BeanFactory 的类加载器,添加 BeanPostProcessor,手动注册特殊的bean
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
//BeanFactoryPostProcessor 是针对 BeanFactory 的扩展,主要用在 bean 实例化之前,读取 bean 的定义,并可以修改它。
this.invokeBeanFactoryPostProcessors(beanFactory);
//BeanPostProcessor 是针对 bean 的扩展,主要用在 bean 实例化之后,允许开发者对 bean 实例进行修改。
this.registerBeanPostProcessors(beanFactory);
//初始化当前 ApplicationContext 的 MessageSource,用于国际化
this.initMessageSource();
/**
* 初始化当前 ApplicationContext 的事件广播器(ApplicationEvent),使用了一个标准的观察者模式:
* 对于applicationEventMulticaster内部的监听者applicationListeners,每次事件到来都会一一获取通知。
* 如果系统有需要广播的情况下,会发送一个 applicationEvent 事件,
* 注册的listener会根据自己关心的类型进行接收和解析。
*/
this.initApplicationEventMulticaster();
//模板方法,提供给子类扩展实现,可以重写以添加特定于上下文的刷新工作,默认实现为空(在实例化 singleton beans 之前)
this.onRefresh();
//注册监听器,与广播器是同时存在的。Spring初始化广播器,但是并没有为广播器绑定Listener。Spring在此方法中进行了绑定。
this.registerListeners();
//实例化所有的 singleton beans(lazy-init(懒加载)除外)
this.finishBeanFactoryInitialization(beanFactory);
//广播事件,表示 ApplicationContext 初始化完成
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
//销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源。
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
/**
* 创建 Bean容器(Bean 并没有实例化)
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
this.refreshBeanFactory(); //关闭旧的 BeanFactory,创建新的 BeanFactory
return this.getBeanFactory(); //返回刚刚创建的 BeanFactory
}
protected final void refreshBeanFactory() throws BeansException {
if (this.hasBeanFactory()) {
this.destroyBeans(); //如果 ApplicationContext 中已经加载过 BeanFactory,销毁所有 Bean
this.closeBeanFactory(); //关闭 BeanFactory
}
try {
DefaultListableBeanFactory beanFactory = this.createBeanFactory(); //创建并初始化BeanFactory实现类的实例
beanFactory.setSerializationId(this.getId()); //序列化
this.customizeBeanFactory(beanFactory); //设置 BeanFactory 的两个配置属性:是否允许 BeanDefinition 覆盖、是否允许循环引用
//BeanDefinition 中保存了 Bean 信息
//比如这个 Bean 指向的是哪个类、是否是单例的、是否懒加载、这个 Bean 依赖了哪些 Bean
//初始化 Bean容器(配置文件的配置信息转换为一个个 BeanDefinition,然后注册各个 BeanDefinition 到 BeanFactory)
this.loadBeanDefinitions(beanFactory);
synchronized(this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
}
}
}
详细过程
1. prepareRefresh 准备刷新容器
(1) initPropertySources() 自定义属性设置,空方法,留给子类继承
(2) this.getEnvironment().validateRequiredProperties() 首先获取环境配置,然后校验必需属性
(3) this.earlyApplicationListeners = new LinkedHashSet(this.applicationListeners) 初始化事件监听器
(4) this.earlyApplicationEvents = new LinkedHashSet() 初始化早期事件
2. obtainFreshBeanFactory 获取Bean工厂
(1) this.refreshBeanFactory() 新建一个Bean工厂,类型为DefaultListableBeanFactory
(2) this.getBeanFactory() 返回刚刚创建的Bean工厂
3. prepareBeanFactory 对Bean工厂做各种预处理设置
(1) 在Bean工厂中设置类加载器、属性解析器等
(2) 在Bean工厂中添加部分Bean后置处理器,例如ApplicationContextAwareProcessor、ApplicationListenerDetector
(3) 在Bean工厂中设置忽略自动注入的接口
(4) 设置自动装配规则
(5) 在Bean工厂中注册一些Bean组件,例如环境配置ConfigurableEnvironment
4. postProcessBeanFactory Bean工厂的后置处理工作
5. invokeBeanFactoryPostProcessors 执行Bean工厂后置处理器
这一步是在Bean工厂的标准初始化(1-4)之后进行的,主要是执行BeanFactoryPostProcessor及其子接口的
BeanFactoryPostProcessor的子接口主要是指BeanDefinitionRegistryPostProcessor:可以向容器中注册自定义的BeanDefinition
(1) 从容器器中获取BeanDefinitionRegistryPostProcessor类型的Bean组件
(2) 将BeanDefinitionRegistryPostProcessor类型的Bean组件按照顺序分类并排序,即是否实现了PriorityOrdered、Ordered接口
(3) 依次执行实现了PriorityOrdered接口的、实现了Ordered接口的、
没有实现任何顺序接口的Bean组件的postProcessBeanDefinitionRegistry(registry)方法
(4) 执行所有BeanDefinitionRegistryPostProcessorBean的postProcessBeanFactory(beanFactory)方法
(5) 从容器中获取其他的BeanFactoryPostProcessor类型的Bean组件,即不是BeanDefinitionRegistryPostProcessor类型的
(6) 剩下的步骤跟上面类似,就是先按照实现的顺序接口分类,在每个类别下排序,然后依次执行它们的postProcessBeanFactory(beanFactory)方法
6. registerBeanPostProcessors 注册Bean后置处理器,这种处理器用于拦截bean的创建过程
BeanPostProcessor有很多子接口,每种子接口的执行时机各有不同
|-DestructionAwareBeanPostProcessor
|-InstantiationAwareBeanPostProcessor
|-MergedBeanDefinitionPostProcessor
|-SmartInstantiationAwareBeanPostProcessor
(1) 获取所有的BeanPostProcessor的Bean名称
(2) 将所有的Bean按优先顺序分为三类:
|-实现了PriorityOrdered接口的列表priorityOrderedPostProcessors
|-实现了Ordered接口的列表orderedPostProcessors
|-没有实现任何顺序接口的列表nonOrderedPostProcessors
|-MergedBeanDefinitionPostProcessor类型的,都放在internalPostProcessors中
(3) 注册priorityOrderedPostProcessors
(4) 注册orderedPostProcessors
(5) 注册nonOrderedPostProcessors
(6) 注册internalPostProcessors
(7) 注册ApplicationListenerDetector,它的作用是在Bean实例化之后判断其是否为
ApplicationListner类型,如果是,则将其添加进容器的监听器集合
7. initMessageSource 初始化消息源Bean,用于消息绑定、消息解析等功能,并且提供国际化解决方案
(1) 获取beanFactory
(2) 判断beanFactory中是否包含id为messageSource的Bean
(3) 如果已存在,则赋值给容器的messageSource属性,这种情况是我们自己在容器中注册了这个Bean
(4) 如果不存在,则新建一个DelegatingMessageSource,并赋值给容器的messageSource属性,
然后在beanFactory中注册这个新Bean,并设置其id为messageSource
8. initApplicationEventMulticaster 初始化事件广播器
(1) 获取beanFactory
(2) 判断beanFactory中是否存在id为applicationEventMulticaster的Bean
(3) 如果已存在,则赋值给容器的applicationEventMulticaster属性,这种情况是我们自己在容器中注册了这个Bean
(4) 如果不存在,则新建一个SimpleApplicationEventMulticaster,并赋值给容器的
applicationEventMulticaster属性,然后在beanFactory中注册这个新Bean,
并设置其id为applicationEventMulticaster
9. onRefresh 没有任何操作,留给子类继承的,我们可以自定义子容器,在重写方法中做一些我们想要的操作
10. registerListeners 注册事件监听器
(1) 获取容器的属性applicationListeners,这是一个事件监听器的集合,将集合中的每个元素都添加进事件广播器
(2) 从容器中获取所有ApplicationListener类型的Bean,将这些Bean添加进事件广播器
(3) 发布早期事件,即容器的earlyApplicationEvents属性,然后清空早期事件
11. finishBeanFactoryInitialization 完成剩下的单实例bean的实例化
(1) 进入DefaultListableBeanFactory.preInstantiateSingletons()方法,获取容器中所有的Bean id列表
(2) 遍历Bean id列表,对每个Bean,获取其Bean定义信息,即RootBeanDefinition
(3) 从Bean定义信息中筛选掉抽象类、非单实例、懒加载的,这些bean在创建容器时并不实例化,
另外还有工厂Bean,即实现了FactoryBean接口的,需要另外一套逻辑进行实例化
(4) 从缓存中获取单实例Bean,即DefaultSingletonBeanRegistry类的singletonObjects属性,所有被创建过的
单实例Bean都会被缓存在这个映射中;如果缓存中存在,说明这个Bean之前被创建过,直接返回
(5) 如果缓存中不存在,则开始新建:AbstractBeanFactory.getBean(beanName)
① 将Bean标记为已创建,即将其id存入AbstractBeanFactory的alreadyCreated属性中
② 获取Bean的定义信息,即RootBeanDefinition
③ 从定义信息中获取该Bean依赖的Bean,如果存在,则重新从第11(4)步开始执行,创建这些依赖的Bean
④ 创建完依赖Bean(如果存在)之后,以下开始正式新建目标Bean
⑤ 给Bean后置处理器一个机会用代理对象代替目标对象,即执行InstantiationAwareBeanPostProcessor
类型的Bean后置处理器的postProcessBeforeInstantiation、postProcessAfterInitialization方法
⑥ 执行MergedBeanDefinitionPostProcessor类型Bean后置处理器的postProcessMergedBeanDefinition方法
⑦ 执行AbstractAutowireCapableBeanFactory.populateBean(beanName, rootBeanDefinition, beanWrapper)方法,即属性赋值。
在属性赋值之前,首先拿到InstantiationAwareBeanPostProcessor类型的Bean后置处理器,
并执行postProcessAfterInstantiation、postProcessProperties、postProcessPropertyValues方法。
然后才执行该类的applyPropertyValues方法,利用反射调用Bean的setter方法进行属性赋值
⑧ 执行以下三种aware接口的方法:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
⑨ 执行Bean后置处理器的初始化前方法,即BeanPostProcessor.postProcessBeforeInitialization(Object bean, String beanName)
⑩ 执行Bean的初始化方法,即InitializingBean.afterPropertiesSet(),以及在容器中自定义的initMethod
⑪ 执行Bean后置处理器的初始化后方法,即BeanPostProcessor.postProcessAfterInitialization(Object bean, String beanName)
⑫ 如果需要,注册Bean的销毁方法,例如在容器中自定义的destroyMethod。这里只是注册,并不调用
(6) 通过第11(5)步,单实例Bean已经创建并初始化完成,接着,会调用AbstractBeanFactory的父类方法——
DefaultSingletonBeanRegistry.getSingleton(beanName, false)方法,将新建的Bean存入singletonObjects属性中,即缓存
(7) 回到DefaultListableBeanFactory.preInstantiateSingletons()方法(见第11(1)步)
如果新建的Bean实现了SmartInitializingSingleton接口,则执行afterSingletonsInstantiated()回调方法
12. finishRefresh 完成容器刷新
(1) 初始化生命周期处理器(LifecycleProcessor),先从BeanFactory中按类型获取,
如果没有就新建一个DefaultLifecycleProcessor,并注册进BeanFactory
(2) 获取上一步注册的生命周期处理器,回调其onRefresh()方法
(3) 发布容器刷新事件,即ContextRefreshedEvent
BeanFactory
BeanFactory是个Factory:
在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。
它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
BeanFactory只是个接口,并不是IOC容器的具体实现,
Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等。
ApplicationContext接口由BeanFactory接口派生而来,ApplicationContext包含BeanFactory的所有功能,通常建议ApplicationContext优先
FactoryBean
FactoryBean是个特殊的Bean:
FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式。
它是一个能生产或者修饰对象生成的工厂Bean,为IOC容器中bean的实现提供了更加灵活的方式。
它是实现了FactoryBean<T>接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象。