2.spring篇-容器

7 篇文章 0 订阅

1、spring容器

主要由spring-core,spring-beans,spring-context提供容器的支持。

2、ClassPathXmlApplicationContext容器初始化过程

2.1 最简单的使用示例

maven

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.10.RELEASE</version>
        </dependency>

在resources下的spring-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean class="com.User"/>
</beans>

简单使用

package com;
import java.util.UUID;
/**
 * @author yinyuming
 * @date 2021-06-08 11:45
 */
public class User {
    public String name = UUID.randomUUID().toString();
}
public class SpringTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        User user = context.getBean(User.class);
    }
}

2.2 容器初始化流程

2.3 类图

在这里插入图片描述

入口构造

	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
		super(parent);
		setConfigLocations(configLocations);
		//初始化容器,使用父类AbstractApplicationContext的refresh方法实现
		if (refresh) {
			refresh();
		}
	}

2.4 核心抽象类AbstractApplicationContext

核心功能都是由AbstractApplicationContext的refresh方法实现的,其他子类则是实现了父类的一些模板方法。

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
            //  容器预先准备记录容器启动时间和标记  ,模板方法装载配置文件,创建environment并加载System.properties()及System.getenv()到environment中。
            prepareRefresh();    
            
            //  创建bean工程,如果已经有则摧毁,实现了对beanDefinition的装载,拿到Bean工厂的时候,beanDefinition就好了,XmlBeanDefinitionReader来读取所有Bean的定义。
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 
            
            //为Bean工厂做准备, 配置bean工厂的标准上下问特性,如类装载器,postProcesser
            prepareBeanFactory(beanFactory);

			try {
                //模板方法,在bean定义被加载后,提供一个修改容器BeanFactory的入口方法
                postProcessBeanFactory(beanFactory);
                
                // 在bean未开始实例化时,对Bean定义修改的入口,常见的执行bean工厂后处理器BeanFactoryPostProcessor等
                invokeBeanFactoryPostProcessors(beanFactory);
                
                // 注册用于拦截bean创建过程的BeanPostProcessors,(这里会先注册Bean的拦截器,也会调用getBean方法,)
                registerBeanPostProcessors(beanFactory);
                
                // 初始话messageResource消息,
                initMessageSource();
                
                // 初始化上下问时间广播
                initApplicationEventMulticaster();
                
                // 模板方法
                onRefresh();
                
                // 注册监听器
                registerListeners();
                
                //完成容器的初始化,里面preInstaniateSingleons会完成单例对象的创建,核心初始化,实例化所有剩余的非懒加载的单例。
                finishBeanFactoryInitialization(beanFactory);
                
                // Last step: publish corresponding event.
                finishRefresh();
			}

            //摧毁bean容器,
            //....省略
		}
	}

3 Bean的初始化过程(AbstractApplicationContext.getBean())

3.1 Bean的声明周期

以下是 org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean的一些核心流程

  • 1、getSingleton获取单例,(3级缓存),SingletonFactories:单例对象工厂cache,earlySingletonObject,提前暴露的单例对象cache,singleObject,单例对象的
  • 2、没有bean,就从objectFactory的获取bean,调用createBean创建实例,
  • 3、createBean执行instantiateBean初始化
  • 4、createBeanInstance生成实例
  • 5、addSingletonFactory提前暴露给spring的object工厂,缓存
  • 6、populateBean填充属性, (初始化后就是设置属性,会执行各种aware,切入织面的Bean后处理器)
  • 7、Bean拦截器,Bean实例话之后postProcessAfterInstantiation,返回false,不设置属性
  • 8、处理autowire,依赖注入,使用getBean,继续递归获取Bean
  • 9、Bean后处理器,postProcessPropertyValues, 可以处理属性值
  • 10、applyPropertyValues最后把收集到的MutablePropertyValues注入到bean实例上
  • 11、填充完属性,初始化方法,initializeBean,
  • 12、(initializeBean)invokeAwareMethods处理核心aware接口,BeanNameAware,BeanClassLoaderAware,BeanFactoryAware
  • 13、(initializeBean)applyBeanPostProcessorsBeforeInitialization执行后处理器postProcessBeforeInitialization(@PostConstruct的实现也是在这里处理的,InitDestroyAnnotationBeanPostProcessor)
  • 14、 (initializeBean)invokeInitMethods,执行InitializingBean,invokeCustomInitMethod(执行自定义的初始化方法,如xml配置的init-method)
  • 15、(initializeBean)postProcessAfterInitialization 后处理器
  • 16、bean摧毁

3.2 bean的构造函数选择

以下是一些核心流程,源码位置:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

  • 1、选择BeanDefinition的InstanceSupplier
  • 2、选择BeanDefinition的FactoryMethodName(xml中配置factory-method属性)
  • 3、走SmartInstantiationAwareBeanPostProcessor切入类获取构造函数,
    (@Autowired注解构造函数处理,通过切入类AutowiredAnnotationBeanPostProcessor的determineCandidateConstructors,获取有注解的构造函数,确认返回的构造函数,如果有两个Autowired注解会报错 )
  • 4、选择clazz.getDeclaredConstructor()默认构造函数

3.3 bean的初始化过程切入类BeanPostProcessor

  • BeanPostProcessor:初始化方法前后切入
  • DestructionAwareBeanPostProcessor:摧毁前切入
  • SmartInstantiationAwareBeanPostProcessor:构造重写,切入bean工厂或则返回指定的构造函数构造
  • MergedBeanDefinitionPostProcessor:构造后收集属性,用于收集bean和beanDefinition
    比如:AutowiredAnnotationBeanPostProcessor就是MergedBeanDefinitionPostProcessor收集属性,然后注入属性时,通过收集的属性注入

3.4 bean初始化循环依赖的处理

  • 构造函数循环依赖
    不支持
  • 属性注入循环依赖,通过三级缓存解决循环依赖

Spring通过三级缓存解决了循环依赖,其中一级缓存为单例池(singletonObjects),二级缓存为早期曝光对象earlySingletonObjects,三级缓存为早期曝光对象工厂(singletonFactories)。
当A、B两个类发生循环引用时,在A完成实例化后,就使用实例化后的对象去创建一个对象工厂,并添加到三级缓存中,如果A被AOP代理,那么通过这个工厂获取到的就是A代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化的对象。当A进行属性注入时,会去创建B,同时B又依赖了A,所以创建B的同时又会去调用getBean(a)来获取需要的依赖,此时的getBean(a)会从缓存中获取,第一步,先获取到三级缓存中的工厂;第二步,调用对象工工厂的getObject方法来获取到对应的对象,得到这个对象后将其注入到B中。紧接着B会走完它的生命周期流程,包括初始化、后置处理器等。当B创建完后,会将B再注入到A中,此时A再完成它的整个生命周期。至此,循环依赖结束!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值