1. 程式人生 > >最簡 Spring IOC 容器原始碼分析

最簡 Spring IOC 容器原始碼分析

![](https://img2020.cnblogs.com/other/633265/202012/633265-20201210214458574-271718932.png) - [前言](#前言) - [BeanDefinition](#beandefinition) - [BeanFactory 簡介](#beanfactory-簡介) - [Web 容器啟動過程](#web-容器啟動過程) - [bean 的載入](#bean-的載入) - [FactoryBean](#factorybean) - [迴圈依賴](#迴圈依賴) - [bean 生命週期](#bean-生命週期) - [公眾號](#公眾號) # 前言 許多文章都是分析的 xml 配置,但是現在 Spring Boot 開發多基於註解。本文從`註解`的角度分析 Spring IOC 容器原始碼。 版本: - Spring Boot:2.1.6.RELEASE - Spring FrameWork:5.1.8.RELEASE - Java 8 文章部分內容參考自:https://www.javadoop.com/post/spring-ioc # BeanDefinition BeanDefinition 介面定義了一個包含屬性、構造器引數、其他具體資訊的 bean 例項。 ```java public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { // ConfigurableBeanFactory 中只有 2 種:singleton 和 prototype。 // request, session 等是基於 Web 的擴充套件 String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; // 不重要 int ROLE_APPLICATION = 0; int ROLE_SUPPORT = 1; int ROLE_INFRASTRUCTURE = 2; // 設定父 Bean 的資訊(繼承父 Bean 的配置資訊) void setParentName(@Nullable String parentName); @Nullable String getParentName(); // 設定 Bean 的類名稱,要通過反射來生成例項 void setBeanClassName(@Nullable String beanClassName); // 返回當前 Bean 的 class name String getBeanClassName(); void setScope(@Nullable String scope); @Nullable String getScope(); // 是否延遲初始化 void setLazyInit(boolean lazyInit); boolean isLazyInit(); // 設定該 Bean 依賴的所有的 Bean,並非 @Autowire 標記的 void setDependsOn(@Nullable String... dependsOn); @Nullable String[] getDependsOn(); // 設定該 Bean 是否可以注入到其他 Bean 中,只對根據型別注入有效, // 如果根據名稱注入,即使這邊設定了 false,也是可以的 void setAutowireCandidate(boolean autowireCandidate); boolean isAutowireCandidate(); // 同一介面的多個實現,如果不指定名字,Spring 會優先選擇設定 primary 為 true 的 bean void setPrimary(boolean primary); boolean isPrimary(); // 如果該 Bean 採用工廠方法生成,指定工廠名稱;否則用反射生成 void setFactoryBeanName(@Nullable String factoryBeanName); @Nullable String getFactoryBeanName(); // 指定工廠類中的 工廠方法名稱 void setFactoryMethodName(@Nullable String factoryMethodName); @Nullable String getFactoryMethodName(); // 返回該 bean 的構造器引數 ConstructorArgumentValues getConstructorArgumentValues(); default boolean hasConstructorArgumentValues() { return !getConstructorArgumentValues().isEmpty(); } // Bean 中的屬性值,返回的例項在 bean factory post-processing 期間會被更改 MutablePropertyValues getPropertyValues(); default boolean hasPropertyValues() { return !getPropertyValues().isEmpty(); } void setInitMethodName(@Nullable String initMethodName); @Nullable String getInitMethodName(); void setDestroyMethodName(@Nullable String destroyMethodName); @Nullable String getDestroyMethodName(); void setRole(int role); int getRole(); void setDescription(@Nullable String description); @Nullable String getDescription(); // Read-only attributes boolean isSingleton(); boolean isPrototype(); boolean isAbstract(); @Nullable String getResourceDescription(); @Nullable BeanDefinition getOriginatingBeanDefinition(); } ``` AnnotationConfigUtils#processCommonDefinitionAnnotations(...) ```java static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) { AnnotationAttributes lazy = attributesFor(metadata, Lazy.class); if (lazy != null) { abd.setLazyInit(lazy.getBoolean("value")); } else if (abd.getMetadata() != metadata) { lazy = attributesFor(abd.getMetadata(), Lazy.class); if (lazy != null) { abd.setLazyInit(lazy.getBoolean("value")); } } if (metadata.isAnnotated(Primary.class.getName())) { abd.setPrimary(true); } AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class); if (dependsOn != null) { abd.setDependsOn(dependsOn.getStringArray("value")); } AnnotationAttributes role = attributesFor(metadata, Role.class); if (role != null) { abd.setRole(role.getNumber("value").intValue()); } AnnotationAttributes description = attributesFor(metadata, Description.class); if (description != null) { abd.setDescription(description.getString("value")); } } ``` 可以看到,processCommonDefinitionAnnotations 方法會根據註解來填充 AnnotatedBeanDefinition,這些註解有: - Lazy - Primary - DependsOn - Role - Description 向上檢視呼叫,發現會在 ConfigurationClassBeanDefinitionReader#registerBeanDefinitionForImportedConfigurationClass 將其註冊為一個 bean definition。 ```java private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) { AnnotationMetadata metadata = configClass.getMetadata(); AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata); ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef); configBeanDef.setScope(scopeMetadata.getScopeName()); String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry); // 1. 通過註解填充 configBeanDef AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata); BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); // 2. 將 bean definition 註冊到 registry 中 this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition()); configClass.setBeanName(configBeanName); if (logger.isTraceEnabled()) { logger.trace("Registered bean definition for imported class '" + configBeanName + "'"); } } ``` 最終會被 AbstractApplicationContext#refresh 的 invokeBeanFactoryPostProcessors(beanFactory) 方法呼叫。 ```java @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } ... } } ``` # BeanFactory 簡介 BeanFactory 是生產 bean 的工廠,它負責生產和管理各個 bean 例項。從下圖可以看到,ApplicationContext 也是一個 BeanFactory。如果說 BeanFactory 是 Spring 的心臟,那麼 ApplicationContext 就是完整的身軀。 ![](https://img2020.cnblogs.com/other/633265/202012/633265-20201210214458881-2064030292.jpg) ApplicationContext 是應用程式執行時提供配置資訊的通用介面。ApplicationContext 在程式執行時是不可更改的,但是實現類可以重新再入配置資訊。 ApplicationContext 的實現類有很多,比如 AnnotationConfigApplicationContext, AnnotationConfigWebApplicationContext, ClassPathXmlApplicationContext, FileSystemXmlApplicationContext, XmlWebApplicationContext 等。我們上面分析的就是 AnnotationConfigApplicationContext,其採用註解的方式提供配置資訊,這樣我們就不用寫 XML 配置檔案了,非常簡潔。 ![](https://img2020.cnblogs.com/other/633265/202012/633265-20201210214459303-1334789932.jpg) # Web 容器啟動過程 本文使用 Spring Boot 開發,其啟動的程式碼是: ```java @SpringBootApplication @EnableScheduling @EnableAspectJAutoProxy public class AppApplication { public static void main(String[] args) { SpringApplication.run(AppApplication.class, args); } } ``` 核心的點是這一句: ```java SpringApplication.run(AppApplication.class, args); ``` SpringApplication 的程式碼就不分析了,明確本次看原始碼的目的是分析`容器原始碼`,Spring Boot 的啟動過程和其他資訊都忽略了,因為 Spring 程式碼實在是龐雜。分析上面的 run 方法,最終會追蹤到 SpringApplication#run(...) 方法。 ```java public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Co