国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Spring源碼原理篇(一)

Acceml / 1427人閱讀

摘要:也是屬于方法調(diào)用棧的一環(huán),進(jìn)去有類似一段偽代碼這段代碼通過遍歷得到所有的,然后挨個(gè)執(zhí)行重寫的方法,倘若有一個(gè)方法返回的為,那么循環(huán)就會(huì)跳出,意味著下面的方法不會(huì)被執(zhí)行。

Spring源碼原理篇--容器初始化&Bean后置處理器
本篇主要是講解IOC容器初始化過程中大體進(jìn)行了哪一些工作,以及Bean后置處理器的工作原理和BeanPostProcessor在底層的使用。
環(huán)境準(zhǔn)備

編譯器IDEA

maven依賴spring-context version:4.3.12.RELEASE

maven依賴junit version:4.11

BeanPostProcessor工作原理

實(shí)現(xiàn)BeanPostProcessor接口的組件,并且在兩個(gè)方法體內(nèi)打上斷點(diǎn):

public class BeanPostProcessorDefinition implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessBeforeInitialization -->"+s+" = "+o);
        return o;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessorAfterInitialization -->"+s+"="+o);
        return o;
    }
}

調(diào)試后查看方法調(diào)用棧如下(如圖1):

在方法調(diào)用棧中的initializeBean(初始化Bean)方法中,有下面一段類似的偽代碼:

initializeBean(param){
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
...
invokeInitMethods(beanName, wrappedBean, mbd);
...
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

這段偽代碼的大致意思就是先執(zhí)行bean初始化之前的方法,然后執(zhí)行bean初始化方法,最后執(zhí)行初始化后的方法。
applyBeanPostProcessorsBeforeInitialization也是屬于方法調(diào)用棧的一環(huán),進(jìn)去有類似一段偽代碼:

applyBeanPostProcessorsBeforeInitialization(param)
            throws BeansException {
        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
            result = beanProcessor.postProcessBeforeInitialization(result, beanName);
            if (result == null) {
                return result;
            }
        }
        return result;
    }

這段代碼通過遍歷得到所有的BeanPostProcessor,然后挨個(gè)執(zhí)行重寫的postProcessBeforeInitialization方法,倘若有一個(gè)方法返回的bean為null,那么循環(huán)就會(huì)跳出,意味著下面的postProcessBeforeInitialization方法不會(huì)被執(zhí)行。在初始化方法后執(zhí)行的applyBeanPostProcessorsAfterInitialization同理也是一樣的。
大致總結(jié)后置處理器處理Bean初始化的過程(如圖2):

容器初始化流程

談到spring的IOC容器都離不開兩個(gè)接口BeanFactory和ApplicationContext,其中ApplicationContext是BeanFactory的子接口,他們都可以代表spring容器。
圖1打斷點(diǎn)所示的方法調(diào)用棧可以用來分析容器初始化所進(jìn)行的工作(以AnnotationConfigApplicationContext獲取容器為例):

init:注冊配置類,調(diào)用refresh()刷新容器

refresh過程:

registerBeanPostProcessors(Param)注冊Bean后置處理器用來攔截Bean的創(chuàng)建

獲取已經(jīng)定義了需要?jiǎng)?chuàng)建對象的BeanPostProcessor

BeanPostProcessor分別區(qū)分實(shí)現(xiàn)PriorityOrdered、Ordered的

優(yōu)先注冊實(shí)現(xiàn)PriorityOrdered接口的BeanPostProcessor

再給容器中注冊實(shí)現(xiàn)Ordered接口的BeanPostProcessor

最后注冊沒實(shí)現(xiàn)優(yōu)先級接口的BeanPostProcessor(常規(guī)的后置處理器)

注冊BeanPostProcessor,實(shí)際上spring就會(huì)創(chuàng)建對象保存在容器中;
以下是創(chuàng)建Bean的流程:
1、doCreateBean(Param)方法內(nèi)創(chuàng)建Bean實(shí)例
2、populateBean(Param)給bean實(shí)例屬性賦值
3、initializeBean(Param):初始化Bean
4、invokeAwareMethods():處理Bean實(shí)現(xiàn)Aware接口的方法回調(diào)
5、后置處理器處理的流程:圖2的流程

