【spring源码系列-02】通过refresh方法剖析IOC的整体流程

news2024/11/24 3:00:17

Spring源码系列整体栏目


内容链接地址
【一】spring源码整体概述https://blog.csdn.net/zhenghuishengq/article/details/130940885
【一】通过refresh方法剖析IOC的整体流程https://blog.csdn.net/zhenghuishengq/article/details/131003428

spring底层源码整体概述

  • 一,通过refresh方法剖析IOC的整体流程
    • 1,prepareRefresh()
    • 2,obtainFreshBeanFactory()
    • 3,prepareBeanFactory()
    • 4,postProcessBeanFactory()
    • 5,invokeBeanFactoryPostProcessors()
    • 6,registerBeanPostProcessors()
    • 7,initMessageSource()
    • 8,initApplicationEventMulticaster
    • 9,onRefresh()
    • 10,registerListeners()
    • 11,finishBeanFactoryInitialization(重点)
      • 11.1,dogetbean方法的粗略总结如下:
      • 11.2,doCreateBean方法粗略总结如下(重点)
    • 12,finishRefresh()
    • 13,总结

一,通过refresh方法剖析IOC的整体流程

在上一篇中,已经粗略的谈了一下springIOC的整体执行流程,接下来通过源码的方式,深度的剖析底层的执行逻辑,这里依旧是针对IOC的底层实现,在对IOC有一定的了解之后,再研究AOP。

在这里插入图片描述

因此通过内部代码来查看容器的具体流程,这里主要研究的就是这个 refresh() 方法,无论是通过注解的方式还是通过XML的方式,都可以在获取上下文之后看到这个refresh方法,这里以xml的方式为例

ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/a.xml");
ctx.getBean("user");

接下来查看这个ClassPathXmlApplicationContext 这个实现类,主要就是初始化父类,加载资源,获取xml路径以及解析xml文件,最后再调用这个最终的refresh 方法。

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)throws BeansException {
    // 初始化父类 ,获得xml路径资源解析器
	super(parent);  
    // 通过环境变量解析 xml路径,如加载上面的a.xml
	setConfigLocations(configLocations);  
	if (refresh) {
        // 这个方法时spring是最重要的一个方法,甚至体系整个ioc的声明周期
		refresh();   
	}
}

接下来就是进入这个最重要的refresh 方法,如下,每个方法有详细的注释。把这个refresh中的10多个方法吃透,spring源码基本上就没多大问题了。

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		//1:准备刷新上下文环境
		prepareRefresh();
		//2:获取告诉子类初始化Bean工厂,不同工厂有不同的实现
        //  并且将配置文件的属性值加载到当前工厂中
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		//3:对bean工厂进行填充属性
		prepareBeanFactory(beanFactory);
		try {
			// 第四:留个子类去实现该接口,bean工厂的后置处理器
			postProcessBeanFactory(beanFactory);
			// 调用我们的bean工厂的后置处理器. 
       	 	//1. 会在此将class扫描成beanDefinition  2.bean工厂的后置处理器调用
			invokeBeanFactoryPostProcessors(beanFactory);
			// 注册我们bean的后置处理器
			registerBeanPostProcessors(beanFactory);
			// 初始化国际化资源处理器.
			initMessageSource();
			// 创建事件多播器
			initApplicationEventMulticaster();
			// 这个方法同样也是留个子类实现的springboot也是从这个方法进行启动tomcat的.
			onRefresh();
			//把我们的事件监听器注册到多播器上
			registerListeners();
			// 实例化我们剩余的单实例bean.
			finishBeanFactoryInitialization(beanFactory);
			// 最后容器刷新 发布刷新事件(Spring cloud也是从这里启动的)
			finishRefresh();
		}
    }
}

1,prepareRefresh()

在刷新上下文之前,有一个准备阶段

protected void prepareRefresh() {
    //设置基础环境标志
	this.closed.set(false);
	this.active.set(true);
    //初始化属性资源,留给子类实现的方法
   	initPropertySources();
    //用来校验我们容器启动必须依赖的环境变量的值
	getEnvironment().validateRequiredProperties();
    //创建一个早期事件监听器对象
	if (this.Listeners == null) {
		this.Listeners = new LinkedHashSet<>(this.applicationListeners);
    }else {
		// Reset local application listeners to pre-refresh state.
		this.applicationListeners.clear();
		this.applicationListeners.addAll(this.earlyApplicationListeners);
	}
}

