天天看點

SpringFramework核心技術一(IOC:Bean的分析)一、下面來看一下BeanDefinition

Bean的概述

Spring IoC容器管理一個或多個bean。這些bean是使用您提供給容器的配置中繼資料建立的,例如,以XML 定義的形式 。

在容器本身中,這些bean定義被表示為BeanDefinition 對象,其中包含以下中繼資料(以及其他資訊):

一、下面來看一下BeanDefinition

1.1

詳細看一下BeanDefinition接口裡面講的有那些東西

首先來看一下,用的比較多的Spring表示範圍Scope中的prototype與singleton差別

1.1.1 singleton作用域

當一個bean的作用域設定為singleton, 那麼Spring IOC容器中隻會存在一個共享的bean執行個體,并且所有對bean的請求,隻要id與該bean定義相比對,則隻會傳回bean的同一執行個體。換言之,當把一個bean定義設定為singleton作用域時,Spring IOC容器隻會建立該bean定義的唯一執行個體。這個單一執行個體會被存儲到單例緩存(singleton cache)中,并且所有針對該bean的後續請求和引用都将傳回被緩存的對象執行個體。

這裡要注意的是singleton作用域和GOF設計模式中的單例是完全不同的,單例設計模式表示一個ClassLoader中隻有一個class存在,而這裡的singleton則表示一個容器對應一個bean,也就是說當一個bean被辨別為singleton時候,spring的IOC容器中隻會存在一個該bean。

1.1.1 prototype作用域

prototype作用域部署的bean,每一次請求(将其注入到另一個bean中,或者以程式的方式調用容器的getBean()方法)都會産生一個新的bean執行個體,相當與一個new的操作,對于prototype作用域的bean,有一點非常重要,那就是Spring不能對一個prototype bean的整個生命周期負責,容器在初始化、配置、裝飾或者是裝配完一個prototype執行個體後,将它交給用戶端,随後就對該prototype執行個體不聞不問了。

不管何種作用域,容器都會調用所有對象的初始化生命周期回調方法,而對prototype而言,任何配置好的析構生命周期回調方法都将不會被調用。清除prototype作用域的對象并釋放任何prototype bean所持有的昂貴資源,都是用戶端代碼的職責。(讓Spring容器釋放被singleton作用域bean占用資源的一種可行方式是,通過使用bean的後置處理器,該處理器持有要被清除的bean的引用。)

1.1.1.1 關于scope=”prototype”沒寫的問題

項目中對一個表的增删該操作是用一個action,這個action擁有add,update,delete,save等方法, 添加和修改是共用一個頁面,當頁面得到id時代表進行的修改操作,反之是添加操作。如果在配置spring的bean時,忘了寫scope=”prototype” ,是以每次添加時都顯示最後一次通路過的記錄。scope=”prototype” 會在該類型的對象被請求時建立一個新的action對象,如果沒有配置scope=”prototype”則添加的時候不會建立一個action,它仍然會保留上次通路的過記錄的資訊 ,是以,webwork的Action不是線程安全的,要求在多線程環境下必須是一個線程對應一個獨立的執行個體,則不能使用singleton。是以,我們在Spring配置Webwork Action Bean時,需要加上屬性scope=”prototype”或singleton=”false”。

singleton模式指的是對某個對象的完全共享,包括代碼空間和資料空間,說白了,如果一個類是singleton的,假如這個類有成員變量,那麼這個成員變量的值是各個線程共享的(有點類似于static的樣子了),當線程A往給變量賦了一個值以後,線程B就能讀出這個值。

是以,對于前台Action,肯定不能使用singleton的模式,必須是一個線程請求對應一個獨立的執行個體。推而廣之,隻要是帶資料成員變量的類,為了防止多個線程混用資料,就不能使用singleton。對于我們用到的Service、Dao,之是以用了singleton,就是因為他們沒有用到資料成員變量,如果誰的Service需要資料成員變量,請設定singleton=false。 有狀态的bean都使用Prototype作用域,而對無狀态的bean則應該使用singleton作用域。

