【啃啊啃 Spring5 源碼】細(xì)碎四:核心類總結(jié)

[TOC]

閱讀spring源碼時,有許多 “核心類” 的作用我們了解了,才會閱讀的更順暢。這里總結(jié)下我閱讀源碼時認(rèn)為比較重要,需要了解的一些 “核心類”

注:本文前三節(jié) 為參考【Spring4揭秘 基礎(chǔ)2】PropertySource和Enviroment系列文章,進(jìn)行的總結(jié)擴展

1. 資源配置相關(guān)

1.1 Resource

public interface Resource extends InputStreamSource {  
       URL getURL() throws IOException;  
       URI getURI() throws IOException;  
       File getFile() throws IOException;  
       
       …………
}  

Resource 主要是對spring中各種資源(包括文件系統(tǒng)資源、class路徑資源、Byte、servletContext資源、url資源)的抽象,spring中xml配置文件便是通過Resource 子類讀取。

它繼承了InputStreamSource接口,子類通過重寫getInputStream()方法,便可輕松的讀取各種資源。解決了Java中不同資源讀取需求寫不同代碼的困難。

常見子類

  • ClassPathResource:對class文件的讀取,默認(rèn)路徑為項目根路徑(/target),也可指定Class或ClassLoader來獲取不同路徑。
  • FileSystemResource:對文件系統(tǒng)資源的讀和寫,路徑為文件系統(tǒng)路徑,例如windos中:“D://a.json”
  • ByteArrayResource:對byte[]數(shù)組資源的讀取
  • UrlResource:對url網(wǎng)絡(luò)資源的讀取
  • ServletContextResource:對web工程中文件的讀取。通過ServletContext讀取webRoot目錄下的資源
  • InputStreamResource:對輸入流資源的讀取,直接通過給定的輸入流讀取。
  • BeanDefinitionResource:對BeanDefinition的讀取,主要通過getBeanDefinition()方法,而不是getInputStream()

1.2 ResourceLoader

public interface ResourceLoader {
     /**
      * 根據(jù)給定的路徑,返回不同的Resource。例如路徑中包含“classpath:”,則返回ClassPathResource
       */
    Resource getResource(String location);
}

從源碼也可以看出,ResourceLoader其實就是Resource的工廠類。根據(jù)資源位置 “l(fā)ocation” 的不同,返回不同的Resource供使用者讀取資源。

常見子類

  • DefaultResourceLoaderResourceLoader的基本功能實現(xiàn)類。返回Resource的策略為:location中包含“classpath:”,則返回ClassPathResource;包含“/”或出現(xiàn)異常返回ClassPathContextResource;其他情況返回UrlResource;
  • FileSystemResourceLoader:繼承DefaultResourceLoader,重寫getResourceByPath()方法,返回文件資源加載類FileSystemContextResource
  • ServletContextResourceLoader:繼承DefaultResourceLoader,重寫getResourceByPath()方法,返回servletContext資源加載類ServletContextResource
    image.png

1.3 ResourcePatternResolver

public interface ResourcePatternResolver extends ResourceLoader {

    /**
     * 多resource匹配location 前綴
     */
    String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

    /**
     * 根據(jù)給定路徑返回多個資源
     */
    Resource[] getResources(String locationPattern) throws IOException;
}

ResourcePatternResolver繼承ResourceLoader接口,增加了getResources()方法用于根據(jù)匹配多個資源返回。例如對于路徑:“classpath:.xml” 將匹配class路徑下的所有的xml文件,加載成對應(yīng)Resource后返回。

常見子類

  • PathMatchingResourcePatternResolver:接口的基礎(chǔ)功能實現(xiàn)類,從類名也可看出,可解析通配符路徑(如“application*.xml”)來返回Resources
  • ServletContextResourcePatternResolver:解析webRoot目錄下的通配符路徑,返回Resources
  • ApplicationContext:spring中的容器接口也繼承了ResourcePatternResolver接口,代表spring中的所有容器都有根據(jù)通配符路徑獲取資源的功能

2. 環(huán)境屬性相關(guān)

2.1 PropertySource

public abstract class PropertySource<T> {
    protected final String name;//屬性源名稱
    protected final T source;//屬性源(包含鍵值對的對象,如Properties、Map、ServletContext等)
    public String getName();  //獲取屬性源的名字  
    public T getSource();        //獲取屬性源  
    public boolean containsProperty(String name);  //是否包含某個屬性  
    public abstract Object getProperty(String name);   //得到屬性名對應(yīng)的屬性值   
} 