在这个initPropertySources() 方法中,比如我们自己写一个类重写了该方法,在该方法中设置了一个环境变量的值为test,启动的时候,我的环境变量中没有test值就会启动抛出异常

initPropertySources();

而在这个getEnvironment 方法中,其获取所有的环境变量相对来说比较复杂,在获取这个环境变量时需要先创建一个环境变量

this.environment = createEnvironment()//创建环境变量
protected ConfigurableEnvironment createEnvironment() {
	return new StandardEnvironment();
}

而在这个StandardEnvironment对象中,需要继承这个AbstractEnvironment父类,那么就需要先加载父类中的变量和属性,如一些System系统变量,属性等

public class StandardEnvironment extends AbstractEnvironment {
		/** System environment property source name: {@value} */
	public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";

	/** JVM system properties property source name: {@value} */
	public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
    
    	@Override
	protected void customizePropertySources(MutablePropertySources propertySources) {
		propertySources.addLast(
				new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
		propertySources.addLast(
				new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
	}
}

该阶段主要是设置一些环境变量标志,获取当前环境对象,并设置环境属性的值,设置监听器和发布事件的值。

2,obtainFreshBeanFactory()

在准备阶段获取到环境变量之后,接下来就是创建一个bean工厂。在这个Bean工厂中,有两个核心的bean工厂,分别是ListableBeanFactoryConfigurableBeanFactory ,同时还需要了解一个重要的bean工厂:DefaultListableBeanFactory

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uEgoZboW-1685675724475)(img/1685349251639.png)]

在初始化这个bean工厂对象的时候,会调用这个obtainFreshBeanFactory方法

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

//获取刷新的bean工厂
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    //刷新bean工厂,有则销毁,无则创建新的
	refreshBeanFactory();
	//返回我们的bean工厂
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	return beanFactory;
}

在refreshBeanFactory刷新bean工厂中,就是创建了这个默认的bean工厂,而上下文创建的这个bean工厂,正是上面图片最底部的DefaultListableBeanFactory 对象,这里就获取到了bean工厂

protected DefaultListableBeanFactory createBeanFactory() {
    //创建默认的bean工厂
	return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

在创建这个bean工厂之后,就会为这个bean工厂赋予默认值,并且loadBeanDefinitions是加载bean定义的阶段,其流程非常复杂,后续会重点讲解接在bean定义的过程。

/**
 * 为我们的Spring应用上下文对象创建我们的beanFactory
 */
DefaultListableBeanFactory beanFactory = createBeanFactory();
//为容器设置一个序列化ID
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
//加载bean定义
loadBeanDefinitions(beanFactory);

加载完这个bean定义之后,会将这beanDefinition加入到beanDefinitionMap中,每一个bean定义中会有对应的具体的属性。

3,prepareBeanFactory()

在上一阶段创建了一个bean工厂,并且将配置文件解析成bean定义,然后将全部的bean定义加载到了工厂里面。接下来这一步就是为bean工厂进行一些属性填充,如设置一些类加载器,对象解析器,后置处理器等等

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	//设置bean工厂的类加载器为当前application应用的加载器
	beanFactory.setBeanClassLoader(getClassLoader());
	//为bean工厂设置我们标准的SPEL表达式解析器对象StandardBeanExpressionResolver
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	//为我们的bean工厂设置了一个propertityEditor 属性资源编辑器对象(用于后面的给bean对象赋值使用)
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
	//后置处理器用来处理ApplicationContextAware接口的回调方法
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
	
    ...
}

除了设置上面这些,还有设置一些忽略的依赖或者接口等

beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

最后就是注册一些工厂内部的bean,如一些环境,环境系统属性等

//环境
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
...

4,postProcessBeanFactory()

该方法是用于执行一些后置处理器的相关操作,该方法里面是一个空方法,相当于定义一个模板,留给子类做具体的实现。主要是用于子类做扩展实现

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	
}

5,invokeBeanFactoryPostProcessors()

顾名思义,就是用于执行bean工厂的后置处理器,在这里就可以执行修改bean定义的操作。通过这个方法上面的注释也可以知道,就是用于实例化和注册全部的bean工厂的后置处理器,并且必须在单例对象的初始化之前。在此步会将class扫描成beanDefinition。

/**
 * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
 * respecting explicit order if given.
 * <p>Must be called before singleton instantiation.
 */
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    
}

在这个invokeBeanFactoryPostProcessors 类中,主要就是根据不同的优先级进行一个对应的加载

public static void invokeBeanFactoryPostProcessors(...){
    if (beanFactory instanceof BeanDefinitionRegistry){
        ...
    }
}

