1. 程式人生 > >java架構之路-(spring原始碼篇)springIOC容器原始碼解析(上)

java架構之路-(spring原始碼篇)springIOC容器原始碼解析(上)

  我們這次來叭叭一下Spring的原始碼,這次部落格主要來說說Spring原始碼,先粗略的擼一遍,下篇部落格選幾個重點去說,由於過於複雜,我也是看了一點點,我們先來過一遍原始碼,然後上流程圖,最後我們再回頭總結一下,我們來循序漸進的叭叭一下。

我們來回顧一下上次Spring部落格的內容,每次都有用到AnnotationConfigApplicationContext來載入我們的配置類,我們就從這裡開始。

/**
     * Create a new AnnotationConfigApplicationContext, deriving bean definitions
     * from the given annotated classes and automatically refreshing the context.  建立新的註釋configapplicationcontext,獲得bean定義並自動重新整理上下文。
     * @param annotatedClasses one or more annotated classes,  我們的配置類
     * e.g. {@link Configuration @Configuration} classes
     */
    public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
        this();
        register(annotatedClasses);
        refresh();
    }

  翻譯過來就是“建立新的註釋configapplicationcontext,獲得bean定義並自動重新整理上下文”。三個方法,我們先來一個個看,優先看父類有沒有構造方法。AnnotationConfigApplicationContext繼承了GenericApplicationContext類,所以我們先看GenericApplicationContext類的構造方法。程式碼很簡單

父類構造方法

/**
 * Create a new GenericApplicationContext.
 * @see #registerBeanDefinition
 * @see #refresh
 */
public GenericApplicationContext() {
  this.beanFactory = new DefaultListableBeanFactory();
}

  這裡建立了一個新的DefaultListableBeanFactory物件,也是我們熟悉的beanFactory物件,記住是DefaultListableBeanFactory物件。我們回到AnnotationConfigApplicationContext的this方法。

this

/**
 * Create a new AnnotationConfigApplicationContext that needs to be populated
 * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
 */
public AnnotationConfigApplicationContext() {
    this.reader = new AnnotatedBeanDefinitionReader(this);//註解型別的解析器
    this.scanner = new ClassPathBeanDefinitionScanner(this);//包掃描器
}

再往下扒一層。看一下那個AnnotatedBeanDefinitionReader註解型別的解析器是怎麼建立的,裡面都有什麼。

/**
 * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry.
 * If the registry is {@link EnvironmentCapable}, e.g. is an {@code ApplicationContext},
 * the {@link Environment} will be inherited, otherwise a new
 * {@link StandardEnvironment} will be created and used.
 * @param registry the {@code BeanFactory} to load bean definitions into,
 * in the form of a {@code BeanDefinitionRegistry}
 * @see #AnnotatedBeanDefinitionReader(BeanDefinitionRegistry, Environment)
 * @see #setEnvironment(Environment)
 */
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
    this(registry, getOrCreateEnvironment(registry)); //優先設定了環境並存在快取內
}

設定了環境,將我們的beanFactory作為引數,做了this呼叫,

/**
 * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry and using
 * the given {@link Environment}.   用registry和Environment建立一個新的AnnnotatedBeanDefinitionReader
 * @param registry the {@code BeanFactory} to load bean definitions into,
 * in the form of a {@code BeanDefinitionRegistry}
 * @param environment the {@code Environment} to use when evaluating bean definition
 * profiles.
 * @since 3.1
 */
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    Assert.notNull(environment, "Environment must not be null");
    this.registry = registry;
    this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

前三行不用看,第四行是用來解析我們@Conditional註解的。可以自己開啟瞧瞧原始碼。我們直接看第五行AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); 也是很重要的程式碼,我們繼續叭叭。

/**
 * Register all relevant annotation post processors in the given registry.
 * @param registry the registry to operate on
 * @param source the configuration source element (already extracted)
 * that this registration was triggered from. May be {@code null}.
 * @return a Set of BeanDefinitionHolders, containing all bean definitions
 * that have actually been registered by this call
 */
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
        BeanDefinitionRegistry registry, @Nullable Object source) {

    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
        if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
            beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
        }
        if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
            beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        }
    }

    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
    if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
    if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition();
        try {
            def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                    AnnotationConfigUtils.class.getClassLoader()));
        }
        catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
                    "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
        }
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    }

    return beanDefs;
}

  原文的註釋為在給定的註冊器中處理所有有意義的後置處理器,基本就是是否包含***,如果包含就set進去。這段程式碼是用來初始化內部的元件的。走到這裡就已經初始化的Bean定義。也就是說我們的容器已經注入了定義資訊,還未例項化。

