springboot bean的实例化

本文深入解析SpringBoot中bean的实例化过程,主要关注`finishBeanfactoryInitialization`方法,包括从缓存中获取bean、从父beanfactory获取、创建bean定义、根据bean类型实例化以及属性注入等步骤。特别地,详细分析了`doGetBean`、`createBean`和`populateBean`等关键方法,展示了如何通过反射和BeanPostProcessor进行bean的创建和属性设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

了解过springboot的加载流程的都知道springboot初始化bean都在refresh方法中。这个方法代码如下:在这里插入图片描述
这里我们主要看下finishBeanfactoryInitialization方法。此方法实现了bean的实例和属性注入等。进入此方法的最后一行。
在这里插入图片描述

注释写的很清楚,实例化剩余非懒加载的bean。此方法的实现是核心类DefaultLisListableBeanFactory实现。这个方法中有个判断:bean是否是beanFactory的实现类。如果是则获取bean的时候会从beanFactory实现类的getObject中获取,我们重点看看getBean这个方法。getBean是spring中最重要、最牛逼的方法之一, 具体的逻辑是通过doGetBean方法处理的。我们看下doGetBean方法,方法很长。我们分成几个部分去看。
1、先判断是否已经存在缓存中,代码如下:
在这里插入图片描述
2、从父beanfactory中获取 在这里插入图片描述
3、直接创建RootBeanDefinition
在这里插入图片描述
4、是singleton还是prototype类型的,根据不同类型去实例化bean,代码只贴了单例的类型:在这里插入图片描述
5、检查bean的类型是否匹配在这里插入图片描述
整个doGetBean方法改成这5个部分,重点看下第4个部分中的createBean和getObjectForBeanInstance方法
1、createBean方法,里面主要是2个部分,bean直接是通过BeanPostProcessor的postProcessBeforeIntantiation方法获取的。注释也是描述的很清楚:Give BeanPostProcessors a chance to return a proxy instead of the bean instance(英语渣渣不敢瞎翻译误导大家,理解就好),代码如下:
在这里插入图片描述
第一个部分自己实现,那么createBean方法第2个部分毋庸置疑肯定是spring去实例化bean,代码如下:
在这里插入图片描述
又是do开头的方法,说明这个也是一个创建方法,spring中一般do开头的都是用于创建某个对象。跟着代码走,看下doCreateBean方法,在查看此方法之前,可能需要了解下BeanWarpper这个封装类。bean的封装、属性注入等都是用BeanWarpper去完成的。看下代码:
在这里插入图片描述
进入createBeanInstance方法中,就是调用构造器去实例化bean,返回beanWrapper。通过构造器获取实例代码如下:
在这里插入图片描述
这里实例化我一开始以为就是简单的反射,后面我点进去时候发现里面一直提策略实例化,我目前了解的是可以解决Override的问题等。如果有兴趣的可以自行查看。到这里为止。我们终于实例化bean了。下面看下第二步bean的属性注入等。代码如下:在这里插入图片描述
populateBean方法名称就暴露他是干啥的:填充bean。我放一段比较重要的部分:在这里插入图片描述
这段代码貌似没有什么注入、填充什么的,我们看下InstantiationAwareBeanPostProcessor这个接口,发现这个接口有个很熟悉的实现类是:AutowiredAnnotationBeanPostProcessor。这个类的方法中我们看到终于看到了jnject方法。但是在inject之前需要调用下findAutowiringMatedata方法获取一下元数据: 在这里插入图片描述
AutowiredAnnotationBeanPostProcessor实现了MergeBeandefinitionPostProcessor,那么就好了,肯定是在bean实例的时候调用了postProcessMergedBeanDefintion这个方法。果然在doCreateBean方法中有这么一段:在这里插入图片描述
元数据有了,下面我们看下element.inject()方法是如何操作的:在这里插入图片描述
方法简单明了,直接使用反射将值set到属性中,至此 bean的实例、属性注入基本完成,下面我们回头来看doGetBean的另一个方法getObjectForBeanInstance。

2、getObjectForBeanInstance方法。对于是FactoryBean类型的 bean通过getObject获取到bean的代理实例,跟着方法一直走下去会到getObejct()方法中。
在这里插入图片描述
到此 finishBeanfactoryInitialization方法执行结束

Spring Boot应用程序中,获取Bean有多种方式。通常我们会依赖于Spring的上下文管理自动装配所需的组件,但在某些场景下也需要手动去取得某个特定的Bean实例。 ### 方式一:通过@Autowired注解 这是最常见的方式之一,在需要注入的地方直接使用`@Autowired`注解,并声明你要注入的对象类型即可让Spring自动为你找到并赋值相应的bean。 ```java @Service public class MyService { @Autowired private AnotherBean anotherBean; } ``` ### 方式二:利用构造函数或者Setter方法注入(@Inject/@Autowired) 除了字段级别的注入外,还可以选择将依赖项作为构造参数传入,或者是提供setter方法来设置依赖属性。这种方式有助于提高单元测试时的灵活性以及更清晰地表达出类之间的依赖关系。 #### 构造器注入示例: ```java @RestController public class MyController { private final AnotherBean bean; // 使用构造器注入另一个bean public MyController(AnotherBean bean) { this.bean = bean; } } ``` #### Setter方法注入示例: ```java @Component public class MyClass{ private Helper helper; @Autowired public void setHelper(Helper helper){ this.helper=helper; } } ``` ### 方式三:ApplicationContextAware 接口 如果是在非受管环境中想要访问到spring容器里的beans的话,则可以考虑实现 `org.springframework.context.ApplicationContextAware` 接口。这允许我们在任意地方获得整个application context 并从中检索指定名称的 Bean。 ```java import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component("myAppCtx") public class ApplicationContextProvider implements ApplicationContextAware { private static ApplicationContext ctx = null; public static ApplicationContext getApplicationContext() { return ctx; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { ctx = applicationContext; } } // 获取名为 "anotherBean" 的bean 示例: MyClass.anotherBeanInstance = (AnotherBean) ApplicationContextProvider.getApplicationContext().getBean("anotherBean"); ``` ### 方式四:从配置文件加载静态资源或者其他复杂类型的Beans 对于一些比较特殊的场景比如读取外部properties/json/yaml等格式的数据源生成对应的Bean对象,我们一般会采用工厂模式结合@Configuration + @Bean定义的方式来完成。 ```java @Configuration class AppConfig { @Value("${api.url}") String apiUrl; @Bean(name="httpClientConfiguredWithApiUrl") HttpClient createHttpClient(){ return HttpClient.createDefault(apiUrl); } } ``` 以上就是几种常见的在Spring Boot应用里获取、创建和注册Bean的方法了!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值