6,registerBeanPostProcessors()

第六步,就是注册bean的后置处理器。在bean工厂中,在初始化前后,可以调用bean的后置处理器,因此需要在使用前提前注册bean的后置处理器。

// 注册bean的后置处理器
registerBeanPostProcessors(beanFactory);

其注册的流程如下,通过下面的注释也可以知道,就是初始化和注册全部的bean后置处理器

/**
 * Instantiate and register all BeanPostProcessor beans,
 * respecting explicit order if given.
 * <p>Must be called before any instantiation of application beans.
 */
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory factory) {
    registerBeanPostProcessors(...);
}

bean的后置处理器,在bean的整个生命周期都会进行调用,如aop的实现,@ConditionalOnClass条件的使用等

public static void registerBeanPostProcessors(...){
	
}

7,initMessageSource()

除了注册这个bean工厂的后置处理器之外,还会进行国际化的初始操作

	protected void initMessageSource() {
		//获取Bean工厂,一般是DefaultListBeanFactory
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		//首先判断是否已有xml文件定义了id为messageSource的bean对象
		if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
			//如果有,则从Bean工厂得到这个bean对象
			this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
			// Make MessageSource aware of parent MessageSource.
			//当父类Bean工厂不为空,并且这个bean对象是HierarchicalMessageSource类型
			if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
				//为HierarchicalMessageSource的实现类
				HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
				//设置父类MessageSource,此处设置内部的parent messageSource
				if (hms.getParentMessageSource() == null) {
					// Only set parent context as parent MessageSource if no parent MessageSource
					// registered already.
					hms.setParentMessageSource(getInternalParentMessageSource());
				}
			}
			if (logger.isTraceEnabled()) {
				logger.trace("Using MessageSource [" + this.messageSource + "]");
			}
		}
		else {
			// Use empty MessageSource to be able to accept getMessage calls.
			//如果没有xml文件定义信息源对象,新建DelegatingMessageSource类作为messageSource的Bean
			//因为DelegatingMessageSource类实现了HierarchicalMessageSource接口,而这个接口继承了MessageSource这个类
			//因此实现了这个接口的类,都是MessageSource的子类,因此DelegatingMessageSource也是一个MessageSource
			DelegatingMessageSource dms = new DelegatingMessageSource();
			//给这个DelegatingMessageSource添加父类消息源
			dms.setParentMessageSource(getInternalParentMessageSource());
			this.messageSource = dms;
			//将这个messageSource实例注册到Bean工厂中
			beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
			if (logger.isTraceEnabled()) {
				logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
			}
		}
	}

8,initApplicationEventMulticaster

国际化之后还需要初始化应用程序事件的多播器,就是说从bean工厂中获取或者直接显示的new一个多播器赋值给我们的applicatoinContext对象

	protected void initApplicationEventMulticaster() {
		//获取我们的bean工厂对象
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		//判断容器中是没有有我们的applicationEventMulticaster 应用多播器组件
		if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
			//直接显示的调用我们的getBean获取出来赋值给我们的applicationContext对象
			this.applicationEventMulticaster =
					beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
			}
		}
		//容器中没有的话
		else {
			//spring ioc显示的new 一个SimpleApplicationEventMulticaster对象保存在applicatoinContext对象中
			this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
			//并且注入到容器中
			beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
		}
	}

9,onRefresh()

这个方法也是留给子类去具体实现

protected void onRefresh() throws BeansException {
	// For subclasses: do nothing by default.
}

10,registerListeners()

把事件的监听器注册到多播器上面

protected void registerListeners() {
	//获取容器中所有的监听器对象
	// 这个时候正常流程是不会有监听器的
	// (因为监听器不会在这之前注册,在initApplicationEventMulticaster后在registerListeners之前,只有一个可能在:在onRefresh里面注册了监听器)
	for (ApplicationListener << ? > listener : getApplicationListeners()) {
		//把监听器挨个的注册到我们的多播器上去
		getApplicationEventMulticaster().addApplicationListener(listener);
	}

	//获取bean定义中的监听器对象
	String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
	//把监听器的名称注册到我们的多播器上
	for (String listenerBeanName: listenerBeanNames) {
		getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
	}

	//在这里获取我们的早期事件
	Set < ApplicationEvent > earlyEventsToProcess = this.earlyApplicationEvents;
	// 在这里赋null。  也就是值此之后都将没有早期事件了
	this.earlyApplicationEvents = null;
	if (earlyEventsToProcess != null) {
		//通过多播器进行播发早期事件
		for (ApplicationEvent earlyEvent: earlyEventsToProcess) {
			getApplicationEventMulticaster().multicastEvent(earlyEvent);
		}
	}
}

