手把手帶你看spring的配置建立、注入以及擷取bean。
看源碼最好的方式就是定義一個最最基本的流程,從開始debug到你認為懂了為止。
bean的配置
最基本的spring配置是将bean配置在spring的配置檔案中,該配置檔案還可以配置spring的配置屬性,雖然标簽不是<bean>,但是spring會将其注入到指定的類中,是以不論标簽如何,spring都會将配置檔案中的屬性轉化成類屬性,最終建立對應的對象。有的朋友可能已經注意到了:配置都是放在<beans>标簽中的。
bean的生成與注入
啟動spring的入口之一就是建立 ClassPathXmlApplicationContext 對象:
java複制代碼//建立Spring容器的對象:ApplicationContext的實作類 ----> ClassPathXmlApplicationContext
//ApplicationContext就是表示Spring容器,我們可以通過容器擷取對象
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
向下看之前不妨看一下該類的UML關系:
建立ClassPathXmlApplicationContext對象時就能看到整個spring建立對象的流程:
真正調用的是這裡:
這裡的setConfigLocations方法隻是将傳入的配置檔案名注入到本類的configLocations字元串數組變量中。
真正的流程是在refresh方法中,該方法的實作其實是在父類AbstractApplicationContext中:
将一些與主流程相關較小的代碼剔除後如下:
scss複制代碼public void refresh() throws BeansException, IllegalStateException {
//在方法内對别的對象加鎖,使得鎖最小化。
synchronized (this.startupShutdownMonitor) {
//第一步就是建立bean的容器
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
finishBeanFactoryInitialization(beanFactory);
} catch (BeansException ex) {...}
finally {
resetCommonCaches();
contextRefresh.end();
}
}
}
逐漸解析:
- obtainFreshBeanFactory():
- 其中:refreshBeanFactory() 才是建立beanFactory的關鍵:其在 AbstractApplicationContext 類中是抽象方法,需要子類實作,通常調用的是 AbstractRefreshableApplicationContext 類。
- 其中 loadBeanDefinitions(beanFactory) 是最主要的,在子類 AbstractXmlApplicationContext 中 loadBeanDefinitions(beanFactory) 建立了 XmlBeanDefinitionReader 對象。該類封裝了讀配置檔案的邏輯。随後就是調用 XmlBeanDefinitionReader的方法 loadBeanDefinitions : 這個方法在其父類 AbstractBeanDefinitionReader 中實作: AbstractBeanDefinitionReader 将字元串類型的配置檔案名轉化為 Resource 對象,Resource是個接口,繼承了InputStreamSource,Spring中對于檔案的讀取類都需實作該接口。 而通過Resource加載類的方法是在子類 XmlBeanDefinitionReader 實作: 接着就是建立但是真正讀配置檔案的抽象類:BeanDefinitionDocumentReader。 registerBeanDefinitions 在子類 DefaultBeanDefinitionDocumentReader 中實作: 然後挨個解析每一個标簽 這裡的 BeanDefinitionHolder 要注意,這個就是解析bean标簽的生成對象,可以看出,bean 标簽裡設定的屬性都在該對象中,沒有配置的屬性會采用預設值(這也解釋了spring中建立的對象預設是懶加載的)。 随後将對象名和類定義放入【DefaultListableBeanFactory】的 beanDefinitionMap 中。
- 而事實上,後續的流程都是針對 DefaultListableBeanFactory類的。 就此,spring中一個完整的配置檔案中bean的解析、注冊就結束了!!!
- prepareBeanFactory(beanFactory)
- 該方法就隻是為Spring的BeanFactory指派。比如後置處理器,添加一些Spring内部對象等:
- scss複制代碼
- /** * 配置BeanFactory的一些上下文屬性,比如上下文類加載器和後置處理器 * @param 需要指派的beanFactory */ protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { //使用調用類的類加載器 beanFactory.setBeanClassLoader(getClassLoader()); if (!shouldIgnoreSpel) { beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); } beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class); // BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // Register early post-processor for detecting inner beans as ApplicationListeners. beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // Detect a LoadTimeWeaver and prepare for weaving, if found. if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // 注冊預設的環境類對象 if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) { beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup()); } }
- invokeBeanFactoryPostProcessors(beanFactory):
- 該方法主要是加載和執行個體化 BeanFactory 後置處理器(所有實作了 BeanFactoryPostProcessor 接口的類)。後置處理器可以在 Bean 執行個體化、屬性填充、初始化和銷毀等不同的階段對 Bean 進行自定義的處理和增強。典型的後處理器就是org.mybatis.spring.mapper.MapperScannerConfigurer,該類将指定的mapper接口注冊到mybatis的Configuration類的MapperRegistry屬性中。
- registerBeanPostProcessors(beanFactory):
- 主要是将上一步執行個體化的後置處理器對象添加到 beanFactory 的 beanPostProcessors 變量中。
- finishBeanFactoryInitialization(beanFactory):
- 從方法名也能看出該方法是最終的一步:初始化所有的單例模式,所有的非懶加載的類。該方法内封裝的其實就是之前建構的 ConfigurableListableBeanFactory 接口實作類的方法,spring中該接口的實作類用的是 DefaultListableBeanFactory
可以看出,初始化類的時候是會根據類是否是工廠類而作出額外的初始化,最重要的還是 getBean方法。 該方法是 ClassPathXmlApplication 的父類 AbstractApplicationContext 實作的:
而 doGetBean 也是 AbstractBeanFactory 實作的:
scss複制代碼protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object beanInstance;
// 看看有無該類對象的緩存,有則直接傳回
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}else {
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 如果有父類的BeanFactory對象則調用父類BeanFactory獨享的doGetBean方法。
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 先初始化要初始化對象依賴的對象,其實就是遞歸調用getBean。
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// 單例對象的初始化
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//原型模式對象的建立
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
//Spring2.0之後又引入了另外三種scope類型:request、session、global session類型
//隻能在隻能在Web應用中使用,若隻是背景程序的話則不會走該分支。
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
doGetBean 方法是先看看該對象是否已經初始化,如果沒有在建立并初始化,值得注意的是,其是先建立并初始化目前要建立的對象的依賴(還是調用doGetbean),最後再根據對象類型分開建立,但是核心是調用 父類 AbstractAutowireCapableBeanFactory 的 createBean 方法。
createBeanInstance則很有意思,其是先判斷是否由指定工廠建立,再有無注冊的構造方法,最後才會通過反射擷取該類的構造方法構造對象。
instantiate方法在 SimpleInstantiationStrategy類中。
而 BeanUtil.instantiateClass方法則是封裝的的通過構造器擷取對象。
由此,一個對象就被建立結束,而後雖然會對該對象進行一系列封裝,但是歸根結底,spring的bean建立還是上述這些過程。
bean的擷取
其實通過 ClassPathXmlApplicationContext 對象擷取指定類的對象的 getBean 方法其實就是第5步中的方法,對于非懶加載類對象就可以直接擷取,而懶加載類的對象則在此刻建構。
最後再附上一張用到的UML圖:
原文連結:https://juejin.cn/post/7261566651605532727