Spring容器創建時refresh()方法源碼分析

入口:

import com.stu.config.RecyleLifeBean;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    @Test
    public void testComponnet1() {
        // 創建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(RecyleLifeBean.class);
        System.out.println("IOC容器創建完畢");

         String str = applicationContext.getEnvironment().getProperty("key");

        // 關閉IOC容器
        applicationContext.close();
    }
}

AbstractApplicationContext抽象類種的refresh():

public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

來深究下這個方法到底幹了些什麼。
首先發現這個加了synchronized鎖,保證容器只有一個被創建。這是加的對象

private final Object startupShutdownMonitor;

這是在構造器中創建的對象:

    public AbstractApplicationContext() {
        this.logger = LogFactory.getLog(this.getClass());
        this.id = ObjectUtils.identityToString(this);
        this.displayName = ObjectUtils.identityToString(this);
        this.beanFactoryPostProcessors = new ArrayList();
        this.active = new AtomicBoolean();
        this.closed = new AtomicBoolean();
        this.startupShutdownMonitor = new Object();
        this.applicationListeners = new LinkedHashSet();
        this.resourcePatternResolver = this.getResourcePatternResolver();
    }

容器創建,到底都做了那些操作。
首先,this.prepareRefresh()方法;

1、狀態設置。
2、有兩個方法,加載了服務器的一些信息和判斷必填項是否都完整。包括文件路徑等

protected void prepareRefresh() {
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);
        if (this.logger.isDebugEnabled()) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Refreshing " + this);
            } else {
                this.logger.debug("Refreshing " + this.getDisplayName());
            }
        }

		// 這兩個方法加載了服務器的一些信息和判斷必填項是否都完整
        this.initPropertySources();
        this.getEnvironment().validateRequiredProperties();
        if (this.earlyApplicationListeners == null) {
            this.earlyApplicationListeners = new LinkedHashSet(this.applicationListeners);
        } else {
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }

        this.earlyApplicationEvents = new LinkedHashSet();
    }

this.obtainFreshBeanFactory()方法:

返回一個bean工廠:

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        this.refreshBeanFactory();
        return this.getBeanFactory();
    }

其中的refreshBeanFactory() 方法:
當前BeanFactory != null就清除當前BeanFactory中的所有單例bean,並將BeanFactory 置爲null。再重新創建一個空的BeanFactory。

 protected final void refreshBeanFactory() throws BeansException {
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }

        try {
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            this.customizeBeanFactory(beanFactory);
            this.loadBeanDefinitions(beanFactory);
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }

接着是this.prepareBeanFactory(beanFactory):
顯然是將上面返回的添加了註解的beanFactory,做一些準備工作。
比較複雜,它主要
1、設置類加載器、標準bean的EL解析、註冊環境信息、和設置後置處理器ApplicationContextAwareProcessor(也包含前置,是BeanPostProcessor的實現類)
2、ignoreDependencyInterface是忽視掉Aware相關的依賴接口,比如EnvironmentAware、EmbeddedValueResolverAware、ApplicationContextAware等
3、registerResolvableDependency註冊依賴,比如beanFactory、ResourceLoader資源類加載、ApplicationEventPublisher事件發佈、ApplicationContext環境上下文設計。
4、添加addBeanPostProcessor和檢查當前環境信息(包括getSystemProperties、getSystemEnvironment等)是否加載,沒有加載則加載。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        beanFactory.setBeanClassLoader(this.getClassLoader());
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));
        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.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
        if (beanFactory.containsBean("loadTimeWeaver")) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

        if (!beanFactory.containsLocalBean("environment")) {
            beanFactory.registerSingleton("environment", this.getEnvironment());
        }

        if (!beanFactory.containsLocalBean("systemProperties")) {
            beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());
        }

        if (!beanFactory.containsLocalBean("systemEnvironment")) {
            beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());
        }

    }

this.postProcessBeanFactory(beanFactory)方法:
該方法是允許再容器初始化完成之前,自定義通過beanFactory對上下文進行操作。

 protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    }

this.invokeBeanFactoryPostProcessors(beanFactory)方法:
實例化並調用所有已註冊的BeanFactoryPostProcessor。

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
        if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

    }

this.registerBeanPostProcessors(beanFactory)方法:
註冊所有BeanPostProcessor

 protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        // 找到所有BeanPostProcessor的實現類,逐一註冊
        PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
    }