二、看一下BeanDefinition的源碼

/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory.config;

import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.core.AttributeAccessor;
import org.springframework.lang.Nullable;

/**
 * A BeanDefinition describes a bean instance, which has property values,
 * constructor argument values, and further information supplied by
 * concrete implementations.
 * 一個bean的定義就是描述一個bean的執行個體,這個bean有屬性值,構造參數的值
 * 這個bean的實作會提供更多的資訊
 *
 * <p>This is just a minimal interface: The main intention is to allow a
 * {@link BeanFactoryPostProcessor} such as {@link PropertyPlaceholderConfigurer}
 * to introspect and modify property values and other bean metadata.
 * 這個BeanDefinition僅僅隻是一個最簡潔的接口,它主要的目的是為了允許BeanFactoryPostProcessor和PropertyPlaceholderConfigurer
 * 去檢討和定義屬性值和一些其他的中繼資料
 *
 * @author Juergen Hoeller
 * @author Rob Harrop
 * @since 19.03.2004
 * @see ConfigurableListableBeanFactory#getBeanDefinition
 * 通過ConfigurableListableBeanFactory可以擷取到bean的屬性定義對應的值
 * @see org.springframework.beans.factory.support.RootBeanDefinition
 * @see org.springframework.beans.factory.support.ChildBeanDefinition
 */
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

    /**
     * SCOPE範圍
     */
    /**
     * Scope identifier for the standard singleton scope: "singleton".
     * scope範圍辨別符的單例singleton由字元串"singleton"表示。
     * <p>Note that extended bean factories might support further scopes.
     * @see #setScope
     */
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

    /**
     * Scope identifier for the standard prototype scope: "prototype".
     * prototype由字元串prototype表示
     * <p>Note that extended bean factories might support further scopes.
     * @see #setScope
     */
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


    /**
     * Role角色
     */
    /**
     * Role hint indicating that a {@code BeanDefinition} is a major part
     * of the application. Typically corresponds to a user-defined bean.
     * 角色應用
     */
    int ROLE_APPLICATION = 0;

    /**
     * Role hint indicating that a {@code BeanDefinition} is a supporting
     * part of some larger configuration, typically an outer
     * {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
     * {@code SUPPORT} beans are considered important enough to be aware
     * of when looking more closely at a particular
     * {@link org.springframework.beans.factory.parsing.ComponentDefinition},
     * but not when looking at the overall configuration of an application.
     * 角色支援
     */
    int ROLE_SUPPORT = 1;

    /**
     * Role hint indicating that a {@code BeanDefinition} is providing an
     * entirely background role and has no relevance to the end-user. This hint is
     * used when registering beans that are completely part of the internal workings
     * of a {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
     * 角色的基礎構造
     */
    int ROLE_INFRASTRUCTURE = 2;


    // Modifiable attributes

    /**
     * Set the name of the parent definition of this bean definition, if any.
     * 設定父類Bean的定義名稱
     */
    void setParentName(@Nullable String parentName);

    /**
     * Return the name of the parent definition of this bean definition, if any.
     * 擷取父類Bean的名字
     */
    @Nullable
    String getParentName();

    /**
     * Specify the bean class name of this bean definition.
     * <p>The class name can be modified during bean factory post-processing,
     * typically replacing the original class name with a parsed variant of it.
     * @see #setParentName
     * @see #setFactoryBeanName
     * @see #setFactoryMethodName
     * 設定bean的類的名字
     */
    void setBeanClassName(@Nullable String beanClassName);

    /**
     * Return the current bean class name of this bean definition.
     * <p>Note that this does not have to be the actual class name used at runtime, in
     * case of a child definition overriding/inheriting the class name from its parent.
     * Also, this may just be the class that a factory method is called on, or it may
     * even be empty in case of a factory bean reference that a method is called on.
     * Hence, do <i>not</i> consider this to be the definitive bean type at runtime but
     * rather only use it for parsing purposes at the individual bean definition level.
     * @see #getParentName()
     * @see #getFactoryBeanName()
     * @see #getFactoryMethodName()
     * 擷取bean的類的名字
     */
    @Nullable
    String getBeanClassName();

    /**
     * Override the target scope of this bean, specifying a new scope name.
     * @see #SCOPE_SINGLETON
     * @see #SCOPE_PROTOTYPE
     * 設定範圍
     */
    void setScope(@Nullable String scope);

    /**
     * Return the name of the current target scope for this bean,
     * or {@code null} if not known yet.
     * 擷取範圍
     */
    @Nullable
    String getScope();

    /**
     * Set whether this bean should be lazily initialized.
     * <p>If {@code false}, the bean will get instantiated on startup by bean
     * factories that perform eager initialization of singletons.
     * 設定是否延遲加載bean
     */
    void setLazyInit(boolean lazyInit);

    /**
     * Return whether this bean should be lazily initialized, i.e. not
     * eagerly instantiated on startup. Only applicable to a singleton bean.
     * 擷取這個bean是否需要延遲加載
     */
    boolean isLazyInit();

    /**
     * Set the names of the beans that this bean depends on being initialized.
     * The bean factory will guarantee that these beans get initialized first.
     * 設定這個bean,它的依賴的bean需要被初始化
     */
    void setDependsOn(@Nullable String... dependsOn);

    /**
     * Return the bean names that this bean depends on.
     * 傳回這個bean所依賴的其他bean的名字
     */
    @Nullable
    String[] getDependsOn();

    /**
     * Set whether this bean is a candidate for getting autowired into some other bean.
     * <p>Note that this flag is designed to only affect type-based autowiring.
     * It does not affect explicit references by name, which will get resolved even
     * if the specified bean is not marked as an autowire candidate. As a consequence,
     * autowiring by name will nevertheless inject a bean if the name matches.
     * 設定這個Bean為自動裝配的候選bean
     */
    void setAutowireCandidate(boolean autowireCandidate);

    /**
     * Return whether this bean is a candidate for getting autowired into some other bean.
     * 擷取這個Bean是否是其他Bean的自動裝配的候選人
     */
    boolean isAutowireCandidate();

    /**
     * Set whether this bean is a primary autowire candidate.
     * <p>If this value is {@code true} for exactly one bean among multiple
     * matching candidates, it will serve as a tie-breaker.
     * 設定這個Bean是否為主要需要自動裝配的候選bean
     */
    void setPrimary(boolean primary);

    /**
     * Return whether this bean is a primary autowire candidate.
     * 擷取這個Bean是否是需要首先自動裝配的Bean
     */
    boolean isPrimary();

    /**
     * Specify the factory bean to use, if any.
     * This the name of the bean to call the specified factory method on.
     * @see #setFactoryMethodName
     * 設定需要使用的工廠bean
     */
    void setFactoryBeanName(@Nullable String factoryBeanName);

    /**
     * Return the factory bean name, if any.
     * 擷取工廠Bean的名字
     */
    @Nullable
    String getFactoryBeanName();

    /**
     * Specify a factory method, if any. This method will be invoked with
     * constructor arguments, or with no arguments if none are specified.
     * The method will be invoked on the specified factory bean, if any,
     * or otherwise as a static method on the local bean class.
     * @see #setFactoryBeanName
     * @see #setBeanClassName
     * 設定工廠方法
     */
    void setFactoryMethodName(@Nullable String factoryMethodName);

    /**
     * Return a factory method, if any.
     * 擷取工廠方法
     */
    @Nullable
    String getFactoryMethodName();

    /**
     * Return the constructor argument values for this bean.
     * <p>The returned instance can be modified during bean factory post-processing.
     * @return the ConstructorArgumentValues object (never {@code null})
     * 擷取這個Bean的構造方法的參數值
     */
    ConstructorArgumentValues getConstructorArgumentValues();

    /**
     * Return if there are constructor argument values defined for this bean.
     * 擷取這個bean是否有構造方法的參數值
     * @since 5.0.2
     */
    default boolean hasConstructorArgumentValues() {
        return !getConstructorArgumentValues().isEmpty();
    }

    /**
     * Return the property values to be applied to a new instance of the bean.
     * <p>The returned instance can be modified during bean factory post-processing.
     * @return the MutablePropertyValues object (never {@code null})
     * 擷取屬性值
     */
    MutablePropertyValues getPropertyValues();

    /**
     * Return if there are property values values defined for this bean.
     * @since 5.0.2
     * 擷取這個Bean是否設定了屬性值
     */
    default boolean hasPropertyValues() {
        return !getPropertyValues().isEmpty();
    }


    // Read-only attributes

    /**
     * Return whether this a <b>Singleton</b>, with a single, shared instance
     * returned on all calls.
     * @see #SCOPE_SINGLETON
     * 擷取這個Bean是否是單例的
     */
    boolean isSingleton();

    /**
     * Return whether this a <b>Prototype</b>, with an independent instance
     * returned for each call.
     * @since 3.0
     * @see #SCOPE_PROTOTYPE
     * 這個Bean是否是Prototype(
     */
    boolean isPrototype();

    /**
     * Return whether this bean is "abstract", that is, not meant to be instantiated.
     * 這個Bean是否是抽象的
     */
    boolean isAbstract();

    /**
     * Get the role hint for this {@code BeanDefinition}. The role hint
     * provides the frameworks as well as tools with an indication of
     * the role and importance of a particular {@code BeanDefinition}.
     * @see #ROLE_APPLICATION
     * @see #ROLE_SUPPORT
     * @see #ROLE_INFRASTRUCTURE
     * 擷取Role角色的值
     */
    int getRole();

    /**
     * Return a human-readable description of this bean definition.
     * 擷取描述
     */
    @Nullable
    String getDescription();

    /**
     * Return a description of the resource that this bean definition
     * came from (for the purpose of showing context in case of errors).
     * 擷取資源的描述
     */
    @Nullable
    String getResourceDescription();

    /**
     * Return the originating BeanDefinition, or {@code null} if none.
     * Allows for retrieving the decorated bean definition, if any.
     * <p>Note that this method returns the immediate originator. Iterate through the
     * originator chain to find the original BeanDefinition as defined by the user.
     * 擷取原始的BeanDefinition
     */
    @Nullable
    BeanDefinition getOriginatingBeanDefinition();

}
           

