通过springboot autoconfig分析bean实例化过程的案例

分析案例前提所参考的例子,Spring Boot中的自定义start pomSpringBoot学习笔记(3) Spring Boot 运行原理,自动配置

,然后我又看了下nacos的源码,发现原来也都是这做的截图如下:

当然最终的目的我是想知道@Bean  helloService实例化过程


/**
 * @desc 自定义自动配置加载类:
 * 1、编写属性配置类,读取application.properties文件初始化属性
 * 2、编写service类。
 * 3、编写自定义自动加载配置类
 * 4、在配置类中根据HelloServiceProperties提供的参数,并通过ConditionalOnMissingBean判断
 * 容器中没有bean时,注入helloService。
 */
@Configuration
@EnableConfigurationProperties(HelloServiceProperties.class)
@ConditionalOnClass(HelloService.class)
@ConditionalOnProperty(prefix = "hello", value = "enabled", matchIfMissing = true)
public class HelloServiceAutoConfiguration {

    @Autowired
    private HelloServiceProperties helloServiceProperties;

    //容器中没有指定的HelloService实例时进行初始化
    @Bean
    @ConditionalOnMissingBean(HelloService.class)
    public HelloService helloService() {
        HelloService helloService = new HelloService();
        helloService.setMsg(this.helloServiceProperties.getMsg());
        return helloService;
    }
}

1:首先回顾一下bean创建以及后期处理过程中的主要类的名字和作用,我觉得有两个类需要提前关注下,如下图所示(ctrl+h),

DefaultListableBeanFactory作为默认的bean注册加载的工厂类,继承了AutowireCapableBeanFacotry(提供创建、自动注入、初始化、和后置处理器的作用)

2:调用关系时序图参考 IDEA自动生成方法时序图 -- Sequence Diagram(一款超好用的Idea插件)

当然,时序图有时候也不是万能的。

      第一步:

此时启动springboot之后,相继进入AbstractApplicationContext类的refresh()方法,这里我只关注一个finishBeanFactoryInitialization方法,其他的并非本次分析的重点:

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
该refresh()所调用的方法注释翻译:实例化所有剩余的(非延迟初始化)单例,当然到了这一步bean已经全部加载完毕,之后的过程是进行实例化的过程

   第二步:

点击进入finishBeanFactoryINitialization方法,此时使用beanFactory就是DefaultListableBeanFactory,准备bean的实例化

/**
	 * Finish the initialization of this context's bean factory,
	 * initializing all remaining singleton beans.
	 */
	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// 省略。。。。。

		// Instantiate all remaining (non-lazy-init) singletons.
		beanFactory.preInstantiateSingletons();
	}

     第三步

  分析DefaultListableBeanFactory的preInstantiateSingletons方法,

Ensure that all non-lazy-init singletons are instantiated(确保所有非懒加载的bean都实例化)
@Override
	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// 1:这里的beanDefinitionNames的存储方式这ArrayList
 	    //private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
        // 在扩展看下就是	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
        //volatile 保证了可见性和顺序性,便于判断逻辑的准确实时


		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                // 这里我的类并没有实现FactoryBean的接口所以进入else的getBean方法,此处的判断逻辑是这样的:beanType != null && FactoryBean.class.isAssignableFrom(beanType)
                // 新的知识点出来了  instanceof, isinstance,isAssignableFrom的区别
                // 自身实例或子类实例 instanceof 自身类 
                // 自身类.class.isInstance(自身实例或子类实例)  返回true 
                // 自身类.class.isAssignableFrom(自身类或子类.class)  返回true 

				if (isFactoryBean(beanName)) {
					// 省略。。。
				}
				else {
					getBean(beanName);
				}
			}
		}

		// 省略。。。。
	}

    第四步:

     查看getBean方法,当然要记住,目前操作都是在DefaultListableBeanFactory,可见,这里多么重要,是bean的存储的地方即beanDefinitionMap,还有创建bean的方法。

    之后的过程会进入DefaultListableBeanFactory的父类AbstractBeanFactory执行doGetBean,这里的方法名挺有意思的,我是这么理解的 getBean -表示想要获取bean,doGetBean-那就去获取bean,之后会看到createBean-表示想要创建bean,doCreateBean-真正的创建bean,当然前提条件是DefaultListableBeanFactory里边的三级缓存无数据,这点参考《spring源码分析》对三级缓存的理解,目的是提前暴露bean避免循环依赖,从代码方面可以看出以下缓存的数据结构

/** Cache of singleton objects: bean name to bean instance. */一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of singleton factories: bean name to ObjectFactory. */ 三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** Cache of early singleton objects: bean name to bean instance. */二级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