PropertySource 代表包含若干鍵值對(key-value)的數(shù)據(jù)源(source)。這個源可以是PropertiesMap、ServletContext等。在spring中,讀取的propertie配置、servlet中的環(huán)境參數(shù)、乃至JDK系統(tǒng)參數(shù)、系統(tǒng)變量,都會以PropertySource的形式存在。

常見子類

  • MapPropertySource:source為一個Map,也就是鍵值對存在Map中
  • PropertiesPropertySource:從名字也可以看出,該類代表properties文件中鍵值對。繼承MapPropertySource,source為Properties對象(Properties繼承了HashMap,所以PropertiesPropertySource也是一個MapPropertySource)。
  • SystemEnvironmentPropertySource:繼承MapPropertySource,source為Map對象,代表系統(tǒng)中的環(huán)境變量,如JAVA_HOME、MABEN_HOME之類。 與MapPropertySource不同的是,取值時它將會忽略大小寫,”.”和”_”將會轉(zhuǎn)化
  • ResourcePropertySource:source為Resource,代表spring中resource資源(例如:“/com/myco/foo.properties”、“file:/path/to/file.xml”)中的鍵值對屬性
  • ServletContextPropertySource:source為ServletContext,代表web環(huán)境中的servlet上下文中的參數(shù)

2.2 PropertySources

public interface PropertySources extends Iterable<PropertySource<?>> {

    /**
     * 返回是否包含該名稱的PropertySource
     */
    boolean contains(String name);

    /**
     *返回指定名稱的PropertySource
     */
    @Nullable
    PropertySource<?> get(String name);

}

PropertySources即多個PropertySource,可看成PropertySource集合。

常見子類

  • MutablePropertySources:PropertySources接口的默認(rèn)也是唯一實現(xiàn)類,內(nèi)部維護了一個PropertySource的集合(CopyOnWriteArrayList實現(xiàn))。支持向集合的頭部、末尾、及指定位置添加PropertySource

2.3 PropertyResolver

public interface PropertyResolver {  

    //是否包含某個屬性  
    boolean containsProperty(String key);  

    //獲取屬性值 如果找不到返回null   
    String getProperty(String key);  

    //獲取屬性值,如果找不到返回默認(rèn)值        
    String getProperty(String key, String defaultValue);  

    //獲取指定類型的屬性值,找不到返回null  
    <T> T getProperty(String key, Class<T> targetType);  

    //獲取指定類型的屬性值,找不到返回默認(rèn)值  
    <T> T getProperty(String key, Class<T> targetType, T defaultValue);  

    //獲取屬性值為某個Class類型,找不到返回null,如果類型不兼容將拋出ConversionException  
    <T> Class<T> getPropertyAsClass(String key, Class<T> targetType);  

    //獲取屬性值,找不到拋出異常IllegalStateException  
    String getRequiredProperty(String key) throws IllegalStateException;  

    //獲取指定類型的屬性值,找不到拋出異常IllegalStateException         
    <T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException;  

    //替換文本中的占位符(${key})到屬性值,找不到不解析  
    String resolvePlaceholders(String text);  

    //替換文本中的占位符(${key})到屬性值,找不到拋出異常IllegalArgumentException  
    String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;  
}  

實現(xiàn)PropertyResolver接口的子類,一般擁有了PropertySources的成員變量,該接口主要用于從PropertySources中獲取對應(yīng)屬性。

從接口的resolvePlaceholders()方法可以看出,該接口還有解析文本,將文本中占位符轉(zhuǎn)換為PropertySources對應(yīng)屬性的功能。spring配置文件中的占位符最后便是這樣被替換成對應(yīng)的屬性。

2.4 Environment

public interface Environment extends PropertyResolver {  
        //得到當(dāng)前激活的配置環(huán)境 
    String[] getActiveProfiles();  

        //得到默認(rèn)激活的配置環(huán)境
    String[] getDefaultProfiles();  

        //是否接受某些配置環(huán)境
    boolean acceptsProfiles(String... profiles);  
}  

Environment接口繼承了PropertyResolver接口,主要添加了“激活配置環(huán)境”功能。

在實際開發(fā)中,一般維護了多套開發(fā)環(huán)境,例如:dev、test、uat、prodcut。每種開發(fā)環(huán)境的配置是有差別的,spring中實現(xiàn)了多環(huán)境配置的功能:

