spring原始碼基礎

辉辉、發表於2024-08-17

1.beanDefinition

檢視程式碼
 public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

    //單例
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

    //原型
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


    /**
     * 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

    //設定父的BeanDefinition名稱
    void setParentName(@Nullable String parentName);

    //獲取父的BeanDefinition名稱
    String getParentName();

    //設定beanClass名稱
    void setBeanClassName(@Nullable String beanClassName);

    //獲取beanClass名稱
    @Nullable
    String getBeanClassName();

    //設定作用域
    void setScope(@Nullable String scope);

    //獲取作用域
    @Nullable
    String getScope();

    //設定是否懶載入
    void setLazyInit(boolean lazyInit);

    //是懶載入
    boolean isLazyInit();

    //設定依賴,對應xmlDepend
    void setDependsOn(@Nullable String... dependsOn);

    /**
     * Return the bean names that this bean depends on.
     */
    @Nullable
    String[] getDependsOn();

    //設定自動裝配
    void setAutowireCandidate(boolean autowireCandidate);

    /**
     * Return whether this bean is a candidate for getting autowired into some other 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.
     * @see #setFallback
     */
    void setPrimary(boolean primary);

    /**
     * Return whether this bean is a primary autowire candidate.
     */
    boolean isPrimary();

    /**
     * Set whether this bean is a fallback autowire candidate.
     * <p>If this value is {@code true} for all beans but one among multiple
     * matching candidates, the remaining bean will be selected.
     * @since 6.2
     * @see #setPrimary
     */
    void setFallback(boolean fallback);

    /**
     * Return whether this bean is a fallback autowire candidate.
     * @since 6.2
     */
    boolean isFallback();

    /**
     * Specify the factory bean to use, if any.
     * This is the name of the bean to call the specified factory method on.
     * <p>A factory bean name is only necessary for instance-based factory methods.
     * For static factory methods, the method will be derived from the bean class.
     * @see #setFactoryMethodName
     * @see #setBeanClassName
     */
    void setFactoryBeanName(@Nullable String factoryBeanName);

    /**
     * Return the factory bean name, if any.
     * <p>This will be {@code null} for static factory methods which will
     * be derived from the bean class instead.
     * @see #getFactoryMethodName()
     * @see #getBeanClassName()
     */
    @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.
     * @see #getFactoryBeanName()
     * @see #getBeanClassName()
     */
    @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})
     */
    ConstructorArgumentValues getConstructorArgumentValues();

    /**
     * Return if there are constructor argument values defined for this bean.
     * @since 5.0.2
     * @see #getConstructorArgumentValues()
     */
    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 defined for this bean.
     * @since 5.0.2
     * @see #getPropertyValues()
     */
    default boolean hasPropertyValues() {
       return !getPropertyValues().isEmpty();
    }

    /**
     * Set the name of the initializer method.
     * @since 5.1
     */
    void setInitMethodName(@Nullable String initMethodName);

    /**
     * Return the name of the initializer method.
     * @since 5.1
     */
    @Nullable
    String getInitMethodName();

    /**
     * Set the name of the destroy method.
     * @since 5.1
     */
    void setDestroyMethodName(@Nullable String destroyMethodName);

    /**
     * Return the name of the destroy method.
     * @since 5.1
     */
    @Nullable
    String getDestroyMethodName();

    /**
     * Set the role hint for this {@code BeanDefinition}. The role hint
     * provides the frameworks as well as tools an indication of
     * the role and importance of a particular {@code BeanDefinition}.
     * @since 5.1
     * @see #ROLE_APPLICATION
     * @see #ROLE_SUPPORT
     * @see #ROLE_INFRASTRUCTURE
     */
    void setRole(int role);

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

    /**
     * Set a human-readable description of this bean definition.
     * @since 5.1
     */
    void setDescription(@Nullable String description);

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


    // Read-only attributes

    /**
     * Return a resolvable type for this bean definition,
     * based on the bean class or other specific metadata.
     * <p>This is typically fully resolved on a runtime-merged bean definition
     * but not necessarily on a configuration-time definition instance.
     * @return the resolvable type (potentially {@link ResolvableType#NONE})
     * @since 5.2
     * @see ConfigurableBeanFactory#getMergedBeanDefinition
     */
    ResolvableType getResolvableType();

    /**
     * Return whether this a <b>Singleton</b>, with a single, shared instance
     * returned on all calls.
     * @see #SCOPE_SINGLETON
     */
    boolean isSingleton();

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

    /**
     * Return whether this bean is "abstract", that is, not meant to be instantiated
     * itself but rather just serving as parent for concrete child bean definitions.
     */
    boolean isAbstract();

    /**
     * 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.
     * <p>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.
     */
    @Nullable
    BeanDefinition getOriginatingBeanDefinition();

}

