[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供使用者讀取資源。
常見子類:
-
DefaultResourceLoader:ResourceLoader的基本功能實現(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)。這個源可以是Properties、Map、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>
常見子類:
-
AbstractEnvironment:Environment的具體功能實現(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對象的生成可以分成兩步:
- 讀取配置文件中bean的配置,將其轉(zhuǎn)換為bean配置類:
BeanDefinition(持有beanName、beanClass、properties等信息) - 根據(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配置類為該類

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) -
SimpleBeanDefinitionRegistry:BeanDefinitionRegistry接口功能的簡單實現(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)。
常見子類:
-
AbstractBeanDefinitionReader:BeanDefinitionReader接口的主要功能實現(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)換功能。
常見子類:
-
BeanWrapperImpl:BeanWrapper接口的默認(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、FactoryBean和BeanFactory:
-
ObjectFactory和FactoryBean很類似,都是工廠類,用于獲取bean。區(qū)別在于ObjectFactory是在代碼中根據(jù)場景手動調(diào)用getObject()方法獲取bean,而FactoryBean是配置寫好,spring會自動調(diào)用getObject()方法獲取bean。 -
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)換…… -
ConfigurableListableBeanFactory:ConfigurableBeanFactory接口的補充,另外還繼承了其余的beanFactory接口,基本包含了BeanFactory體系目前的所有方法,可以看成BeanFactory體系中功能最完善的接口 -
ApplicationContext:spring容器的核心接口,繼承了BeanFactory體系的接口,在其功能上增加了資源加載、事件體制、環(huán)境配置、國際化支持、bean生命周期管理等功能
核心類:
-
DefaultListableBeanFactory:實現(xiàn)了ConfigurableListableBeanFactory接口,spring容器最重要的一個核心類。實現(xiàn)了容器的大部分功能。已經(jīng)廢棄的XmlBeanFactory便是繼承自它。而現(xiàn)在我們使用的ApplicationContext容器子類,也都是組合的它來實現(xiàn)重要功能