至此,所有的准备工作就完成了。接下来就是通过bean工厂去创建个获取实例对象了。

11,finishBeanFactoryInitialization(重点)

在这一阶段,主要就是完成bean工厂要完成的事情,如实例化,属性填充和初始化等。如下图,里面主要是创建一些bean工厂类型的转换器,以及处理一些aspectj,实例化剩余的懒加载单例bean对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ORyJsjgz-1685675724475)(img/1685594647873.png)]

而在这里面最重要的就是最后这个preInstantiateSingletons 实例化剩余的单例bean,在spring中,几乎所有的bean都是在这一步生成的。这里主要就是获取全部bean定义的名称,然后遍历这些名称,然后再合并这些bean定义,成为一个RootBean。最后判断这个RootBean是不是抽象的、类加载的或者单例的等

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SyW9bi1N-1685675724476)(img/1685595044271.png)]

最终会调用一个getBean 方法,去真正的执行这个获取bean的流程。

/**
 * 该方法是一个空壳方法,没有任何的实现逻辑 真正的逻辑调用在doGetBean()中
 * 该接口是实现了BeanFactory的getBean(String name)接口
 */
@Override
public Object getBean(String name) throws BeansException {
	//真正的获取bean的逻辑
	return doGetBean(name, null, null, false);
}

而真正的获取这个bean的逻辑,正是这个 doGetBean 方法,这个方法的内容真的超级多。

/**
 * 返回bean的实例,该实例可能是单例bean 也有可能是原型的bean
 * @param name bean的名称 也有可能是bean的别名
 * @param requiredType 需要获取bean的类型
 * @param args 通过该参数传递进来,到调用构造方法时候发现有多个构造方法,我们就可以通过该参数来指定想要的构造方法了
 *             不需要去推断构造方法(因为推断构造方法很耗时)
 * @param typeCheckOnly 判断当前的bean是不是一个检查类型的bean 这类型用的很少.
 * @return 返回一个bean实例
 * @throws BeansException 如何bean不能被创建 那么就回抛出异常
 */