this.initMessageSource()方法:
初始化MessageSource組件(做國際化功能;消息綁定,消息解析)。

protected void initMessageSource() {
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if (beanFactory.containsLocalBean("messageSource")) {
            this.messageSource = (MessageSource)beanFactory.getBean("messageSource", MessageSource.class);
            if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
                HierarchicalMessageSource hms = (HierarchicalMessageSource)this.messageSource;
                if (hms.getParentMessageSource() == null) {
                    hms.setParentMessageSource(this.getInternalParentMessageSource());
                }
            }

            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Using MessageSource [" + this.messageSource + "]");
            }
        } else {
            DelegatingMessageSource dms = new DelegatingMessageSource();
            dms.setParentMessageSource(this.getInternalParentMessageSource());
            this.messageSource = dms;
            beanFactory.registerSingleton("messageSource", this.messageSource);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No 'messageSource' bean, using [" + this.messageSource + "]");
            }
        }

    }

實際應用中的體現:(當然你也可以直接用JDK的java.util包中提供了幾個支持本地化的格式化操作工具類:NumberFormat、DateFormat、MessageFormat)。
比如:


//①信息格式化串    
String pattern1 = "呵呵噠";  
String pattern2 = "麼麼噠";  
 
//②用於動態替換佔位符的參數    
Object[] params = {"John", new GregorianCalendar().getTime(), 1.0E3};  
 
//③使用默認本地化對象格式化信息    
String msg1 = MessageFormat.format(pattern1, params);  
 
//④使用指定的本地化對象格式化信息    
MessageFormat mf = new MessageFormat(pattern2, Locale.US);  
String msg2 = mf.format(params);

但是通常我們選擇下面的操作過程。

    @Autowired
    ApplicationContext applicationContext;

    //@Bean
    @Bean("getUserBean")
    public User getUser(){
        String str = applicationContext.getMessage("com.stu",new Object[]{"heheda"}, Locale.US)
        return new User();
    }

this.initApplicationEventMulticaster()方法:
初始化事件監聽多路廣播器(多播器)。beanFactory有多路廣播器則獲得,沒有則註冊applicationEventMulticaster。主要用於事件發佈監聽。

 protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if (beanFactory.containsLocalBean("applicationEventMulticaster")) {
            this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        } else {
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No 'applicationEventMulticaster' bean, using [" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
            }
        }

    }

this.onRefresh()方法:這是空殼子方法。估計是預留方法。
this.registerListeners()方法:
正如文字表現就是該方法作用就是註冊監聽器。這個是和事件發佈相關。
1、先將的ApplicationListener放入this.getApplicationEventMulticaster().addApplicationListener(listener)中,再2、將實現了ApplicationListener.class放入this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
3、發佈早期的監聽器,this.getApplicationEventMulticaster().multicastEvent(earlyEvent);這個反射調用。

protected void registerListeners() {
        Iterator var1 = this.getApplicationListeners().iterator();

        while(var1.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var1.next();
            this.getApplicationEventMulticaster().addApplicationListener(listener);
        }

        String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false);
        String[] var7 = listenerBeanNames;
        int var3 = listenerBeanNames.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            String listenerBeanName = var7[var4];
            this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            Iterator var9 = earlyEventsToProcess.iterator();

            while(var9.hasNext()) {
                ApplicationEvent earlyEvent = (ApplicationEvent)var9.next();
                this.getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }

    }

this.finishBeanFactoryInitialization(beanFactory)方法:
實例化所有的bean。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        if (beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
            beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));
        }

        if (!beanFactory.hasEmbeddedValueResolver()) {
            beanFactory.addEmbeddedValueResolver((strVal) -> {
                return this.getEnvironment().resolvePlaceholders(strVal);
            });
        }

        String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
        String[] var3 = weaverAwareNames;
        int var4 = weaverAwareNames.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String weaverAwareName = var3[var5];
            this.getBean(weaverAwareName);
        }

        beanFactory.setTempClassLoader((ClassLoader)null);
        // 凍結上下文,不允許再進行修改配置
        beanFactory.freezeConfiguration();
        // 實例化預處理
        beanFactory.preInstantiateSingletons();
    }