beanFactory.addBeanPostProcessor:將創(chuàng)建完成的BeanPostProcessor放在容器中

==========上面流程則完成對BeanPostProcessor的注冊和創(chuàng)建

refresh過程接上:

finishBeanFactoryInitialization(Param)完成對BeanFactory初始化的工作,剩下創(chuàng)建單實(shí)例的bean

單實(shí)例Bean被創(chuàng)建的方法調(diào)用棧:getBean->doGetBean()->getSingleton()-createBean-doCreateBean然后就是上面重復(fù)的創(chuàng)建Bean的流程。這一部分Bean創(chuàng)建源碼細(xì)節(jié)暫時(shí)先緩一緩,待到spring aspectJ源碼分析再回過頭來分析從getBean到doCreateBean進(jìn)行了哪一些操作。

BeanPostProcessor在spring底層的使用

在spring中,Aware接口的Bean在被初始之后,可以取得一些相對應(yīng)的資源,也就是說,自定義組件想要使用Spring容器底層的一些組件(ApplicationContext,BeanFactory,xxx)的話,自定義組件就需要實(shí)現(xiàn)xxxxAware接口;在創(chuàng)建對象的時(shí)候,會(huì)調(diào)用接口規(guī)定的方法注入相關(guān)組件,把Spring底層一些組件注入到自定義的Bean中;
ApplicationContextAware
可以在Spring初始化實(shí)例 Bean的時(shí)候,可以通過這個(gè)接口將當(dāng)前的Spring上下文傳入,即獲得spring 容器,實(shí)際開發(fā)中,常常封裝成一個(gè)工具類(方便獲取容器獲取bean):

//將組件注冊添加到容器中后可以直接當(dāng)作工具類
public class SpringContextTool implements ApplicationContextAware {

    private static ApplicationContext context = null;

    public static Object getBean(String beanName) {
        return context.getBean(beanName);
    }

    public static  T getBean(Class clazz){
        return context.getBean(clazz);
    }

    public static ApplicationContext getContext() {
        return context;
    }

    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        context = applicationContext;//打個(gè)斷點(diǎn)
    }
}

原理:在重寫方法打個(gè)斷點(diǎn),查看方法調(diào)用棧
容器看出,在bean初始化方法執(zhí)行之前,先執(zhí)行后置處理器的postProcessBeforeInitialization方法,程序跳進(jìn)ApplicationContextAwareProcessor這個(gè)類中(此類實(shí)現(xiàn)了BeanPostProcessor接口),執(zhí)行重寫的postProcessBeforeInitialization方法,在跳到invokeAwareInterfaces方法中,判斷了當(dāng)前初始化bean時(shí)候繼承了對應(yīng)的Aware,如果是則調(diào)用對應(yīng)的set方法,傳入對應(yīng)的資源。

同理還有**EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware**也是注入spring底層組件
再舉個(gè)EmbeddedValueResolverAware的例子,可以實(shí)現(xiàn)這個(gè)aware接口來完成Spring獲取properties文件屬性值:

public class PropertiesUtil implements EmbeddedValueResolverAware {

    private static StringValueResolver resolver;

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.resolver = resolver;
    }
    public static String getPropertiesValue(String key) {
        StringBuilder name = new StringBuilder("${").append(key).append("}");
        return resolver.resolveStringValue(name.toString());
    }
}

需要獲取properties文件的屬性值時(shí)可以采用:propertiesUtil.getPropertiesValue("xxxxxxx")或者@value("xxxx")來達(dá)到獲取屬性值。
打個(gè)斷點(diǎn)后發(fā)現(xiàn)它的原理和ApplicationContextAware是一樣的。都是判斷了當(dāng)前初始化bean時(shí)候繼承了對應(yīng)的Aware,如果是則調(diào)用對應(yīng)的set方法,傳入對應(yīng)的資源。源碼如下:

private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof EnvironmentAware) {
                ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
            }
            if (bean instanceof EmbeddedValueResolverAware) {
                ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
            }
            if (bean instanceof ResourceLoaderAware) {
                ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
            }
            if (bean instanceof ApplicationEventPublisherAware) {
                ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
            }
            if (bean instanceof MessageSourceAware) {
                ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
            }
            if (bean instanceof ApplicationContextAware) {
                ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
            }
        }
    }