三、配置Bean的工廠接口

可以在裡面,對Bean的作用範圍等資訊進行配置

四、Bean的定義主要有以下幾個方面

表1.bean的定義

屬性 解釋
執行個體化Bean
名稱 給Bean命名
範圍 Bean的範圍
構造函數參數 依賴注入
自動裝配的模式 自動裝配的合作者
延遲加載模式 延遲加載Bean
初始化方法 初始化回調
銷毀方法 銷毀方法的回調

注意:

除了包含有關如何建立特定bean的資訊的bean定義之外,這些ApplicationContext實作還允許使用者注冊在容器外部建立的現有對象。這是通過getBeanFactory()傳回BeanFactory實作的方法通路ApplicationContext的BeanFactory來完成的DefaultListableBeanFactory。DefaultListableBeanFactory 支援通過方法該登記registerSingleton(..)和 registerBeanDefinition(..)。但是,典型的應用程式隻能通過中繼資料bean定義來定義bean。

Bean中繼資料和手動提供的單例執行個體需要盡早注冊,以便容器在自動裝配和其他自省步驟中正确推理它們。雖然重寫現有的中繼資料和現有的單例執行個體在某種程度上受到支援,但在運作時注冊新的Bean(與實時通路工廠同時)并未得到正式支援,并且可能導緻并發通路異常和/或bean容器中的狀态不一緻。

未完待~~~