@SuppressWarnings("unchecked")
protected < T > T doGetBean(final String name, @Nullable final Class < T > requiredType,
	@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

	/**
	 * 在这里 传入进来的name 可能是 别名, 也有可能是工厂bean的name,所以在这里需要转换
	 */
	final String beanName = transformedBeanName(name);
	Object bean;

	//尝试去缓存中获取对象,一级二级三级缓存中查找
	Object sharedInstance = getSingleton(beanName);

	if (sharedInstance != null && args == null) {
		/**
		 * /*
		 * 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。但如果
		 * sharedInstance 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的
		 * bean 实例。如果用户想获取 FactoryBean 本身,这里也不会做特别的处理,直接返回
		 * 即可。毕竟 FactoryBean 的实现类本身也是一种 bean,只不过具有一点特殊的功能而已。
		 */
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	} else {

		/**
		 * spring 只能解决单例对象的setter 注入的循环依赖,不能解决构造器注入
		 */
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}

		/**
		 * 判断AbstractBeanFacotry工厂是否有父工厂(一般情况下是没有父工厂因为abstractBeanFactory直接是抽象类,不存在父工厂)
		 * 一般情况下,只有Spring 和SpringMvc整合的时才会有父子容器的概念,
		 * 比如我们的Controller中注入Service的时候,发现我们依赖的是一个引用对象,那么他就会调用getBean去把service找出来
		 * 但是当前所在的容器是web子容器,那么就会在这里的 先去父容器找
		 */
		BeanFactory parentBeanFactory = getParentBeanFactory();
		//若存在父工厂,切当前的bean工厂不存在当前的bean定义,那么bean定义是存在于父beanFacotry中
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			//获取bean的原始名称
			String nameToLookup = originalBeanName(name);
			//若为 AbstractBeanFactory 类型,委托父类处理
			if (parentBeanFactory instanceof AbstractBeanFactory) {
				return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
					nameToLookup, requiredType, args, typeCheckOnly);
			} else if (args != null) {
				//  委托给构造函数 getBean() 处理
				return (T) parentBeanFactory.getBean(nameToLookup, args);
			} else {
				// 没有 args,委托给标准的 getBean() 处理
				return parentBeanFactory.getBean(nameToLookup, requiredType);
			}
		}

		/**
		 * 方法参数 typeCheckOnly ,是用来判断调用 #getBean(...) 方法时,表示是否为仅仅进行类型检查获取 Bean 对象
		 * 如果不是仅仅做类型检查,而是创建 Bean 对象,则需要调用 #markBeanAsCreated(String beanName) 方法,进行记录
		 */
		if (!typeCheckOnly) {
			markBeanAsCreated(beanName);
		}

		try {
		
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			//检查当前创建的bean定义是不是抽象的bean定义
			checkMergedBeanDefinition(mbd, beanName, args);
			//依赖bean的名称
			String[] dependsOn = mbd.getDependsOn();
			if (dependsOn != null) {
				// <1> 若给定的依赖 bean 已经注册为依赖给定的 bean
				// 即循环依赖的情况,抛出 BeanCreationException 异常
				for (String dep: dependsOn) {
					//beanName是当前正在创建的bean,dep是正在创建的bean的依赖的bean的名称
					if (isDependent(beanName, dep)) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
					}
					//保存的是依赖 beanName 之间的映射关系:依赖 beanName - > beanName 的集合
					registerDependentBean(dep, beanName);
					try {
						//获取depentceOn的bean
						getBean(dep);
					} catch (NoSuchBeanDefinitionException ex) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
					}
				}
			}

			//创建单例bean
			if (mbd.isSingleton()) {
				//把beanName 和一个singletonFactory 并且传入一个回调对象用于回调
				sharedInstance = getSingleton(beanName, () - > {
					try {
						//进入创建bean的逻辑
						return createBean(beanName, mbd, args);
					} catch (BeansException ex) {
						//创建bean的过程中发生异常,需要销毁关于当前bean的所有信息
						destroySingleton(beanName);
						throw ex;
					}
				});
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			} else if (mbd.isPrototype()) {
				// It's a prototype -> create a new instance.
				Object prototypeInstance = null;
				try {
					beforePrototypeCreation(beanName);
					prototypeInstance = createBean(beanName, mbd, args);
				} finally {
					afterPrototypeCreation(beanName);
				}
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			} else {
				String scopeName = mbd.getScope();
				final Scope scope = this.scopes.get(scopeName);
				if (scope == null) {
					throw new IllegalStateException();
				}
				try {
					Object scopedInstance = scope.get(beanName, () - > {
						beforePrototypeCreation(beanName);
						try {
							return createBean(beanName, mbd, args);
						} finally {
							afterPrototypeCreation(beanName);
						}
					});
					bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
				} catch (IllegalStateException ex) {
					
				}
			}
		} catch (BeansException ex) {
			cleanupAfterBeanCreationFailure(beanName);
			throw ex;
		}
	}

	// Check if required type matches the type of the actual bean instance.
	if (requiredType != null && !requiredType.isInstance(bean)) {
		try {
			T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
			if (convertedBean == null) {
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
			return convertedBean;
		} catch (TypeMismatchException ex) {
			if (logger.isDebugEnabled()) {
					ClassUtils.getQualifiedName(requiredType) + "'", ex);
			}
			throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
		}
	}
	return (T) bean;
}

11.1,dogetbean方法的粗略总结如下:

1,首先获取bean的名字beanName,随后根据名字先尝试去一级缓存中获取

final String beanName = transformedBeanName(name);
getSingleton(beanName);

2,如果缓存中没有获取到这个实例,则继续往下判断。如果是单例对象,则先解决循环依赖问题,如果是原型模式下也存在循环依赖,则直接抛出异常

if (isPrototypeCurrentlyInCreation(beanName)) {
	throw new BeanCurrentlyInCreationException(beanName);
}

3,接下来再判断当前工厂是否有父工厂,正常情况是没有,因为AbstractBeanFacotry是一个抽象类。只有在spring和springMVC 中才会出现父子容器的概念

getParentBeanFactory()

4,随后再获取beanDefinition,并检查当前的bean定义是不是抽象的,随后再判断当前bean是否存在依赖的bean,如果存在,则获取依赖bean的实例

final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//检查当前创建的bean定义是不是抽象的bean定义
checkMergedBeanDefinition(mbd, beanName, args);
//随后在判断当前bean是否存在依赖的bean
String[] dependsOn = mbd.getDependsOn();

5,最后会判断一下获取到的beanDefinition是单例的还是原型的,如果是单例的bean定义则获取单例的bean对象,如果是一个原型的bean定义则获取一个原型的bean对象