this.finishRefresh()方法:
初始化生命週期處理器LifecycleProcessor並調用其onrefresh方法,找到SmartLifecycle接口的所有實現類並調用start方法,發佈事件告知listener,如果設置了JMX相關屬性,還會調用LiveBeansView的registerApplicationContext方法。

protected void finishRefresh() {
        // 清空此資源加載器中所有的資源緩存
        this.clearResourceCaches();
        // 爲此上下文初始化生命週期處理器
        this.initLifecycleProcessor();
        // 首先將刷新完畢事件傳播到生命週期處理器
        this.getLifecycleProcessor().onRefresh();
        // 容器完成初始化後調用finishRefresh()時會發布ContextRefreshedEvent事件
        this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
        // 容器完成初始化後調用finishRefresh()時會發布ContextRefreshedEvent事件
        LiveBeansView.registerApplicationContext(this);
    }

清空此資源加載器中所有的資源緩存。
這個涉及到Spring核心之——資源加載器。
DefaultResourceLoader ,默認資源加載器,是 ResourceLoader 接口的默認實現類,用於加載資源配置。AbstractApplicationContext 直接繼承此類。

package org.springframework.core.io;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

/**
 * 通過ResourceEditor來使用,作爲一個基礎類來服務於
 * org.springframework.context.support.AbstractApplicationContext
 *
 * 如果location 的值是一個 URL,將返回一個UrlResource資源;
 * 如果location 的值非URL路徑或是一個"classpath:"相對URL,則返回一個ClassPathResource.
 *
 * @author Juergen Hoeller
 * @since 10.03.2004
 * @see FileSystemResourceLoader
 * @see org.springframework.context.support.ClassPathXmlApplicationContext
 */
public class DefaultResourceLoader implements ResourceLoader {

    /**
     * 可爲空的類加載器。
     * 默認情況下,類加載器將在這個ResourceLoader初始化時使用線程上下文類加載器進行訪問。
     */
    @Nullable
    private ClassLoader classLoader;
    /** 路徑協議解析的Set集合 */
    private final Set<ProtocolResolver> protocolResolvers = new LinkedHashSet<>(4);

    /** 用於資源緩存的Map的映射集 */
    private final Map<Class<?>, Map<Resource, ?>> resourceCaches = new ConcurrentHashMap<>(4);


    /**
     * 無參構造方法創建一個新的DefaultResourceLoader對象,並設置類加載器.
     * @see java.lang.Thread#getContextClassLoader()
     */
    public DefaultResourceLoader() {
        /**
         * 底層實現是按以下遞進獲取,有則返回:
         * 當前線程的類加載、ClassUtils.class 的加載器、系統類加載
         */
        this.classLoader = ClassUtils.getDefaultClassLoader();
    }

    /**
     * 有參構造方法,主動注入一個類加載
     * @param classLoader 用來加載類路徑資源的類加載器,因爲這個類加載器可以null,所以可傳null值
     */
    public DefaultResourceLoader(@Nullable ClassLoader classLoader) {
        this.classLoader = classLoader;
    }


    /**
     * setter 方法注入一個(可爲null)的類加載器
     */
    public void setClassLoader(@Nullable ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    /**
     * 返回用於加載類資源的類加載器。
     * 如果未null,則通過ClassUtils.getDefaultClassLoader()重新獲取。
     * @see ClassPathResource
     */
    @Override
    @Nullable
    public ClassLoader getClassLoader() {
        return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());
    }

    /**
     * 用這個資源加載器註冊給定的解析器(前面的文章也講說,解析器用於解析多個資源路徑)。
     * 任何這樣的解析器都會在這個加載程序的標準解析規則之前被調用。
     * 因此,它還可能覆蓋任何默認規則。
     * @since 4.3
     * @see #getProtocolResolvers()
     */
    public void addProtocolResolver(ProtocolResolver resolver) {
        Assert.notNull(resolver, "ProtocolResolver must not be null");
        this.protocolResolvers.add(resolver);
    }

    /**
    * 返回當前註冊的協議解析器集合,允許進行自行修改。
     * @since 4.3
     */
    public Collection<ProtocolResolver> getProtocolResolvers() {
        return this.protocolResolvers;
    }

