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

資訊專欄INFORMATION COLUMN

Spring源碼原理篇(一)

Acceml / 1434人閱讀

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

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

編譯器IDEA

maven依賴spring-context version:4.3.12.RELEASE

maven依賴junit version:4.11

BeanPostProcessor工作原理

實現BeanPostProcessor接口的組件,并且在兩個方法體內打上斷點:

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;
    }
}

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

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

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

這段偽代碼的大致意思就是先執行bean初始化之前的方法,然后執行bean初始化方法,最后執行初始化后的方法。
applyBeanPostProcessorsBeforeInitialization也是屬于方法調用棧的一環,進去有類似一段偽代碼:

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

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

容器初始化流程

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

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

refresh過程:

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

獲取已經定義了需要創建對象的BeanPostProcessor

BeanPostProcessor分別區分實現PriorityOrdered、Ordered的

優先注冊實現PriorityOrdered接口的BeanPostProcessor

再給容器中注冊實現Ordered接口的BeanPostProcessor

最后注冊沒實現優先級接口的BeanPostProcessor(常規的后置處理器)

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

beanFactory.addBeanPostProcessor:將創建完成的BeanPostProcessor放在容器中

==========上面流程則完成對BeanPostProcessor的注冊和創建

refresh過程接上:

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

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

BeanPostProcessor在spring底層的使用

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

//將組件注冊添加到容器中后可以直接當作工具類
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;//打個斷點
    }
}

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

同理還有**EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware**也是注入spring底層組件
再舉個EmbeddedValueResolverAware的例子,可以實現這個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文件的屬性值時可以采用:propertiesUtil.getPropertiesValue("xxxxxxx")或者@value("xxxx")來達到獲取屬性值。
打個斷點后發現它的原理和ApplicationContextAware是一樣的。都是判斷了當前初始化bean時候繼承了對應的Aware,如果是則調用對應的set方法,傳入對應的資源。源碼如下:

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等幾個原理也是差不多類似的。
同理還有BeanValidationPostProcessor也實現了BeanPostProcessor接口,可用于數據校驗,還有InitDestroyAnnotationBeanPostProcessor也實現了此接口,主要是用于處理JSR250那幾個注解的,AutowiredAnnotationBeanPostProcessor也實現了該接口,用于處理@autowired注解裝載bean。總之,Bean的賦值、注入其他組件,@autowired,@Async,生命周期等都是使用BeanPostProcessor來完成的。這一些使用和原理在下一章再分析并補上流程圖。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/74767.html

相關文章

  • spring boot - 收藏集 - 掘金

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

    rollback 評論0 收藏0
  • 【好好面試】學完Aop,連動態代理的原理都不懂?

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

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

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

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

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

    tommego 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<