if (mbd.isSingleton()) {
    getSingleton(String beanName, ObjectFactory<?> singletonFactory)createBean(beanName, mbd, args)}else if (mbd.isPrototype()) {
    prototypeInstance = createBean(beanName, mbd, args);
}else {
    ...
}

以单例模式为例,getSingleton 获取实例的流程主要如下

在这里插入图片描述

先从一级缓存的单例池中获取对象

//尝试从一级缓存的单例缓存池中获取对象
Object singletonObject = this.singletonObjects.get(beanName);

如果从一级缓存中获取对象失败,则会标记该对象需要被创建,随后创建bean,最后加入到一级缓存中。

//如果获取对象失败,标记当前的bean马上就要被创建了
beforeSingletonCreation(beanName);
//初始化bean,这个过程其实是调用 createBean() 方法
singletonObject = singletonFactory.getObject();
//将标记移除
afterSingletonCreation(beanName);
//加入到一级缓存中
addSingleton(beanName, singletonObject);

其主要方法是 singletonFactory.getObject() ,其内部就是调用了一个 createBean() 方法,在createBean() 方法中,其核心方法就是 doCreateBean 方法,该方法才是真正的创建bean对象的方法。在这个真正的去创建bean的方法中,其内容也超级多,这一步包含了 调用构造方法,给对象的属性赋值,初始化操作以及生成代理对象。最后将获取到的对象返回

protected Object doCreateBean(...) throws BeanCreationException {
	...
}

再拿到这个bean的实例对象之后,就会做一个后置处理操作,将正在创建的bean从容器中删除

//主要做的事情就是把singletonsCurrentlyInCreation标记正在创建的bean从集合中移除
afterSingletonCreation(beanName);

最后,将这个实例对象加入到一级缓存的单例池中

addSingleton(beanName, singletonObject);

6,判断当前bean是普通bean还是FactoryBean

bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd)

7,至此,整个finishBeanFactoryInitialization 的流程结束。

11.2,doCreateBean方法粗略总结如下(重点)

1,第一步就是实例化一个对象,通过反射的方式实例化一个对象,可以通过构造器的方式等

//创建bean实例化,工厂方法、构造函数自动注入、简单初始化
instanceWrapper = createBeanInstance(beanName, mbd, args);

2,在实例化之后,会有一个调用后置处理器的操作,主要用来解析一些 @AutoWired @Value等注解

//进行后置处理 @AutoWired @Value的注解的预解析
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);

3,解决循环依赖问题,允许提前暴露实例化的对象,其属性值为默认值。就是将这个实例化的对象存入到三级缓存中,

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

4,这一步就是给实例化的对象进行属性填充 ,主要针对的是setter对象,这里就会将默认值变为具体的值

//属性赋值 给我们的属性进行赋值(调用set方法进行赋值)
populateBean(beanName, mbd, instanceWrapper);

而属性注入有两种方式,一种是通过名称方式注入,一种是通过类型的方式注入

//根据bean的属性名称注入
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
	autowireByName(beanName, mbd, bw, newPvs);
}
//根据bean的类型进行注入
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
	autowireByType(beanName, mbd, bw, newPvs);
}

6,属性填充之后就是初始化的操作

//进行对象初始化操作(在这里可能生成代理对象)
exposedObject = initializeBean(beanName, exposedObject, mbd);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J6QBqdVU-1685675724477)(img/1685671327056.png)]

在初始化对象之前,会去判断该对象是否实现了XXXaware 接口,以及调用bean的后置处理器的方法,再调用初始化方法 进行初始化,最后又会调用bean的后置处理器的后置方法

