spring ioc容器之BeanDefinition注冊

?????這段時間開始了對spring的復(fù)習(xí),spring的模塊很多,這里主要對spring ioc容器、aop的實現(xiàn)原理和spring聲明式事務(wù)原理做下探究和總結(jié),給自己后續(xù)復(fù)習(xí)所用。
?????這里以AnnotationConfigApplicationContext作為例子,來探究下spring ioc容器的初始化過程,以及對應(yīng)的BeanDefinition的定位、載入和注冊的過程。

public static void main(String[] args) {
        //編程式啟動spring容器
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        User user = applicationContext.getBean(User.class);
        System.out.println(user);
        user.testMethod();
}

?????這里以編程式啟動和使用spring容器。以AnnotationConfigApplicationContext的實例化開始啟動,實例化BeanDefinitionReader和BeandifinitionScanner。

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
        this();
        register(annotatedClasses);
        //初始化ioc容器
        refresh();
}

public AnnotationConfigApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
}

?????這里看看AnnotatedBeanDefinitionReader,這里面通過AnnotationConfigUtils.registerAnnotationConfigProcessors方法,給容器添加了很多BeanPostProcessor后置處理器,在Bean生命周期的初始化前后進行調(diào)用。類似關(guān)于@Autowired注解功能實現(xiàn)的AutowiredAnnotationProcessor后置處理器,在這里會添加上通用的bean后置處理器到BeanFactory容器中。

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            //容器初始化準備,一些標記的設(shè)立
            prepareRefresh();

            //獲取容器,在這里開啟了BeanDefinition的定位、載入和初始化
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            //配置Classloader和ApplicationContextAwareProcessor
            prepareBeanFactory(beanFactory);

            try {
                //擴展口子,為容器子類提供添加BeanPostProcessor
                postProcessBeanFactory(beanFactory);

                //調(diào)用BeanFactoryPostProcessor的postProcessBeanDefinitionRegistry方法,修改BeanDedifinition的配置元信息
                invokeBeanFactoryPostProcessors(beanFactory);

                //注冊自定義的BeanPostProcessor
                registerBeanPostProcessors(beanFactory);

                //初始化信息源,國際化用到
                initMessageSource();

                //初始化上下文的廣播事件
                initApplicationEventMulticaster();

                //擴展口子,供容器子類初始化的調(diào)用
                onRefresh();

                //注冊事件監(jiān)聽器
                registerListeners();

                //預(yù)實例化所有的單例bean
                finishBeanFactoryInitialization(beanFactory);

                //發(fā)布容器初始化事件
                finishRefresh();
            }

            catch (BeansException ex) {
                // ...
            }

            finally {
                // ..
            }
        }
    }

?????這里大致羅列下BeanFactory在refresh的時候做的事情:

  • prepareRefresh容器初始化準備,設(shè)立一些標記
  • obtainFreshBeanFactory獲取容器,這里開啟了BeanDefinition的定位、載入和初始化。
  • prepareBeanFactory配置Classloader和ApplicationContextAwareProcessor,這里的BeanPostProcessor可以在每個Bean實例化之前設(shè)置beanName和ApplicationContext等其它容器相關(guān)引用。
    -invokeBeanFactoryPostProcessors調(diào)用BeanFactoryPostProcessor的postProcessBeanDefinitionRegistry方法,可以用來修改任何Bean的定義信息,修改Bean定義的。
  • registerBeanPostProcessors注冊自定義的一些后置處理器,可以用來在每個bean初始化前后進行處理。
  • finishBeanFactoryInitialization這里是在容器初始化的時候,對一些需要預(yù)實例化的單例Bean進行提前實例化加載。

?????下面來看初始化容器的核心方法obtainFreshBeanFactory,BeanDefinition的定位、加載和注冊。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    //初始化容器
    refreshBeanFactory();
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    //返回容器
    return beanFactory;
}


protected final void refreshBeanFactory() throws BeansException {
        //如果容器已經(jīng)初始化,銷毀容器
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            //這里去創(chuàng)建了一個DefaultListableBeanFactory作為spring ioc容器的具體容器
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            //這里去加載bean的定義信息BeanDefinition
            loadBeanDefinitions(beanFactory);
            this.beanFactory = beanFactory;
        } catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
}


protected DefaultListableBeanFactory createBeanFactory() {
    return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

?????這里創(chuàng)建了一個DefaultListableBeanFactory作為spring ioc的具體容器實現(xiàn),然后在loadBeanDefinitions里面去加載bean的定義信息。AbstractXmlApplicationContext用來解析加載xml定義的bean信息,AnnotationConfigWebApplicationContext用來解析加載注解配置的bean信息。

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's
        // resource loading environment.
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // then proceed with actually loading the bean definitions.
        initBeanDefinitionReader(beanDefinitionReader);
        loadBeanDefinitions(beanDefinitionReader);
    }

?????可以看到對應(yīng)xml配置的bean定義信息,是用XmlBeanDefinitionReader來加載解析bean的定義信息。

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        
        // ...
        InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                //獲取xml文件流
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
        }
}


protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            Document doc = doLoadDocument(inputSource, resource);
            return registerBeanDefinitions(doc, resource);
        }
        // ...
}


public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
}

?????在這里獲取xml配置的bean定義信息的文件路徑,然后把文件轉(zhuǎn)化成InputStream文件流,依靠文件流獲取配置信息。然后把文件流里面的信息讀出來,形成一個Document對象,然后依靠BeanDefinitionDocumentReader來解析bean的定義信息,然后再把bean定義信息注冊到容器中。最后的結(jié)果是在beanDefinitionMap中存儲了bean的配置信息。

最后以一張時序圖作為spring容器初始化BeanDefinition加載的總結(jié):

spring ioc容器初始化時序圖.png

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容