代码角度分析doGetBean的过程:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		final String beanName = transformedBeanName(name);
		Object bean;

		// 缓存检测实例是否提前被暴露,接下来看看里边的缓存是如何处理的
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			//省略。。。
		}

		else {
			//原型模式的bean检测是否存在循环依赖,有的话直接报异常,因为会造成死循环,最终导致程序崩溃
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// 省略。。。

			try {
				// 省略。。。

				// Create bean instance.
				if (mbd.isSingleton()) {
                    // 此处对于单例bean的创建,参数是beanNane和接口实现方法
                    // 最终调用createBean,当然还没完之后还有个doCreate真正去创建bean的方法
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				// 省略。。。
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}

		// 省略。。。
		return (T) bean;
	}

分析下第一个获取bean的方法--getSingleton,挺有意思的,对照前面提到的三级缓存结构,大致逻辑是查找一级缓存是否存在实例对象,不存在找二级缓存是否存在实例对象,不存在就再次查找三级缓存是否存在ObjectFactory,如果没有返回空,否则通过beanFactory.getBean获取实例对象,存入二级缓存,同时移除三级缓存对象。同理之后的处理逻辑会从二级缓存提取放入以及缓存,移除二级缓存对象,但是我没搞懂为啥有个二级缓存,可能为了更好的解耦合,见代码:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

第五步:

现在分析下第二个getSingleton方法,当然我们看到了第二个入参,是个匿名类,一定会调用匿名类的createBean方法,代码如下:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				// 省略。。。
                // 前置BeanCurrentlyInCreationException判断
                beforeSingletonCreation(beanName);
				try {
                    // 匿名类参数的调用,实际上是调用createBean方法,之后会分析createBean方法
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				// 省略。。。
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
                    // 后置BeanCurrentlyInCreationException判断
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
                    // 这块提前看下,就是把bean实例放入一级缓存,之后的调用
                    // 直接从一级缓存获取
                    // synchronized (this.singletonObjects) {
			            // this.singletonObjects.put(beanName, singletonObject);
			            // this.singletonFactories.remove(beanName);
			            // this.earlySingletonObjects.remove(beanName);
		            	// this.registeredSingletons.add(beanName);
		             // }
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

第六步:crreateBean方法,主要做了三个主要的灵魂级别的事情1:创建一个bean实例 ,2:填充bean实例 ,3:执行后置处理器

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
            // 这里是创建beanInstance的过程,继续跟代码
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
            // 这里是丰富化实例,执行属性注入,这里会获取beanPostProcess(getBeanPostProcessors)
            // 循环调用得到AutowiredAnnotationBeanPostProcessor,去处理@Autowired注入
            // 20200630补注:AutowiredAnnotationBeanPostProcessor类的postProcessProperties方法进行注入
            // 当然这里又会持续doGetBean的过程
			populateBean(beanName, mbd, instanceWrapper);
            // 这里执行后置处理器的过程
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		// 省略。。。

		return exposedObject;
	}

 

当然代码继续调用的是doCreateBean方法实现这些过程的。需要额外说明的是spring保证每个bean都要执行beanPostProcess方法,内置了大概是个process方法,也可以自定义,自定义之后,启动refresh的时候,会执行registerBeanPostProcessors方法,大概过程如下:前提已经加载了左右的bean class到beanDefinitionMap容器,之后执行doGetBeanNamesForType方法

private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
   List<String> result = new ArrayList<>();

   // Check all bean definitions.
   for (String beanName : this.beanDefinitionNames) {省略。。。。}

获取所有实现BeanPostProcessor接口的实现类,提取存放到beanPostProcessors里

private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();

最后在populateBean、exposedObject 时候会执行processor方法,给予实例化的更改实际的机会,大致代码过程

for (BeanPostProcessor processor : getBeanPostProcessors()) {
   Object current = processor.postProcessBeforeInitialization(result, beanName);
   if (current == null) {
      return result;
   }
   result = current;
}

当然当执行到ConfigurationBeanBindingPostProcessor的postProcessBeforeInitialization时候会进行@ConfigurationProperties的值反射绑定(bind-->bindDataObject),其绑定的定义值也都是从PropertySource类中获取,说的有点远了,看下PropertySource的结构

public abstract class PropertySource<T> {

	protected final Log logger = LogFactory.getLog(getClass());

	protected final String name;

	protected final T source;


	/**
	 * Create a new {@code PropertySource} with the given name and source object.
	 */
	public PropertySource(String name, T source) {
		Assert.hasText(name, "Property source name must contain at least one character");
		Assert.notNull(source, "Property source must not be null");
		this.name = name;
		this.source = source;
	}

          其实这个结构存储额所有springboot配置文件的key vale值,可以通过Environment  注入的形式获取,源头都是PropertySource,找到源头是一件非常好玩的一件事情。

 

 第七步:分析createBeanInstance方法,这里挺有意思的,普通方法例如使用@Component,直接进行构造函数实例化,但是本例中使用的是@Configuration @Bean进行实例化的,如下图,所以我猜测spring会给mdb set一个特殊实例化工厂方法,然后执行具体的策略,有兴趣的自己可以在setFacory断点查看,

如我所愿,果真如此,可以看下图,这里边的信息表明@Configuration 真的是将工厂方法策略的元数据信息set到了mdb里边,方便之后的执行操作,具体操作大家应该都能猜到,就是使用的@Bean里边自定义的实例化方法

特殊工厂方法策略实例化代码

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// 省略。。。
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// 省略。。。
		// 无特殊处理:只需使用无参数构造函数。
		return instantiateBean(beanName, mbd);
	}

第八步:

	protected BeanWrapper instantiateUsingFactoryMethod(
			String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

		return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
	}

继续跟代码,可以看到最终的猜想是否正确,到底使用工厂方法做了什么特殊处理呢?

public BeanWrapper instantiateUsingFactoryMethod(
			String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
        // 省略。。。。
        // 获取工厂
			factoryClass = factoryBean.getClass();
        // uniqueCandidate是具体@Bean注解的方法Method,之后利用反射执行实例化
            bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
			return bw;

利用工厂方法(helloService)进行反射实例化Bean的过程如下

@Override
	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
			@Nullable Object factoryBean, final Method factoryMethod, Object... args) {

		try {
			if (System.getSecurityManager() != null) {
				AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
					ReflectionUtils.makeAccessible(factoryMethod);
					return null;
				});
			}
			else {
				ReflectionUtils.makeAccessible(factoryMethod);
			}

			Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
			try {
				currentlyInvokedFactoryMethod.set(factoryMethod);
				Object result = factoryMethod.invoke(factoryBean, args);
				if (result == null) {
					result = new NullBean();
				}
				return result;
			}
			// 省略。。。。
		}
		// 省略。。。。
	}

我的公众号:第一次想认真写写博客,写写生活点滴

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值