this方法的上半部分就說完了,我們再來看下半部分的new ClassPathBeanDefinitionScanner,建立一個類路徑掃描器,這個程式碼不多,就是判斷我們是否使用預設的類路徑掃描器。

 1 /**
 2  * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory and
 3  * using the given {@link Environment} when evaluating bean definition profile metadata.
 4  * @param registry the {@code BeanFactory} to load bean definitions into, in the form
 5  * of a {@code BeanDefinitionRegistry}
 6  * @param useDefaultFilters whether to include the default filters for the
 7  * {@link org.springframework.stereotype.Component @Component},
 8  * {@link org.springframework.stereotype.Repository @Repository},
 9  * {@link org.springframework.stereotype.Service @Service}, and
10  * {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
11  * @param environment the Spring {@link Environment} to use when evaluating bean
12  * definition profile metadata
13  * @param resourceLoader the {@link ResourceLoader} to use
14  * @since 4.3.6
15  */
16 public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
17                                       Environment environment, @Nullable ResourceLoader resourceLoader) {
18 
19     Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
20     this.registry = registry;
21 
22     if (useDefaultFilters) {
23         registerDefaultFilters();
24     }
25     setEnvironment(environment);
26     setResourceLoader(resourceLoader);
27 }

我們來直接看一下第23行程式碼,是否註冊一個預設的過濾器(掃描策略)。25行設定環境,26行設定資源載入器。

到這裡就已經制定好了我們的掃描策略了。

有點亂啊梳理一下。

 register(annotatedClasses)

this部分就說你完了,再來看看register(annotatedClasses);字面意思來看是帶著我們的配置檔案註冊,我們來看一下程式碼。

/**
 * Register one or more annotated classes to be processed.
 * <p>Note that {@link #refresh()} must be called in order for the context
 * to fully process the new classes.
 * @param annotatedClasses one or more annotated classes,
 * e.g. {@link Configuration @Configuration} classes
 * @see #scan(String...)
 * @see #refresh()
 */
public void register(Class<?>... annotatedClasses) {
    Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
    this.reader.register(annotatedClasses);
}

用我們上一步的reader解析器去註冊,裡面是一個迴圈方法。最終呼叫doRegisterBean來真正的註冊。這一步我們先來簡單的叫做註冊吧。

 直到這裡其實我們容器還是沒有建立的,這些都是一些前期的準備工作。最後也是最關鍵的一步才是我們的容器的例項化。refresh()方法。內容超多。

@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();
        }

        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                        "cancelling refresh attempt: " + ex);
            }

            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();

            // Reset 'active' flag.
            cancelRefresh(ex);

            // Propagate exception to caller.
            throw ex;
        }

        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}

我們來逐個方法看一下都是做什麼的。

prepareRefresh()建立早期程式監聽器。

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()通知子類重新整理Bean工廠

prepareBeanFactory(beanFactory)配置工廠上下文。

postProcessBeanFactory(beanFactory)處理Bean工廠的後置處理

invokeBeanFactoryPostProcessors例項化並呼叫所有註冊的Bean工廠的後置處理器

registerBeanPostProcessors(beanFactory)註冊Bean工廠的後置處理器

initMessageSource()初始化訊息源

initApplicationEventMulticaster()初始化事件多播器

onRefresh()初始化特殊定義的Bean

registerListeners()註冊事件監聽器

finishBeanFactoryInitialization(beanFactory)例項化剩餘非懶載入Bean

finishRefresh()事件釋出

resetCommonCaches()重新整理快取

就這樣我們的Bean工廠就建立完成了。看著如此簡單吧。後面我們來詳細看一下。內部還有超多的東西。Spring原始碼不建議太過於深入的學習,容易陷進去....

最近搞了一個個人公眾號,會每天更新一篇原創博文,java,python,自然語言處理相關的知識有興趣的小夥伴可以關注一下。