如下,定義了test、dev兩個配置環(huán)境,它們加載的bean并不相同,啟動spring時,可指定active profile來加載指定配置環(huán)境下的bean

    <beans profile="test">
        <bean class="test.wsz.spring.aop.AspectDemo" />
        <bean id="a" class="test.wsz.spring.bean.A" >
            <constructor-arg value="wsz1" index="0" />
        </bean>
    </beans>

    <beans profile="dev">
        <bean id="b" class="test.wsz.spring.bean.B" />
        <bean class="test.wsz.spring.postProcess.MyBeanPostProcessor" />
    </beans>

常見子類

  • AbstractEnvironmentEnvironment的具體功能實現(xiàn)類
  • StandardEnvironment:標(biāo)準(zhǔn)環(huán)境類,會自動注冊System.getProperties()中的屬性到環(huán)境中。spring應(yīng)用啟動時采用該環(huán)境類。
  • StandardServletEnvironment:標(biāo)準(zhǔn)servlet環(huán)境類,web應(yīng)用時采用。

3. bean配置相關(guān)

spring中bean對象的生成可以分成兩步:

  1. 讀取配置文件中bean的配置,將其轉(zhuǎn)換為bean配置類:BeanDefinition(持有beanName、beanClass、properties等信息)
  2. 根據(jù)BeanDefinition中的配置信息,實例化并初始化bean

本節(jié)主要介紹第一步,bean配置相關(guān)的類。

3.1 BeanDefinition

ublic interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

    //單例或原型
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; 
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

     //Bean角色
    int ROLE_APPLICATION = 0; 
    int ROLE_SUPPORT = 1; 
    int ROLE_INFRASTRUCTURE = 2;

    // 返回/設(shè)置父BeanDefinition 
    String getParentName(); 
    void setParentName(String parentName);

    //返回/設(shè)置 當(dāng)前的BeanClassName(不等于最終Bean的名稱)
    String getBeanClassName(); 
    void setBeanClassName(String beanClassName);

    //返回設(shè)置 factory bean name  
    String getFactoryBeanName(); 
    void setFactoryBeanName(String factoryBeanName);

    String getFactoryMethodName(); 
    void setFactoryMethodName(String factoryMethodName);
    
    //返回/設(shè)置 bean的Scope:單例、原型等等
    String getScope(); 
    void setScope(String scope);

    //返回/設(shè)置 bean是否懶加載
    boolean isLazyInit(); 
    void setLazyInit(boolean lazyInit);

    String[] getDependsOn(); 
    void setDependsOn(String... dependsOn);

    boolean isAutowireCandidate(); 
    void setAutowireCandidate(boolean autowireCandidate);

    boolean isPrimary(); 
    void setPrimary(boolean primary);

    ConstructorArgumentValues getConstructorArgumentValues();
    
    //返回/設(shè)置 bean的屬性
    MutablePropertyValues getPropertyValues(); 
    boolean isSingleton(); 
    boolean isPrototype(); 
    boolean isAbstract(); 
    int getRole(); 
    String getDescription(); 
    String getResourceDescription(); 
    BeanDefinition getOriginatingBeanDefinition();
}

從接口方法可以看出,BeanDefiniton主要包含了bean的名稱、class、scope、屬性、描述、懶加載等配置信息。

常見子類

  • GenericBeanDefinition:一個綜合性的標(biāo)準(zhǔn)BeanDefiniton,包含了BeanDefinition中的主要功能
  • AnnotatedGenericBeanDefinition:一個注解式的標(biāo)準(zhǔn)BeanDefiniton,繼承了GenericBeanDefinition,在其基礎(chǔ)上增加了對類注解配置的支持,即可通過該類獲取注解配置。
  • ConfigurationClassBeanDefinition:如果spring中的配置是用類來表示的,則解析后生成的bean配置類為該類
image.png

3.2 BeanDefinitionHolder

public class BeanDefinitionHolder implements BeanMetadataElement {

    private final BeanDefinition beanDefinition;

    private final String beanName;

    @Nullable
    private final String[] aliases;

    public boolean matchesName(@Nullable String candidateName) {
        ……省略
    }
}

從類代碼中可以看出,BeanDefinitionHolder其實就是一個持有了beanDefinition和bean名稱beanName,及bean的別名數(shù)組aliases的類。

matchesName()方法可以知道,該類能夠在beanDefinition注冊時,匹配占位符,如果匹配中則注冊該BeanDefinition

3.3 BeanDefinitionRegistry

public interface BeanDefinitionRegistry extends AliasRegistry {

     // 注冊一個BeanDeinition
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException;

     // 刪除注冊的BeanDeinition
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    //獲取注冊的BeanDefinition
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    boolean containsBeanDefinition(String beanName);