2.AbstractBeanDefinition:定義了預設常量與方法,服務BeanDefinition

檢視程式碼
 public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
       implements BeanDefinition, Cloneable {

    //定義預設的常量
    public static final String SCOPE_DEFAULT = "";
    public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
    public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
    public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;

    /**
     * Constant that indicates autowiring a constructor.
     * @see #setAutowireMode
     */
    public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;

    /**
     * Constant that indicates determining an appropriate autowire strategy
     * through introspection of the bean class.
     * @see #setAutowireMode
     * @deprecated as of Spring 3.0: If you are using mixed autowiring strategies,
     * use annotation-based autowiring for clearer demarcation of autowiring needs.
     */
    @Deprecated
    public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;

    /**
     * Constant that indicates no dependency check at all.
     * @see #setDependencyCheck
     */
    public static final int DEPENDENCY_CHECK_NONE = 0;

    /**
     * Constant that indicates dependency checking for object references.
     * @see #setDependencyCheck
     */
    public static final int DEPENDENCY_CHECK_OBJECTS = 1;

    /**
     * Constant that indicates dependency checking for "simple" properties.
     * @see #setDependencyCheck
     * @see org.springframework.beans.BeanUtils#isSimpleProperty
     */
    public static final int DEPENDENCY_CHECK_SIMPLE = 2;

    /**
     * Constant that indicates dependency checking for all properties
     * (object references as well as "simple" properties).
     * @see #setDependencyCheck
     */
    public static final int DEPENDENCY_CHECK_ALL = 3;

    /**
     * The name of an attribute that can be
     * {@link org.springframework.core.AttributeAccessor#setAttribute set} on a
     * {@link org.springframework.beans.factory.config.BeanDefinition} so that
     * bean definitions can indicate one or more preferred constructors. This is
     * analogous to {@code @Autowired} annotated constructors on the bean class.
     * <p>The attribute value may be a single {@link java.lang.reflect.Constructor}
     * reference or an array thereof.
     * @since 6.1
     * @see org.springframework.beans.factory.annotation.Autowired
     * @see org.springframework.beans.factory.support.RootBeanDefinition#getPreferredConstructors()
     */
    public static final String PREFERRED_CONSTRUCTORS_ATTRIBUTE = "preferredConstructors";

    /**
     * The name of an attribute that can be
     * {@link org.springframework.core.AttributeAccessor#setAttribute set} on a
     * {@link org.springframework.beans.factory.config.BeanDefinition} so that
     * bean definitions can indicate the sort order for the targeted bean.
     * This is analogous to the {@code @Order} annotation.
     * @since 6.1.2
     * @see org.springframework.core.annotation.Order
     * @see org.springframework.core.Ordered
     */
    public static final String ORDER_ATTRIBUTE = "order";

3.包掃描

無非是有兩種:

路徑+類,透過反射獲取到類。

位元組碼操作技術,直接在位元組碼中獲取後設資料,位元組碼包含這個類的一切資訊。

以下程式碼就是將

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {
       // 掃描包路徑,classpath*:com/xxx/**/*.class   匹配這個包以及子包下的class檔案
       String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
             resolveBasePackage(basePackage) + '/' + this.resourcePattern;
       // URL [jar:file:/D:/sourceStudy/spring-framework/spring-study/build/libs/spring-study-6.2.0-SNAPSHOT.jar!/com/ydlclass/bean/Dog.class]
       //Spring會將每一個定義的位元組碼檔案載入成為一個Resource資源
       Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
       boolean traceEnabled = logger.isTraceEnabled();
       boolean debugEnabled = logger.isDebugEnabled();
       for (Resource resource : resources) {
          String filename = resource.getFilename();
          if (filename != null && filename.contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
             // Ignore CGLIB-generated classes in the classpath
             continue;
          }
          if (traceEnabled) {
             logger.trace("Scanning " + resource);
          }
          try {
             MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
             if (isCandidateComponent(metadataReader)) {
                ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                sbd.setSource(resource);
                if (isCandidateComponent(sbd)) {
                   if (debugEnabled) {
                      logger.debug("Identified candidate component class: " + resource);
                   }
                   candidates.add(sbd);
                }
                else {
                   if (debugEnabled) {
                      logger.debug("Ignored because not a concrete top-level class: " + resource);
                   }
                }
             }
             else {
                if (traceEnabled) {
                   logger.trace("Ignored because not matching any filter: " + resource);
                }
             }
          }
          catch (FileNotFoundException ex) {
             if (traceEnabled) {
                logger.trace("Ignored non-readable " + resource + ": " + ex.getMessage());
             }
          }
          catch (ClassFormatException ex) {
             if (shouldIgnoreClassFormatException) {
                if (debugEnabled) {
                   logger.debug("Ignored incompatible class format in " + resource + ": " + ex.getMessage());
                }
             }
             else {
                throw new BeanDefinitionStoreException("Incompatible class format in " + resource +
                      ": set system property 'spring.classformat.ignore' to 'true' " +
                      "if you mean to ignore such files during classpath scanning", ex);
             }
          }
          catch (Throwable ex) {
             throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, ex);
          }
       }
    }
    catch (IOException ex) {
       throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
    }
    return candidates;
}