    /**
     * 獲取由 Resource 鍵入的給定值類型的緩存。
     * @param valueType 值類型, 比如一個 ASM MetadataReader
     * @return Map緩存, 在ResourceLoader級別進行分享
     * @since 5.0
     */
    @SuppressWarnings("unchecked")
    public <T> Map<Resource, T> getResourceCache(Class<T> valueType) {
        return (Map<Resource, T>) this.resourceCaches.computeIfAbsent(valueType, key -> new ConcurrentHashMap<>());
    }

    /**
     * 清空此資源加載器中所有的資源緩存
     * @since 5.0
     * @see #getResourceCache
     */
    public void clearResourceCaches() {
        this.resourceCaches.clear();
    }

    /**
     * 從指定的路徑獲取資源,不能爲null
     *
     * 獲取資源的優先策略從高到底依次是:
     * 1.從協議解析器集合遍歷每個協議器嘗試解析指定位置的資源;
     * 2.從"/"開頭的絕對路徑嘗試解析資源;
     * 3.從"classpath:"的類相對路徑解析資源;
     * 4.最後從網絡URL處解析資源。
     */
    @Override
    public Resource getResource(String location) {
        Assert.notNull(location, "Location must not be null");
        // 遍歷協議解析器的集合
        for (ProtocolResolver protocolResolver : this.protocolResolvers) {
            // 然後用當前的協議解析來解析指定路徑的資源
            Resource resource = protocolResolver.resolve(location, this);
            if (resource != null) {
                // 如果在當前協議解析器下解析的資源不爲空,則返回該資源
                return resource;
            }
        }
        // 程序運行到這裏,要麼說明協議解析器集合爲空,
        // 要麼說明協議解析器集合中的所有協議解析器解析指定位置的資源都爲null
        // 那麼就對資源路徑判斷
        if (location.startsWith("/")) {
            // 此方法是本類中的方法,下面分析
            return getResourceByPath(location);
        }
        // 如果資源路徑不以 "/" 爲開始的絕對路徑標識,
        // 則判斷是否以默認方式 "classpath:" 開頭
        else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
            // 如果以默認的"classpath:"開頭,則說明資源是類路徑的相對資源
            return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
        }
        // 在不然,就嘗試從遠處網絡URL資源加載
        else {
            try {
                // 嘗試將路徑位置解析爲URL…
                URL url = new URL(location);
                return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
            }
            catch (MalformedURLException ex) {
                // 沒有URL可以解析爲資源路徑
                return getResourceByPath(location);
            }
        }
    }

    /**
     * 返回給定路徑上的資源地址引用。
     * 默認實現支持類路徑位置。 這應該適用於獨立實現,但可以被重寫,
     * 比如:用於針對Servlet容器的實現。
     * @param path 資源的路徑
     * @return 對應的資源引用
     * @see ClassPathResource
     * @see org.springframework.context.support.FileSystemXmlApplicationContext#getResourceByPath
     * @see org.springframework.web.context.support.XmlWebApplicationContext#getResourceByPath
     */
    protected Resource getResourceByPath(String path) {
        return new ClassPathContextResource(path, getClassLoader());
    }


    /**
     * 類路徑庫,通過實現上下文源接口顯式地表示上下文相關路徑。
     */
    protected static class ClassPathContextResource extends ClassPathResource implements ContextResource {

        public ClassPathContextResource(String path, @Nullable ClassLoader classLoader) {
            super(path, classLoader);
        }

        @Override
        public String getPathWithinContext() {
            return getPath();
        }

        @Override
        public Resource createRelative(String relativePath) {
            String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath);
            return new ClassPathContextResource(pathToUse, getClassLoader());
        }
    }
}

初始化異常,則調用如下兩個方法,銷燬beans、取消剛開始設置的刷新狀態
this.destroyBeans() 和this.cancelRefresh(var9);

銷燬beans:

 protected void destroyBeans() {
        this.getBeanFactory().destroySingletons();
    }

取消剛開始設置的刷新狀態:

 protected void cancelRefresh(BeansException ex) {
        this.active.set(false);
    }

最後執行 this.resetCommonCaches()方法:

    protected void resetCommonCaches() {
        // 清空反射集合
        ReflectionUtils.clearCache();
        // 清空註解集合
        AnnotationUtils.clearCache();
        // ResolvableType更好的處理泛型,清除泛型集合
        ResolvableType.clearCache();
        // 清除當前類加載器
        CachedIntrospectionResults.clearClassLoader(this.getClassLoader());
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章