    String[] getBeanDefinitionNames();

    int getBeanDefinitionCount();

    boolean isBeanNameInUse(String beanName);

}

BeanDefinitionRegistry接口定義了‘注冊/獲取BeanDefinition’的方法。實現(xiàn)該接口的子類一般都維護了一個BeanDeinition集合:Map<String, BeanDefinition> beanDefinitionMap

常見子類

  • DefaultListableBeanFactory:這個類是spring容器功能的核心類,它實現(xiàn)了BeanDefinitionRegistry接口,代表spring中的beanFactory基本都有注冊、刪除BeanDefinition的功能
  • GenericApplicationContext:從類名也可以看出,該類是spring上下文的主要功能實現(xiàn)類,該類對BeanDefinition的注冊、刪除,實際是委托DefaultListableBeanFactory來實現(xiàn)
  • SimpleBeanDefinitionRegistryBeanDefinitionRegistry接口功能的簡單實現(xiàn),主要用來測試功能的……

3.4 BeanDefinitionReader

public interface BeanDefinitionReader {
    //獲取BeanDefinition的注冊器
    BeanDefinitionRegistry getRegistry();

    //獲取用于加載配置的ResourceLoader(上文有提到)
    ResourceLoader getResourceLoader();

    //獲取用于加載bean class的ClassLoader
    ClassLoader getBeanClassLoader();

    BeanNameGenerator getBeanNameGenerator();

        //加載解析配置,并注冊解析后的BeanDefinition
    int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;

        //加載解析多個配置,并注冊解析后的BeanDefinition
    int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;

    //根據(jù)配置路徑,加載解析配置,并注冊解析后的BeanDefinition
    int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;

    //根據(jù)多個配置路徑,加載解析多個配置,并注冊解析后的BeanDefinition
    int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;

}

BeanDefinitionReader接口的方法可以看出,這個接口主要實現(xiàn)了 直接從配置中加載并注冊所有BeanDefinition的功能,注冊的動作實際委托了BeanDefinitionRegister實現(xiàn)。

常見子類

  • AbstractBeanDefinitionReaderBeanDefinitionReader接口的主要功能實現(xiàn)抽象類
  • PropertiesBeanDefinitionReader:用于從properties文件中加載注冊BeanDefinition(ps:我也是第一次知道,properties文件也可以配置bean,配置方式可見該類注釋)
  • XmlBeanDefinitionReader:用于從xml文件中加載注冊BeanDefinition

擴展
上面的BeanDefinitionReader子類都是從配置文件中加載注冊beanDefinition,但是實際應(yīng)用中,我們經(jīng)常采用注解方式來聲明一個bean。那這中注解bean又是如何被發(fā)現(xiàn)并注冊的呢?

注解式bean的加載注冊,主要看兩個類:

  • AnnotatedBeanDefinitionReader:該類并沒有實現(xiàn)BeanDefinitonReader接口,主要根據(jù)bean class來加載注冊BeanDefinition
  • ClassPathBeanDefinitionScanner:從類名也可以看出,該類主要是掃描classpath中的注解類(@Component、@Repository、@Service、@Controller),然后加載注冊對應(yīng)的BeanDefinition

4. bean相關(guān)

4.1 BeanWrapper

public interface BeanWrapper extends ConfigurablePropertyAccessor {

    void setAutoGrowCollectionLimit(int autoGrowCollectionLimit);

    int getAutoGrowCollectionLimit();

    //返回被包裝的bean實例
    Object getWrappedInstance();

    //返回被包裝的bean的class
    Class<?> getWrappedClass();

    //返回被包裝的bean的屬性集合
    PropertyDescriptor[] getPropertyDescriptors();

    //根據(jù)屬性名稱,返回被包裝的bean的屬性
    PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException;

}

BeanWrapper是spring中bean的包裝類的接口,從接口定義的方法可以看出,beanWrapper的子類包含bean的實例及屬性信息。

它的父接口ConfigurablePropertyAccessor定義了setConversionService()方法來設(shè)置屬性轉(zhuǎn)換器(spring中ConversionService負(fù)責(zé)屬性的轉(zhuǎn)換,例如將 字符串“2018-08-20”轉(zhuǎn)換為Date類型)。

ConfigurablePropertyAccessor繼承的TypeConverter接口提供了屬性轉(zhuǎn)換的方法convertIfNecessary()。故BeanWrapper還有將bean中的屬性進(jìn)行轉(zhuǎn)換的功能。