ServletContextAware、ServletConfigAware等幾個(gè)原理也是差不多類似的。
同理還有BeanValidationPostProcessor也實(shí)現(xiàn)了BeanPostProcessor接口,可用于數(shù)據(jù)校驗(yàn),還有InitDestroyAnnotationBeanPostProcessor也實(shí)現(xiàn)了此接口,主要是用于處理JSR250那幾個(gè)注解的,AutowiredAnnotationBeanPostProcessor也實(shí)現(xiàn)了該接口,用于處理@autowired注解裝載bean。總之,Bean的賦值、注入其他組件,@autowired,@Async,生命周期等都是使用BeanPostProcessor來完成的。這一些使用和原理在下一章再分析并補(bǔ)上流程圖。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/74767.html

相關(guān)文章

  • spring boot - 收藏集 - 掘金

    摘要:引入了新的環(huán)境和概要信息,是一種更揭秘與實(shí)戰(zhàn)六消息隊(duì)列篇掘金本文,講解如何集成,實(shí)現(xiàn)消息隊(duì)列。博客地址揭秘與實(shí)戰(zhàn)二數(shù)據(jù)緩存篇掘金本文,講解如何集成,實(shí)現(xiàn)緩存。 Spring Boot 揭秘與實(shí)戰(zhàn)(九) 應(yīng)用監(jiān)控篇 - HTTP 健康監(jiān)控 - 掘金Health 信息是從 ApplicationContext 中所有的 HealthIndicator 的 Bean 中收集的, Spring...

    rollback 評論0 收藏0
  • 【好好面試】學(xué)完Aop,連動(dòng)態(tài)代理的原理都不懂?

    摘要:總結(jié)動(dòng)態(tài)代理的相關(guān)原理已經(jīng)講解完畢,接下來讓我們回答以下幾個(gè)思考題。 【干貨點(diǎn)】 此處是【好好面試】系列文的第12篇文章。文章目標(biāo)主要是通過原理剖析的方式解答Aop動(dòng)態(tài)代理的面試熱點(diǎn)問題,通過一步步提出問題和了解原理的方式,我們可以記得更深更牢,進(jìn)而解決被面試官卡住喉嚨的情況。問題如下 SpringBoot默認(rèn)代理類型是什么 為什么不用靜態(tài)代理 JDK動(dòng)態(tài)代理原理 CGLIB動(dòng)態(tài)代理...

    Keven 評論0 收藏0
  • 【推薦】最新200:技術(shù)文章整理

    摘要:作為面試官,我是如何甄別應(yīng)聘者的包裝程度語言和等其他語言的對比分析和主從復(fù)制的原理詳解和持久化的原理是什么面試中經(jīng)常被問到的持久化與恢復(fù)實(shí)現(xiàn)故障恢復(fù)自動(dòng)化詳解哨兵技術(shù)查漏補(bǔ)缺最易錯(cuò)過的技術(shù)要點(diǎn)大掃盲意外宕機(jī)不難解決,但你真的懂?dāng)?shù)據(jù)恢復(fù)嗎每秒 作為面試官,我是如何甄別應(yīng)聘者的包裝程度Go語言和Java、python等其他語言的對比分析 Redis和MySQL Redis:主從復(fù)制的原理詳...

    BicycleWarrior 評論0 收藏0
  • 【推薦】最新200:技術(shù)文章整理

    摘要:作為面試官,我是如何甄別應(yīng)聘者的包裝程度語言和等其他語言的對比分析和主從復(fù)制的原理詳解和持久化的原理是什么面試中經(jīng)常被問到的持久化與恢復(fù)實(shí)現(xiàn)故障恢復(fù)自動(dòng)化詳解哨兵技術(shù)查漏補(bǔ)缺最易錯(cuò)過的技術(shù)要點(diǎn)大掃盲意外宕機(jī)不難解決,但你真的懂?dāng)?shù)據(jù)恢復(fù)嗎每秒 作為面試官,我是如何甄別應(yīng)聘者的包裝程度Go語言和Java、python等其他語言的對比分析 Redis和MySQL Redis:主從復(fù)制的原理詳...

    tommego 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<