BeanDefinition到Bean
转自:http://songzi0206.iteye.com/blog/1430239
当 BeanDefinition 注册完毕以后, Spring Bean 工厂就可以随时根据需要进行实例化了。对于XmlBeanFactory 来说,实例化默认是延迟进行的,也就是说在 getBean 的时候才会;而对于 ApplicationContext来说,实例化会在容器启动后通过 AbstractApplicationContext 中 reflash 方法自动进行,主要经过方法链:reflesh() à finishBeanFactoryInitialization (factory) à DefaultListableBeanFactory.preInstantiateSingletons (), 在这里会根据注册的 BeanDefinition 信息依此调用 getBean(beanName) 。而真正实例化的逻辑和 BeanFactory 是“殊途同归”的,所有有关 Bean 实例化都可以从 getBean(beanName) 入手。
AbstractBeanFactory 有四个 getBean 的重载方法,不管调用哪个方法最终都是会调用另一个 doGetBean 方法:
- public Object getBean(String name) throws BeansException {
- return getBean(name, null, null);
- }
- public Object getBean(String name, Class requiredType) throws BeansException {
- return getBean(name, requiredType, null);
- }
- public Object getBean(String name, Object[] args) throws BeansException {
- return getBean(name, null, args);
- }
- /**
- * Return an instance, which may be shared or independent, of the specified bean.
- * @param name the name of the bean to retrieve
- * @param requiredType the required type of the bean to retrieve
- * @param args arguments to use if creating a prototype using explicit arguments to a
- * static factory method. It is invalid to use a non-null args value in any other case.
- * @return an instance of the bean
- * @throws BeansException if the bean could not be created
- */
- public Object getBean(String name, Class requiredType, Object[] args) throws BeansException {
- return doGetBean(name, requiredType, args, false);
- }
doGetBean方法比较长一点,见下面注释:
- protected Object doGetBean(
- final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly)
- throws BeansException {
- //bean name处理,去除FactoryBean前缀等
- final String beanName = transformedBeanName(name);
- Object bean = null;
- //先从singleton缓存中查看是否已经实例化过该Bean,根据是否有缓存分为两个分支分别处理
- Object sharedInstance = getSingleton(beanName);
- if (sharedInstance != null && args == null) {
- // 分支一,若缓存中获取到了并且该BeanDefinition信息表明该bean是singleton的,直接将获取到的缓存Bean
- //(有可能是半成品)交给getObjectForBeanInstance处理
- /*.........省略logger部分代码............*/
- //调用getObjectForBeanInstance处理
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
- }else {
- // 分之二:没有缓存,则需要从头实例化该bean
- // We're assumably within a circular reference.
- if (isPrototypeCurrentlyInCreation(beanName)) {
- throw new BeanCurrentlyInCreationException(beanName);}
- // 检查BeanDefinition是否在当前工厂或父工厂
- BeanFactory parentBeanFactory = getParentBeanFactory();
- if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
- // Not found -> check parent.
- String nameToLookup = originalBeanName(name);
- if (args != null) {
- // 父工厂getBean
- return parentBeanFactory.getBean(nameToLookup, args);
- }
- else {
- // No args -> delegate to standard getBean method.
- return parentBeanFactory.getBean(nameToLookup, requiredType);
- }
- }
- //将bean加入“正在创建”的集合,完成后会remove,对应afterSingletonCreation/afterPrototypeCreation方法
- if (!typeCheckOnly) {
- markBeanAsCreated(beanName);
- }
- final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
- checkMergedBeanDefinition(mbd, beanName, args);
- // 解决依赖关系,将依赖的bean提前实例化
- String[] dependsOn = mbd.getDependsOn();
- if (dependsOn != null) {
- for (int i = 0; i < dependsOn.length; i++) {
- String dependsOnBean = dependsOn[i];
- getBean(dependsOnBean);
- registerDependentBean(dependsOnBean, beanName);
- }
- }
- // 这里又需要根据bean的类型分为三种情况:singleton、prototype、request/session
- if (mbd.isSingleton()) {
- //通过自定义ObjectFactory实例化Bean,此结果可能是半成品(是FactoryBean等)
- sharedInstance = getSingleton(beanName, new ObjectFactory() {
- public Object getObject() throws BeansException {
- try {
- //真正实例化装配的逻辑在createBean方法中
- 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方法处理
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
- }
- else if (mbd.isPrototype()) {
- // It's a prototype -> create a new instance.
- Object prototypeInstance = null;
- try {
- beforePrototypeCreation(beanName);
- //真正实例化装配的逻辑在createBean方法中
- prototypeInstance = createBean(beanName, mbd, args);
- }
- finally {
- afterPrototypeCreation(beanName);
- }
- //上一步半成品的Bean交给getObjectForBeanInstance方法处理
- bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
- }
- else {
- //request、session 的bean
- String scopeName = mbd.getScope();
- final Scope scope = (Scope) this.scopes.get(scopeName);
- if (scope == null) {
- throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
- }
- try {
- Object scopedInstance = scope.get(beanName, new ObjectFactory() {
- public Object getObject() throws BeansException {
- beforePrototypeCreation(beanName);
- try {
- //真正实例化装配的逻辑在createBean方法中
- return createBean(beanName, mbd, args);
- }
- finally {
- afterPrototypeCreation(beanName);
- }
- }
- });
- //上一步半成品的Bean交给getObjectForBeanInstance方法处理
- bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
- }
- catch (IllegalStateException ex) {
- throw new BeanCreationException(beanName,
- "Scope '" + scopeName + "' is not active for the current thread; " +
- "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
- ex);
- }
- }
- }
- // Check if required type matches the type of the actual bean instance.
- if (requiredType != null && bean != null &&
- !requiredType.isAssignableFrom(bean.getClass())) {
- throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
- }
- return bean;
- }
通过注释,可以整理出较清晰的逻辑: 检查Bean缓存,已经有缓存的Bean对象(有可能是半成品)则交给getObjectForBeanInstance方法处理;否则先根据Bean的生命周期类型分别实例化,每种情况大致都分两步,第一步都交给createBean方法生产一个半成品的bean对象,然后同样是将半成品的bean交给getObjectForBeanInstance方法处理。所以关键的逻辑就在这两个方法了,下面以singleton为例看看这两个方法,具体代码:
- sharedInstance = getSingleton(beanName, new ObjectFactory() {
- public Object getObject() throws BeansException {
- 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);
getSingleton方法做的工作主要是实例化bean之前和之后回调beforeSingletonCreation/afterSingletonCreation、实例化bean、以及将bean对象缓存起来,具体实例化bean是通过回调匿名对象ObjectFactory的getObject方法实现的,从代码中明显看到主要是createBean方法。这里要特别注意下,缓存的bean对象是createBean生产的,这个方法生产的bean只是“半成品”,有可能是个factoryBean,真正返回给客户端使用的bean还必须进行下一步getObjectBeanInstance处理。所以缓存的bean对象可以认为是“半成品”,这就和前文代码中的注释相呼应(缓存中若取到了bean,必须进行getObjectBeanInstance处理)。
对createBean方法实际上在“Spring IOC之BeanFactory”中已经有过分析,所以流程就不再简单重复,直接按步骤:
1. resolveBeanClass(mbd, beanName);
2. mbd.prepareMethodOverrides();//Spring IOC之BeanFactory已有解释,不重复
3. Object bean = resolveBeforeInstantiation(beanName, mbd);
解释下,这里主要对于一些代理的bean做处理,我们平常经常会配置一些AOP模块,对于需要aop增强的bean实际上都会经过spring代理织入,而这些bean的代理逻辑应该就在这里处理了,具体看看这部分的代码:
- /**
- * Apply before-instantiation post-processors, resolving whether there is a
- * before-instantiation shortcut for the specified bean.
- * @param beanName the name of the bean
- * @param mbd the bean definition for the bean
- * @return the shortcut-determined bean instance, or <code>null</code> if none
- */
- protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
- Object bean = null;
- if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
- // Make sure bean class is actually resolved at this point.
- if (mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
- bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName);
- if (bean != null) {
- bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
- }
- }
- mbd.beforeInstantiationResolved = Boolean.valueOf(bean != null);
- }
- return bean;
- }
- /**
- * Apply InstantiationAwareBeanPostProcessors to the specified bean definition
- * (by class and name), invoking their <code>postProcessBeforeInstantiation</code> methods.
- * <p>Any returned object will be used as the bean instead of actually instantiating
- * the target bean. A <code>null</code> return value from the post-processor will
- * result in the target bean being instantiated.
- * @param beanClass the class of the bean to be instantiated
- * @param beanName the name of the bean
- * @return the bean object to use instead of a default instance of the target bean, or <code>null</code>
- * @throws BeansException if any post-processing failed
- * @see InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
- */
- protected Object applyBeanPostProcessorsBeforeInstantiation(Class beanClass, String beanName)
- throws BeansException {
- for (Iterator it = getBeanPostProcessors().iterator(); it.hasNext();) {
- BeanPostProcessor beanProcessor = (BeanPostProcessor) it.next();
- if (beanProcessor instanceof InstantiationAwareBeanPostProcessor) {
- InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) beanProcessor;
- Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
- if (result != null) {
- return result;
- }
- }
- }
- return null;
- }
- //AbstractAutoProxyCreator
- public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {
- Object cacheKey = getCacheKey(beanClass, beanName);
- if (!this.targetSourcedBeans.contains(cacheKey)) {
- if (this.advisedBeans.contains(cacheKey) || this.nonAdvisedBeans.contains(cacheKey)) {
- return null;
- }
- if (isInfrastructureClass(beanClass, beanName) || shouldSkip(beanClass, beanName)) {
- this.nonAdvisedBeans.add(cacheKey);
- return null;
- }
- }
- // Create proxy here if we have a custom TargetSource.
- // Suppresses unnecessary default instantiation of the target bean:
- // The TargetSource will handle target instances in a custom fashion.
- TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
- if (targetSource != null) {
- this.targetSourcedBeans.add(beanName);
- Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
- Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
- this.proxyTypes.put(cacheKey, proxy.getClass());
- return proxy;
- }
- return null;
- }
对于AutoProxy部分代码要放到spring aop部分中去写了,这里只要明白如果是代理bean在postProcessBeforeInstantiation阶段会返回一个proxy,这时候bean已经算是实例化好了,再调用applyBeanPostProcessorsAfterInitialization即BeanPostProcessor.postProcessAfterInitialization回调进行属性的设置。最后的结果就可以返回bean对象了,只是一个Proxy Bean Object.
4. Object beanInstance = doCreateBean(beanName, mbd, args);//如果是代理bean就不会走到这一步
解释下:对于非代理的bean,基本上实例化的逻辑就在doCreateBean这个方法了,这个方法在“Spring IOC之BeanFactory”中已经有过分析,所以不重复解释了,贴一个bean生命周期的流程图做为createBean方法的结尾:

上图不是我所画,来源于spring IOC容器介绍。
半成品出来之后还需要调用getObjectForBeanInstance进一步处理,这个方法:
- protected Object getObjectForBeanInstance(
- Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
- // Don't let calling code try to dereference the factory if the bean isn't a factory.
- if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
- throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
- }
- // Now we have the bean instance, which may be a normal bean or a FactoryBean.
- // If it's a FactoryBean, we use it to create a bean instance, unless the
- // caller actually wants a reference to the factory.
- if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
- return beanInstance;
- }
- Object object = null;
- if (mbd == null) {
- object = getCachedObjectForFactoryBean(beanName);
- }
- if (object == null) {
- // Return bean instance from factory.
- FactoryBean factory = (FactoryBean) beanInstance;
- // Caches object obtained from FactoryBean if it is a singleton.
- if (mbd == null && containsBeanDefinition(beanName)) {
- mbd = getMergedLocalBeanDefinition(beanName);
- }
- boolean synthetic = (mbd != null && mbd.isSynthetic());
- object = getObjectFromFactoryBean(factory, beanName, !synthetic);
- }
- return object;
- }
开始部分是逻辑检查,是否是FactoryBean,后面是从factoryBean中获取实际的Bean。获取bean也是先检查缓存,没有缓存再getObjectFromFactoryBean获取,详细再doGetObjectFromFactoryBean方法中,最后将获取的bean缓存起来。代码就不贴了。
BeanDefinition到Bean的更多相关文章
- (spring-第6回【IoC基础篇】)BeanDefinition——实例化Bean之前的第一大利器。
上节讲了Bean实例化的内部机制,这里再复述一遍: ResourceLoader从系统中加载XML配置信息,并由Resource来表示. BeanDefinitionReader从Resource中读 ...
- spring源码分析系列2:Bean与BeanDefinition关系
接口表示一种能力,实现了一个接口,即拥有一种能力. BeanDefinition与Bean的关系, 就好比类与对象的关系. 类在spring的数据结构就是BeanDefinition.根据BeanDe ...
- Spring工厂方式创建Bean实例
创建Bean实例的方式: 1) 通过构造器(有参或无参) 方式: <bean id="" class=""/> 2) 通过静态工厂方法 方式: &l ...
- SpringMVC 源码深度解析<context:component-scan>(扫描和注冊的注解Bean)
我们在SpringMVC开发项目中,有的用注解和XML配置Bean,这两种都各有自己的优势,数据源配置比較经经常使用XML配置.控制层依赖的service比較经经常使用注解等(在部署时比較不会改变的) ...
- 4.0 spring-注册解析的Bean
1.0 registerBeanDefinition 对于配置文件,解析也解析完了,装饰也装饰完了,对于得到的BeanDefinition已经可以满足后续的使用了,唯一剩下的工作就是注册了, 也就是: ...
- 【spring源代码分析】--Bean的解析与注冊
接着上一节继续分析,DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法: protected void parseBeanDefini ...
- Spring多种加载Bean方式简析
1 定义bean的方式 常见的定义Bean的方式有: 通过xml的方式,例如: <bean id="dictionaryRelMap" class="java.ut ...
- Spring读书笔记——bean解析
前情回顾 上篇<Spring读书笔记--bean加载>我们从代码角度介绍了有哪些类负责解析XML文件,又是如何一步步从XML格式脱变成我们熟悉的bean的,直到DefaultBeanDef ...
- 【Spring源码分析】Bean加载流程概览
代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...
随机推荐
- CI、CD和dev-ops概念
传统的开发方式是:需求方提供文档,实现方按照文档一步步开发,中间很少变动和修改. 但是随着市场的变化,产品更新迭代的加快,也要求开放方更快的响应变化,用最短的时间开发,部署上线. 这样,持续集成(CI ...
- 利用github搭建个人maven仓库
之前看到有开源项目用了github来做maven仓库,寻思自己也做一个.研究了下,记录下. 简单来说,共有三步: deploy到本地目录 把本地目录提交到gtihub上 配置github地址为仓库地址 ...
- bootstrap基础学习小记(三)网格简介
网格系统:网格系统的实现原理非常简单,仅仅是通过定义容器大小,平分12份(也有平分成24份或32份,但12份是最常见的),再调整内外边距,最后结合媒体查询,就制作出了强大的响应式网格系统.Bootst ...
- pyqt5 Button.click 报错:argument 1 has unexpected type 'NoneType'
如上所示,在括号中,添加‘lambda:’,就可以成功运行,不知道为啥. 参考:https://blog.csdn.net/flhsxyz/article/details/79220936?utm_s ...
- Bs4 BeautifulSoup取值
原文网址:https://blog.csdn.net/u010244522/article/details/79627073 从网页获取HTML数据后,获取对应标签.属性的值 取值方法主要有以下几种: ...
- python -m SimpleHTTPServer 8080
启动一个简单的 web 服务器 python -m SimpleHTTPServer 8080
- spring的Java注解方式
以往我们在使用spring的时候都是用一堆<>这个玩意(尖括号)的xml文件来配置spring,在xml里都是"xxx"来配置需要的内容信息,在"" ...
- 组件基础(插槽slot)—Vue学习笔记
刚开始我们淡淡提过<slot></slot>现在深入了解一下. slot可以进行父组件传值到子组件. 比如:我们将hiboy通过<slot>传递到组件中. < ...
- 利用Warensoft Stock Service编写高频交易软件--客户端驱动接口说明
Warensoft Stock Service Api客户端接口说明 Warensoft Stock Service Api Client Reference 本项目客户端驱动源码已经发布到GitHu ...
- 剑指offer二十之包含min函数的栈
一.题目 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数. 二.思路 用一个栈dataStack保存数据,用另外一个栈minStack保存依次入栈最小的数.每次元素存入minSt ...