🚀 优质资源分享 🚀
学习路线指引(点击解锁) | 知识定位 | 人群定位 |
---|---|---|
🧡 Python实战微信订餐小程序 🧡 | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
💛Python量化交易实战💛 | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
Spring Ioc源码分析系列–实例化Bean的几种方法
前言
前面的文章Spring Ioc源码分析系列–Bean实例化过程(二)在讲解到bean真正通过那些方式实例化出来的时候,并没有继续分析了,而是留到了这里去分析,主要是因为获取获取构造函数,推断构造函数也是一个比较复杂的操作,就想另起一篇文章再说,但是总的来说,应该不会比前面的逻辑绕,因为这里很清晰,就是实例化对象的几种方法,那么实例化对象有哪几种选择呢?没印象,那说明前面的文章没留下影响,回去翻翻。所以废话少说,跟着上面文章的口子,我们来分析实例化bean的过程。
源码分析
首先,这里回忆一下之前说到什么。
本篇文章的核心逻辑入口是在AbstractAutowireCapableBeanFactory#createBeanInstance()
方法里。
跟进createBeanInstance(beanName, mbd, args)
方法。这个方法干了哪几件事?
- 首先尝试调用
obtainFromSupplier()
实例化bean - 尝试调用
instantiateUsingFactoryMethod()
实例化bean - 根据给定参数推断构造函数实例化bean
- 以上均无,则使用默认构造函数实例化bean
先贴一下代码,然后逐个分析。
/**
* Create a new instance for the specified bean, using an appropriate instantiation strategy:
* factory method, constructor autowiring, or simple instantiation.
*
* 使用适当的实例化策略为指定的 bean 创建一个新实例:工厂方法、构造函数自动装配或简单实例化。
*
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @param args explicit arguments to use for constructor or factory method invocation
* @return a BeanWrapper for the new instance
* @see #obtainFromSupplier
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
* @see #instantiateBean
*/
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
// 确保此时实际解析了 bean 类。
Class beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
// 通过bd中提供的instanceSupplier来获取一个对象
// 正常bd中都不会有这个instanceSupplier属性,这里也是Spring提供的一个扩展点,但实际上不常用
Supplier instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
//如果工厂方法不为null,则使用工厂方法初始化策略
// bd中提供了factoryMethodName属性,那么要使用工厂方法的方式来创建对象,
// 工厂方法又会区分静态工厂方法跟实例工厂方法
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
// 在原型模式下,如果已经创建过一次这个Bean了,那么就不需要再次推断构造函数了
// 是否推断过构造函数
boolean resolved = false;
// 构造函数是否需要进行注入
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
//一个类里面有多个构造函数,每个构造函数都有不同的参数,所以调用前需要根据参数锁定要调用的构造函数或工厂方法
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
//如果已经解析过则使用解析好的构造函数方法,不需要再次锁定
if (resolved) {
if (autowireNecessary) {
//构造函数自动注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
//使用默认构造函数进行构造
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring?
//需要根据参数解析构造函数
Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//构造函数自动注入
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
// 默认构造的首选构造函数?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
//使用默认构造函数
return instantiateBean(beanName, mbd);
}
使用Supplier实例化bean
这一块的逻辑对应如下
// 通过bd中提供的instanceSupplier来获取一个对象
// 正常bd中都不会有这个instanceSupplier属性,这里也是Spring提供的一个扩展点,但实际上不常用
Supplier instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
Supplier在Spring里面的使用是相对比较新的,看了一个代码的commit记录,这一块的代码是在2016年12月19号加上的,相对来说还是比较新的。
Supplier就是一个Java 8提供的函数式编程接口,里面提供一个get()
方法,可以通过这个方法实例化bean对象。
@FunctionalInterface
public interface Supplier {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
跟进obtainFromSupplier()
方法,可以看到逻辑是比较简单的,通过一个NamedThreadLocal
设置依赖关系beanName
,然后调用instanceSupplier.get()
获取对象,随后包装成一个BeanWrapper
返回。
/**
* Obtain a bean instance from the given supplier.
*
* 从给定的 supplier 处获取一个 bean 实例。
*
* @param instanceSupplier the configured supplier
* @param beanName the corresponding bean name
* @return a BeanWrapper for the new instance
* @since 5.0
* @see #getObjectForBeanInstance
*/
protected BeanWrapper obtainFromSupplier(Supplier instanceSupplier, String beanName) {
Object instance;
// 这里是处理 Supplier 创建的 bean 的内外部名称依赖关系
String outerBean = this.currentlyCreatedBean.get();
this.currentlyCreatedBean.set(beanName);
try {
// 调用 get() 方法获取对象
instance = instanceSupplier.get();
}
finally {
if (outerBean != null) {
this.currentlyCreatedBean.set(outerBean);
}
else {
this.currentlyCreatedBean.remove();
}
}
if (instance == null) {
instance = new NullBean();
}
BeanWrapper bw = new BeanWrapperImpl(instance);
initBeanWrapper(bw);
return bw;
}
使用工厂方法实例化bean
简介
这一块的代码逻辑对应如下
//如果工厂方法不为null,则使用工厂方法初始化策略
// bd中提供了factoryMethodName属性,那么要使用工厂方法的方式来创建对象,
// 工厂方法又会区分静态工厂方法跟实例工厂方法
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
跟进instantiateUsingFactoryMethod()
方法,可以看到这里先new
了一个ConstructorResolver
,这个ConstructorResolver
非常重要,它会去推断合适的构造函数。实例化bean另起这篇文章来写,很大程度就是因为这个ConstructorResolver
,我想写清楚一点。
/**
* Instantiate the bean using a named factory method. The method may be static, if the
* mbd parameter specifies a class, rather than a factoryBean, or an instance variable
* on a factory object itself configured using Dependency Injection.
*
* 使用命名工厂方法实例化 bean。
* 如果 mbd 参数指定一个类,而不是 factoryBean,或者使用依赖注入配置的工厂对象本身的实例变量,则该方法可能是静态的。
*
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @param explicitArgs argument values passed in programmatically via the getBean method,
* or {@code null} if none (-> use constructor argument values from bean definition)
* @return a BeanWrapper for the new instance
* @see #getBean(String, Object[])
*/
protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
首先来看一下ConstructorResolver
类上的定义,翻译一下就是:用于解析构造函数和工厂方法的委托,通过参数匹配执行构造函数解析。
Delegate for resolving constructors and factory methods.Performs constructor resolution through argument matching.
这个类的作用非常强大,可以解析实例化对象的所需的构造器,如果有多个,会根据构造器的参数类型和给定的参数类型通过计算权重的方式去匹配一个最佳的构造器。
跟进方法instantiateUsingFactoryMethod()
代码,这个方法整整三百行,可以说非常离谱。
这里先贴个图,看下基本的逻辑。其实逻辑也跟我们写业务差不多,先做些基础准备,这里就是初始化个BeanWrapperImpl
,给工厂bean属性赋赋值等,然后就去缓存去工厂方法和参数,取不到就去解析获取方法和参数,然后利用工厂方法和参数,实例化一个对象返回,逻辑清晰。
下面分段来看一下代码吧。
基础属性赋值
这一块代码比较简单,就是初始化一个BeanWrapperImpl
,然后给一些属性赋值。
// 创建并初始化一个 BeanWrapperImpl
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
// 实例化这个Bean的工厂Bean
Object factoryBean;
// 工厂Bean的Class
Class factoryClass;
// 静态工厂方法或者是实例化工厂方法
boolean isStatic;
/*下面这段代码就是为上面申明的这三个属性赋值*/
String factoryBeanName = mbd.getFactoryBeanName();
if (factoryBeanName != null) {
// 如果创建这个Bean的工厂就是这个Bean本身的话,那么直接抛出异常
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
// 得到创建这个Bean的工厂Bean
factoryBean = this.beanFactory.getBean(factoryBeanName);
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
throw new ImplicitlyAppearedSingletonException();
}
factoryClass = factoryBean.getClass();
isStatic = false;
}
else {
// It's a static factory method on the bean class.
// factoryBeanName为null,说明是通过静态工厂方法来实例化Bean的
// 静态工厂进行实例化Bean,beanClass属性必须要是工厂的class,如果为空,直接报错
if (!mbd.hasBeanClass()) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"bean definition declares neither a bean class nor a factory-bean reference");
}
factoryBean = null;
factoryClass = mbd.getBeanClass();
isStatic = true;
}
从缓存获取参数
完成准备后,接下来是从缓存中获取工厂方法和参数,这里也比