protected Object initializeBean(...) {
    //若我们的bean实现了XXXAware接口进行方法的回调
    invokeAwareMethods(beanName, bean);
    //调用我们的bean的后置处理器的前置方法
    //@PostCust注解的方法
    applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    //调用初始化方法
	invokeInitMethods(beanName, wrappedBean, mbd);
    //调用bean的后置处理器的后置方法
    applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

其步骤和上篇谈的bean工厂获取对象的步骤是一模一样的

在这里插入图片描述

7,到此为止,就是获取到了一个完整的实例对象,就可以将这个实例对象给返回了。

12,finishRefresh()

最后一步,就是最后容器刷新,发布刷新事件。如一些清除缓存,声明处理器,发布事件等等。

在这里插入图片描述

13,总结

从整个spring流程的源码分析来看,主要就是先读取配置文件,然后获取和设置一些环境变量,再初始化bean工厂,然后将读取到的文件读取到容器中,将这些配置文件先生成一个统一beanDifinition,期间也可以通过bean定义的后置处理器去修改这些生成的beandifinition,随后判断这些bean定义是单例的还是原型的,单例的通过bean工厂创建单例的对象,原型的创建原型的对象,bean工厂默认为DefaultListAbleBeanFactory,通过调用getbean方法从一级缓存中获取对象,如果获取失败,则进行一些实例化,属性填充,初始化的操作,期间会去实现Aware属性,bean的后置处理器等等,然后生成一个完整的对象,随后会将这个对象再加入到一级缓存中,再创建对象完成之后,就会去刷新容器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/601253.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2个实际工作中的小技巧,先收再看(网工版)

大家好&#xff0c;我是老杨。 本来想发点关于快乐的文章&#xff0c;但我思来想去&#xff0c;对成年人最大的快乐&#xff0c;莫过于高效完成工作&#xff0c;早点下班回家。 关于提升工作效率这方面啊&#xff0c;我的文章其实零碎、分散的写过了很多次了。 你要知道&…

ChatGPT国内免费使用地址和开源公众号集成项目分享

ChatGPT国内免费使用地址和开源公众号集成项目分享 ChatGPT国内免费使用地址ChatGPT开源公众号集成项目ChatGPT国内免费调用API的地址总结免费体验地址 人工智能技术的快速发展&#xff0c;ChatGPT聊天机器人备受瞩目。然而&#xff0c;如何在国内免费使用ChatGPT却是许多人关注…

手绘echarts散点图

面对各种定制&#xff0c;echarts图表有时候不好处理&#xff0c;无论是数据处理还是样式处理&#xff0c;都会被echarts限制。 举例&#xff1a;echarts散点图如果数据较少&#xff0c;echarts会均匀分布&#xff0c;如图1 对于产品或者老板对页面的要求&#xff0c;认为中间…

ROS2中,从SolidWorks导出的urdf,联合moveit、gazebo进行控制及仿真

文章目录 1.前言2.从urdf到moveit3.从urdf到gazebo3.1.urdf文件的修改3.1.1.mesh路径3.1.2.零件起飞3.1.3.文件保存 3.2.xacro文件的修改3.3.launch 4.用moveit控制gazebo5.结语 1.前言 本文是对之前发的文章【在ROS2中&#xff0c;通过MoveIt2控制Gazebo中的自定义机械手】的…

C 语言详细教程

目录 第一章 C语言基础知识 第二章 数据类型、运算符和表达式 第三章 结构化程序设计 第四章 数组 第五章 函数 第六章 指针 第七章 结构体类型和自定义类型 第八章 编译预处理 第九章 文件 说明&#xff1a;本教程中的代码除一二三个之外&#xff0c;都在https://ligh…

尝试理解卷积神经和深度学习的关系,并且怎么使用

前言 最近想要了解卷积神经和深度学习,才发现并不是我想象中的简单,也不是我想象中的难.我想的难是指没有任何思路:不知道这是个什么玩意,里面的流程是不是很难,我想的简单就是:也就是用人家的包,全都是用来导包,我只需要知道这个包是怎么用的,从来没想过自己怎么开发出来一个依…

Python splitlines() 的使用

Python splitlines() 的作用 Python splitlines() 按照行(\r, \r\n, \n)分隔&#xff0c;返回一个包含各行作为元素的列表 Python splitlines()的注意事项 splitlines小括号里面的参数没有的时候,默认按照行(\r, \r\n, \n)分隔不带这些特殊的字符 如果这样splitlines(True)…

ISO21434 概述(一)

目录 一、ISO21434 1.1 目的 1.2 ISO21434文档组织结构 二、适用范围 三、引用标准 四、术语和缩写 4.1 术语 4.2 缩写 五、一般考虑 一、ISO21434 1.1 目的 本文件阐述了道路车辆内电气和电子&#xff08;E/E&#xff09;系统工程中的网络安全问题。通过确保对网络安…

Ansible的配置、主机清单、Ansible的脚本Playbook详解

文章目录 Ansible的配置配置文件 主机清单远程主机的分组变量 Ansible的脚本PlaybookPlaybook的文件格式YAMLansible-playbook的命令Playbook的基本语法变量 Ansible的配置 配置文件 Ansible是一款功能强大的自动化工具&#xff0c;可以实现对远程主机的管理和操作&#xff0…

华为认证 | HCIA-Datacom 考试大纲

今天给大家说点基础的&#xff0c;很多人对华为认证考试有了一定了解后&#xff0c;想要进一步了解具体的考试内容。 这篇先说HCIA-Datacom的具体考试大纲~ 01 华为HCIA-Datacom认证考试 02 华为HCIA-Datacom考试内容 HCIA-Datacom V1.0考试覆盖数通基础知识&#xff0c;包括&…

java 中的动态代理实现

1. 什么是代理模式 代理模式是常见的设计模式之一&#xff0c;顾名思义&#xff0c;代理模式就是代理对象具备真实对象的功能&#xff0c;并代替真实对象完成相应操作&#xff0c;并能够在操作执行的前后&#xff0c;对操作进行增强处理。&#xff08;为真实对象提供代理&…

表格软件有哪些?热门表格软件推荐

作为报表开发人员&#xff0c;我们经常需要使用各种表格软件来处理数据并生成清晰、易读的报表。在市面上&#xff0c;有许多不同类型的表格软件可供选择。下面我将列举7款热门的表格软件&#xff0c;并详细介绍其中一款优秀的软件—VeryReport。 编辑搜图 请点击输入图片描述…

Qt6.5.1+WebRTC学习笔记(九)运行官方示例(win10+vs2019)

前言 webrtc源码目录下&#xff0c;有个examples目录&#xff0c;里面放置着官方的示例&#xff0c;其有peerconnection示例。 一、问题 peerconnection示例分客户端和服务端&#xff0c;以win系统为例&#xff0c;编译后会在输出目录生成两个可执行文件 服务端程序可以正常…

【基于GD32E230的定时器级联M/T法电机测速】

前言 在有感电机控制中&#xff0c;获取电机转速是非常重要的步骤&#xff0c;转速获取越准确&#xff0c;控制电机时越方便&#xff0c;抛开霍尔不谈&#xff0c;这里讨论电机编码器。 目前常见的电机编码器按种类分为绝对值编码器和增量编码器&#xff0c;绝对值编码器相对…

厚积薄发,AR光学方案商光舟半导体于AWE 2023首次公开亮相

青亭网6月2日报道&#xff0c;国内AR光波导技术厂商“光舟半导体”&#xff08;深圳市光舟半导体技术有限公司&#xff09;在AWE 2023首次公开亮相&#xff0c;并展示了最新的AR光波导模组、光机/光引擎、汽车HUD三大产品。 光舟半导体成立于2020年1月&#xff0c;公司由AR光学…

5.8 几个常见JavaScript图表库

几个常见JavaScript图表库 目录1、 Chart.js2、 Chartist.js3、 Highcharts.js4、 D3.js5、 Plotly.js6、 ECharts.js7、 Google Charts8、Other Charts 目录 1、 Chart.js 官方网站&#xff1a; www.chartjs.org Chart.js 是一个基于 HTML5 Canvas 的 JavaScript 图表库&…

Day59【单调栈】503.下一个更大元素II、42.接雨水

503.下一个更大元素II 力扣题目链接/文章讲解 视频讲解 本题和739.每日温度很相似&#xff0c;只不过是循环数组 一种处理循环的方式是&#xff0c;直接把两个数组拼接在一起&#xff0c;然后使用单调栈求下一个最大值 class Solution { public:vector<int> nextGre…

【JUC基础】13. 线程池(二)

目录 1、前言 2、Java实现线程池 2.1、Executors框架 2.2、newFixedThreadPool 2.3、newCachedThreadPool 2.4、newSingleThreadExecutor 2.5、newScheduledThreadPool 2.5.1、scheduleAtFixedRate 2.5.2、scheduleWithFixedDelay 2.5.3、异常中断 3、execute()和sub…

大数据挖掘企业服务平台(TipDM大数据挖掘建模平台)-快速构建数据挖掘工程

“TipDM大数据挖掘建模平台”&#xff08;以下简称平台&#xff09;是由广东泰迪智能科技股份有限公司自主研发&#xff0c;基于Python引擎的数据挖掘建模平台。使用平台配置的开箱即用的算法组件&#xff0c;用户可在没有编程基础的情况下&#xff0c;通过拖拽的方式进行操作&…

蓝牙规范系列--经典蓝牙概述(第一篇)

一、目的 从本篇开始介绍经典蓝牙的基础知识&#xff0c;内容较多故会分成多篇进行介绍。 经典蓝牙&#xff08;BR/EBR&#xff09;射频&#xff08;物理层PHY&#xff09;工作在免授权的2.4G ISM频段&#xff08;2400 - 2483.5 MHz&#xff09;&#xff0c;使用跳频技术来对抗…