3.ApplicationContext與BeanFactory區別

ApplicationContext:可以理解成高階容器,具備相對符合的能力。

ListableBeanFactory(具備beanFactoryg管理能力)

HierarchicalBeanFactory 具備分層能力
MessageSource 國籍化能力
ApplicationEventPublisher 事件傳送能力
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
       MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
       ...............
       ..............
4. refresh重新整理過程
public void refresh() throws BeansException, IllegalStateException {
    this.startupShutdownLock.lock();
    try {
       // 啟動關閉執行緒,這個執行緒用來表示啟動當前容器使用的執行緒
       // 該成員變數在之前的版本中並不存在,也是為了支援後續的併發例項化bean的情況
       this.startupShutdownThread = Thread.currentThread();

       // StartupStep是個小工具,用來記錄執行流程
       StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

       // 為當前上下文進行重新整理前的準備
       prepareRefresh();

       // 此處是要初始化一個bean工廠,實時上beanFactory會在上下文構建的就建立了
       // 核心的目的是為了提供一種可以進行重複重新整理的bean工廠的擴充套件,雖然我們不用
       ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

       // 為工廠做一些準備工作,完成一些核心的基礎配置
       // 這是spring-framework需要做的工作
       // 註冊幾個和環境相關的bean,如:environment、systemProperties、systemEnvironment
       prepareBeanFactory(beanFactory);

       try {
          // 空方法,留給子類去實現,GenericXmlApplicationContext沒有進行擴充套件
          // GenericWebApplicationContext進行了擴充套件,註冊了新的作用域,處理了和servlet相關的一些工作
          // 此處是spring提供給第三方的框架如spring-mvc等在容器啟動前做的配置性工作
          postProcessBeanFactory(beanFactory);

          // 記錄新的步驟,post-process
          StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

          // 呼叫所有beanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor的實現類,此時bean沒有進行例項化
          // 我們可以在此處配置beanFactory,修改beanDefinition
          // 此處會處理BeanDefinitionRegistryPostProcessor
          // 執行流程會根據priorityOrdered  Ordered noOrdered進行排序
          // 單獨新增了一個listener的探測器,會在bean例項化後判斷是否是一個listener,如果是進行註冊
          invokeBeanFactoryPostProcessors(beanFactory);

          // 註冊beanPostProcessor,同樣會根據priorityOrdered  Ordered noOrdered進行排序
          registerBeanPostProcessors(beanFactory);
          // 結束步驟
          beanPostProcess.end();

          // 初始化上下文的messageSource
          initMessageSource();

          // 初始化上下文的多播器
          initApplicationEventMulticaster();

          // 留出空方法,讓子類擴充套件
          // ServletWebServerApplicationContext進行了擴充套件,建立一個webServer,啟動tomcat
          onRefresh();

          // 註冊監聽器,此處listenerBean不會被例項化,會議beanName的方式註冊
          // 還會處理一些早期事件
          registerListeners();

          // 核心:例項化所有的非懶載入的單例bean
          finishBeanFactoryInitialization(beanFactory);

          // 完成重新整理,釋出完成重新整理的事件
          finishRefresh();
       }

       // 捕獲執行時異常和錯誤
       catch (RuntimeException | Error ex ) {
          // 如果日誌器支援警告級別,則記錄異常資訊
          if (logger.isWarnEnabled()) {
             logger.warn("Exception encountered during context initialization - " +
                   "cancelling refresh attempt: " + ex);
          }
          // 銷燬已建立的單例,以避免資源洩露
          destroyBeans();
          // 重置'active'標誌
          cancelRefresh(ex);
          // 將異常拋給呼叫者
          throw ex;
       }
       // 無論是否丟擲異常,都會執行的程式碼塊,用於清理工作
       finally {
          contextRefresh.end(); // 結束上下文重新整理過程
       }
    }
    // 無論是否丟擲異常,都會執行的程式碼塊,用於釋放資源
    finally {
       this.startupShutdownThread = null; // 重置啟動/關閉執行緒
       this.startupShutdownLock.unlock(); // 解鎖啟動/關閉鎖
    }

}

相關文章