spring中實例化bean結(jié)束后,會將生成的BeanWrapper作為形參傳給populateBean()方法,進(jìn)行bean的初始化:即bean的屬性設(shè)值。這個設(shè)值操作便會用到BeanWrapper的屬性轉(zhuǎn)換功能。

常見子類

  • BeanWrapperImplBeanWrapper接口的默認(rèn)實現(xiàn)。繼承了AbstractNestablePropertyAccessor類,父類中的registerCustomEditor()方法可增加自定義的PropertyEditor屬性編輯器(PropertyEditor和ConversionService一樣用于屬性的轉(zhuǎn)換,具體可看:SpringMVC數(shù)據(jù)類型轉(zhuǎn)換

4.2 ObjectFactory

public interface ObjectFactory<T> {

    //返回一個被工廠管理的實例
    T getObject() throws BeansException;

}

就是一個很簡單工廠接口,在調(diào)用時返回實例。在【啃啊啃 Spring5 源碼】細(xì)碎二:bean的循環(huán)依賴中我們看到過它的運用:

為了解決bean的循環(huán)依賴,bean在第一次獲取時,生成的ObjectFactory對象,getObject()方法實際上會調(diào)用createBean()方法創(chuàng)建bean。而bean在創(chuàng)建的過程中,實例化完成后會重新創(chuàng)建ObjectFactory對象,getObject()方法會變成調(diào)用getEarlyBeanReference(),用于獲取的緩存的實例化的bean。這樣依賴bean再通過ObjectFactory工廠獲取實例時,獲取的便是緩存中的bean。

4.3 FactoryBean

public interface FactoryBean<T> {

    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }

}

FactoryBean對應(yīng)spring中的工廠類bean。即定義的bean實際是一個工廠,可獲取bean。這里不引申了,有興趣的同學(xué)可以自行百度了解。

最后比較下ObjectFactory、FactoryBeanBeanFactory

  1. ObjectFactoryFactoryBean很類似,都是工廠類,用于獲取bean。區(qū)別在于ObjectFactory是在代碼中根據(jù)場景手動調(diào)用getObject()方法獲取bean,而FactoryBean是配置寫好,spring會自動調(diào)用getObject()方法獲取bean。
  2. BeanFactory是容器的父類,管理著bean,并不能簡單的看成工廠類,和前兩者區(qū)別很大

5. 容器相關(guān)

5.1 BeanFactory

public interface BeanFactory {

    String FACTORY_BEAN_PREFIX = "&";

    Object getBean(String name) throws BeansException;

    <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;

    Object getBean(String name, Object... args) throws BeansException;

    <T> T getBean(Class<T> requiredType) throws BeansException;

    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    boolean containsBean(String name);

    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    
    String[] getAliases(String name);

}

BeanFactory是spring容器的核心接口,spring中的容器類,都實現(xiàn)了該接口。定義了獲取bean、獲取bean類型、判斷bean是否單例等基礎(chǔ)方法。

常見子類

BeanFactory下面有三個子接口:

  • HierarchicalBeanFactory:提供容器分層功能,通過getParentBeanFactory()方法獲取父容器
  • ListableBeanFactory:和類名一樣,提供了getBeanDefinitionNames()列出容器內(nèi)所有bean的名字、根據(jù) “type” 獲取所有bean名字 等方法
  • AutowireCapableBeanFactory:提供了自動裝配的功能,根據(jù)類定義BeanDefinition裝配Bean、執(zhí)行前、后處理器等。

主要接口:

  • ConfigurableBeanFactory:該接口包含大量容器工廠的配置方法,從bean的注冊、加載、銷毀、依賴,到后處理器的添加,以及屬性編輯器和類型轉(zhuǎn)換……
  • ConfigurableListableBeanFactoryConfigurableBeanFactory接口的補充,另外還繼承了其余的beanFactory接口,基本包含了BeanFactory體系目前的所有方法,可以看成BeanFactory體系中功能最完善的接口
  • ApplicationContext:spring容器的核心接口,繼承了BeanFactory體系的接口,在其功能上增加了資源加載、事件體制、環(huán)境配置、國際化支持、bean生命周期管理等功能

核心類:

  • DefaultListableBeanFactory:實現(xiàn)了ConfigurableListableBeanFactory接口,spring容器最重要的一個核心類。實現(xiàn)了容器的大部分功能。已經(jīng)廢棄的XmlBeanFactory便是繼承自它。而現(xiàn)在我們使用的ApplicationContext容器子類,也都是組合的它來實現(xiàn)重要功能
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容