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

資訊專欄INFORMATION COLUMN

不,你不了解Spring實例化bean的時候做了什么

impig33 / 2023人閱讀

摘要:加載的時候構造函數什么時候調用什么時候調用實現了接口的中的和什么時候調用你是否清楚呢如果清楚的話可以直接忽略該篇文章最近來了幾個新人,被問了一個和生命周期相關的一個知識點,解決新人的問題后自己再寫了一個,目的是為了清晰的描述整個的生命周期。

Spring加載bean的時候構造函數什么時候調用、@PostConstruct什么時候調用、實現了BeanPostProcessor接口的bean中的postProcessAfterInitialization和postProcessBeforeInitialization什么時候調用?你是否清楚呢?如果清楚的話可以直接忽略該篇文章?。。?/pre>

最近來了幾個新人,被問了一個和bean生命周期相關的一個知識點,解決新人的問題后自己再寫了一個demo,目的是為了清晰的描述整個bean的生命周期。

注意注意,以下demo有五個類,可能會引起部分人不適,建議可以直接跳到最后看最終總結,或者自己下載源碼運行下。
demo地址:https://github.com/wiatingpub...
給出一個demo

首先給出一個實現了BeanFactoryPostProcessor的類,目的是為了比較清晰的看出postProcessBeanFactory接口被調用的時間點。

/**
 * BeanFactoryPostProcessor是bean工廠的處理器
 */
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    public MyBeanFactoryPostProcessor() {
        super();
        System.out.println("【BeanFactoryPostProcessor】實現類postProcessBeanFactory的構造函數");
    }

    // 允許我們在工廠里所有的bean被加載進來后但是還沒初始化前,對所有bean的屬性進行修改也可以add屬性值,該操作在對應bean的構造函數執行前
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
            throws BeansException {
        System.out
                .println("【BeanFactoryPostProcessor.postProcessBeanFactory】,來自MyBeanFactoryPostProcessor");
        //獲取到Spring中所有的beanName
        String[] beanStr = arg0.getBeanDefinitionNames();
        //循環打印
        for (String beanName : beanStr) {
            System.out.print("bean name:" + beanName + ";");
        }

        System.out.println();
    }
}

這里給出一個實現了BeanPostProcessor的類,目的是為了看出postProcessAfterInitialization、postProcessBeforeInitialization調用的時間點。

/**
 * 完成bean實例化、配置以及其他初始化方法前后要添加一些自己邏輯處理則要實現接口BeanPostProcessor
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    public MyBeanPostProcessor() {
        super();
        System.out.println("【MyBeanPostProcessor】BeanPostProcessor實現類的構造函數");
    }

    // 實例化、依賴注入完畢,在調用顯示的初始化之前完成一些定制的業務
    @Override
    public Object postProcessAfterInitialization(Object arg0, String arg1)
            throws BeansException {

        if (arg0.getClass() == TestBeanA.class || arg0.getClass() == TestBeanB.class) {
            System.out
                    .println("【BeanPostProcessor.postProcessAfterInitialization】來自MyBeanPostProcessor,beanName:" + arg1);
        }
        return arg0;
    }

    // 實例化、依賴注入、初始化后完成一些定制的業務
    @Override
    public Object postProcessBeforeInitialization(Object arg0, String arg1)
            throws BeansException {

        if (arg0.getClass() == TestBeanA.class || arg0.getClass() == TestBeanB.class) {
            System.out
                    .println("【BeanPostProcessor.postProcessBeforeInitialization】來自MyBeanPostProcessor,beanName:" + arg1);
        }
        return arg0;
    }
}

這里給出繼承了InstantiationAwareBeanPostProcessorAdapter的子類,目的是為了看出postProcessBeforeInitialization、postProcessAfterInitialization、postProcessPropertyValues被調用的時間點。

/**
 * 適配器類,基類是BeanPostProcessor的實現類
 */
@Component
public class MyInstantiationAwareBeanPostProcessor extends
        InstantiationAwareBeanPostProcessorAdapter {

    public MyInstantiationAwareBeanPostProcessor() {
        super();
        System.out
                .println("【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter實現類的構造函數");
    }

    // 接口方法、實例化Bean之前調用
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        if (bean.getClass() == TestBeanA.class || bean.getClass() == TestBeanB.class) {
            System.out
                    .println("【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:" + beanName);

        }
        return bean;
    }

    // 接口方法、實例化Bean之后調用
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        if (bean.getClass() == TestBeanA.class || bean.getClass() == TestBeanB.class) {
            System.out
                    .println("【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:" + beanName);
        }

        return bean;
    }

    // 接口方法、設置某個屬性時調用
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs,
                                                    PropertyDescriptor[] pds, Object bean, String beanName)
            throws BeansException {

        if (bean.getClass() == TestBeanA.class || bean.getClass() == TestBeanB.class) {
            System.out
                    .println("【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:" + beanName);
        }

        return pvs;
    }

這個就牛逼了,直接交給applicationContext.xml注入并且實現了BeanFactoryAware, BeanNameAware,InitializingBean,DisposableBean四個接口類,目的是為了清晰的看出以下好幾個接口被調用的時間點。

public class TestBeanA implements BeanFactoryAware, BeanNameAware,
        InitializingBean, DisposableBean {

    private String name;
    private String address;
    private int phone;

    private BeanFactory beanFactory;
    private String beanName;

    @PostConstruct
    public void init() {
        System.out.println("【TestBeanA.@PostConstruct】");
    }

    public TestBeanA() {
        System.out.println("【TestBeanA.默認構造器】");
    }

    public TestBeanA(String name) {
        System.out.println("【TestBeanA.帶參構造器】");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getPhone() {
        return phone;
    }

    public void setPhone(int phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "TestBeanA [address=" + address + ", name=" + name + ", phone="
                + phone + "]";
    }

    // 這是BeanFactoryAware接口方法
    @Override
    public void setBeanFactory(BeanFactory arg0) throws BeansException {
        System.out
                .println("【BeanFactoryAware.setBeanFactory】來自TestBeanA");
        this.beanFactory = arg0;
    }

    // 這是BeanNameAware接口方法
    @Override
    public void setBeanName(String arg0) {
        System.out.println("【BeanNameAware.setBeanName】來自TestBeanA");
        this.beanName = arg0;
    }

    // 這是InitializingBean接口方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out
                .println("【InitializingBean.afterPropertiesSet】來自TestBeanA");
    }

    // 這是DiposibleBean接口方法
    @Override
    public void destroy() throws Exception {
        System.out.println("【DiposibleBean.destory】來自TestBeanA");
    }

    // 通過的init-method屬性指定的初始化方法
    public void myInit() {
        System.out.println("【TestBeanA.myInit】");
    }

    // 通過的destroy-method屬性指定的初始化方法
    public void myDestory() {
        System.out.println("【TestBeanA.destroy-method】");
    }
}

TestBeanB的作用比較簡單,為了看出內部數據成員有其他容器Bean的時候Spring是如何加載bean的。

@Component
public class TestBeanB {

    @Autowired
    private TestBeanA testBeanA;

    public TestBeanB() {
        System.out.println("【TestBeanB.默認構造器】");
    }
}

這個是啟動類。

@SpringBootApplication
@ImportResource(locations = {"classpath:applicationContext.xml"})
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

雖然使用的是SpringBoot,這里還使用xml是為了看看init-method和destroy-method的調用時間。




    
        
    

很長很長的代碼算是都給出來了,接下來看下運行后給出的結果

【BeanFactoryPostProcessor】實現類postProcessBeanFactory的構造函數
【BeanFactoryPostProcessor.postProcessBeanFactory】,來自MyBeanFactoryPostProcessor
【MyBeanPostProcessor】BeanPostProcessor實現類的構造函數
【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter實現類的構造函數
【TestBeanB.默認構造器】
【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
【TestBeanA.默認構造器】
【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
【BeanNameAware.setBeanName】來自TestBeanA
【BeanFactoryAware.setBeanFactory】來自TestBeanA
【BeanPostProcessor.postProcessBeforeInitialization】來自MyBeanPostProcessor,beanName:testBeanA
【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
【TestBeanA.@PostConstruct】
【InitializingBean.afterPropertiesSet】來自TestBeanA
【TestBeanA.myInit】
【BeanPostProcessor.postProcessAfterInitialization】來自MyBeanPostProcessor,beanName:testBeanA
【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
【BeanPostProcessor.postProcessBeforeInitialization】來自MyBeanPostProcessor,beanName:testBeanB
【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
【BeanPostProcessor.postProcessAfterInitialization】來自MyBeanPostProcessor,beanName:testBeanB
【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
【DiposibleBean.destory】來自TestBeanA
【TestBeanA.destroy-method】

貌似又是一段看完頭暈腦脹的惡心代碼,不過不方不方,直接進入分析階段,跟著分析入手就簡單多了。

通過結果分析

首先從

【BeanFactoryPostProcessor】實現類postProcessBeanFactory的構造函數
【BeanFactoryPostProcessor.postProcessBeanFactory】,來自MyBeanFactoryPostProcessor
【MyBeanPostProcessor】BeanPostProcessor實現類的構造函數
【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter實現類的構造函數

可以看出執行順序是:

調用postProcessBeanFactory實現類的構造函數

BeanFactoryPostProcessor是bean工廠的處理器

調用postProcessBeanFactory實現類的postProcessBeanFactory實現函數

postProcessBeanFactory函數允許我們在工廠里所有的bean被加載進來后但是還沒初始化前,對所有bean的屬性進行修改也可以add屬性值

調用BeanPostProcessor實現類的構造函數

完成bean實例化、配置以及其他初始化方法前后要添加一些自己邏輯處理則要實現接口BeanPostProcessor

調用InstantiationAwareBeanPostProcessorAdapter實現類的構造函數

適配器類,基類是BeanPostProcessor的實現類

再從

【TestBeanB.默認構造器】
【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB

可以看到,此處spring容器先掃描到了TestBeanB,因此調用順序是

TestBeanB的默認構造器【無參構造器】

調用InstantiationAwareBeanPostProcessorAdapter實現類的postProcessPropertyValues接口

postProcessPropertyValues在接口方法、設置某個屬性時調用,通過實驗看到實例化一個Bean的時候也會調用該接口方法

之后實例化TestBeanB的時候發現內部注入了TestBeanA,因此Spring轉而實例化TestBeanA。

接下來看到的是TestBeanA的實例化過程中調用的順序

【TestBeanA.默認構造器】
【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
【BeanNameAware.setBeanName】來自TestBeanA
【BeanFactoryAware.setBeanFactory】來自TestBeanA
【BeanPostProcessor.postProcessBeforeInitialization】來自MyBeanPostProcessor,beanName:testBeanA
【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
【TestBeanA.@PostConstruct】
【InitializingBean.afterPropertiesSet】來自TestBeanA
【TestBeanA.myInit】
【BeanPostProcessor.postProcessAfterInitialization】來自MyBeanPostProcessor,beanName:testBeanA
【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA

調用了TestBeanA的默認構造器

調用InstantiationAwareBeanPostProcessorAdapter實現類的postProcessPropertyValues接口

調用BeanNameAware的setBeanName接口

可以從源碼看到TestBeanA實現了接口BeanNameAware

調用BeanFactoryAware的setBeanFactory接口

可以從源碼看到TestBeanA實現了接口BeanFactoryAware

調用BeanPostProcessor的postProcessBeforeInitialization接口

調用InstantiationAwareBeanPostProcessorAdapter的postProcessBeforeInitialization接口

調用TestBeanA中注解了@PostConstruct的函數

調用了InitializingBean的afterPropertiesSet接口

可以從源碼看到TestBeanA實現了接口InitializingBean

調用了TestBeanA的myInit接口

可以看到該init-method接口是在applicationContext中init-method配置上的

調用BeanPostProcessor實現類的postProcessAfterInitialization接口

調用InstantiationAwareBeanPostProcessorAdapter子類的postProcessAfterInitialization接口

等TestBeanA實例化結束后,則繼續TestBeanB的實例化路程

【BeanPostProcessor.postProcessBeforeInitialization】來自MyBeanPostProcessor,beanName:testBeanB
【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
【BeanPostProcessor.postProcessAfterInitialization】來自MyBeanPostProcessor,beanName:testBeanB
【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB

調用BeanPostProcessor實現類的postProcessBeforeInitialization接口

調用InstantiationAwareBeanPostProcessorAdapter子類的postProcessBeforeInitialization接口

調用BeanPostProcessor實現類的postProcessAfterInitialization接口

調用InstantiationAwareBeanPostProcessorAdapter子類的postProcessAfterInitialization接口

最后

【DiposibleBean.destory】來自TestBeanA
【TestBeanA.destroy-method】

調用DiposibleBean實現類的destory接口

TestBeanA實現了DiposibleBean接口,實現了destroy接口

調用TestBeanA的myDestory函數

可以看到該myDestory接口是在applicationContext中destroy-method配置上的。
最終總結

【超重點,面試回答模板,老牛逼了】

如果有bean實現了BeanFactoryPostProcessor接口類,則會實例化該bean,并且調用默認構造器,然后調用postProcessBeanFactory接口

如果有bean實現了BeanPostProcessor接口類,則會先實例化該bean,同樣調用默認構造器

如果有bean繼承了InstantiationAwareBeanPostProcessorAdapter類,則會先實例化該bean,同樣調用默認構造器

之后真正進入一個bean的生命周期過程

先調用bean的默認構造函數

如果有bean繼承了InstantiationAwareBeanPostProcessorAdapter類,此刻會調用postProcessPropertyValues函數

如果這個bean已經實現了BeanNameAware接口,會調用它實現的setBeanName方法,此處傳遞的就是applicationContext.xml配置文件中Bean的id值

如果這個bean已經實現了BeanFactoryAware接口,會調用它實現的setBeanFactory,傳遞的是Spring工廠自身

如果存在其他bean實現了BeanPostProcessor接口,將會調用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor經常被用作是Bean內容的更改,并且由于這個是在Bean初始化結束時調用那個的方法,也可以被應用于內存或緩存技術;

如果存在其他bean繼承了InstantiationAwareBeanPostProcessorAdapter類,則會調用postProcessBeforeInitialization接口

如果這個bean中有函數加了@PostConstruct注解,則該函數會在此刻被調用

如果這個bean實現了InitializingBean接口重寫了afterPropertiesSet方法,該方法會在此刻被調用

如果這個bean在Spring配置文件中配置了init-method屬性,則會自動調用其配置的初始化方法。

如果存在其他bean實現了BeanPostProcessor接口,將會調用postProcessAfterInitialization(Object obj, String s)方法

如果存在其他bean繼承了InstantiationAwareBeanPostProcessorAdapter類,則會調用postProcessAfterInitialization接口

走到這一步以后就可以應用這個Bean了,而這個Bean是一個Singleton的,雖然在Spring配置文件中也可以配置非Singleton,這里不做贅述。

走入銷毀階段

當bean不再需要時,會經過清理階段,如果這個bean實現了DisposableBean接口,會調用其實現的destroy()方法;

如果這個bean的applicationContext.xml配置中配置了destroy-method屬性,會自動調用其配置的銷毀方法。

Java源碼分析、go語言應用、微服務,更多干貨歡迎關注公眾號:

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

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

相關文章

  • 面試被問爛 Spring IOC(求求你別再問了)

    摘要:例如資源的獲取,支持多種消息例如的支持,對多了工具級別的支持等待。最上面的知道吧我就不講了。生命周期事件回調等。他支持不同信息源頭,支持工具類,支持層級容器,支持訪問文件資源,支持事件發布通知,支持接口回調等等。 廣義的 IOC IoC(Inversion of Control) 控制反轉,即不用打電話過來,我們會打給你。 兩種實現: 依賴查找(DL)和依賴注入(DI)。 IOC 和...

    denson 評論0 收藏0
  • Spring IOC 容器源碼分析系列文章導讀

    摘要:本文是容器源碼分析系列文章的第一篇文章,將會著重介紹的一些使用方法和特性,為后續的源碼分析文章做鋪墊。我們可以通過這兩個別名獲取到這個實例,比如下面的測試代碼測試結果如下本小節,我們來了解一下這個特性。 1. 簡介 Spring 是一個輕量級的企業級應用開發框架,于 2004 年由 Rod Johnson 發布了 1.0 版本。經過十幾年的迭代,現在的 Spring 框架已經非常成熟了...

    NSFish 評論0 收藏0
  • Spring IOC 容器源碼分析 - 循環依賴解決辦法

    摘要:實例化時,發現又依賴于。一些緩存的介紹在進行源碼分析前,我們先來看一組緩存的定義。可是看完源碼后,我們似乎仍然不知道這些源碼是如何解決循環依賴問題的。 1. 簡介 本文,我們來看一下 Spring 是如何解決循環依賴問題的。在本篇文章中,我會首先向大家介紹一下什么是循環依賴。然后,進入源碼分析階段。為了更好的說明 Spring 解決循環依賴的辦法,我將會從獲取 bean 的方法getB...

    aikin 評論0 收藏0
  • 零基礎帶你看Spring源碼——IOC控制反轉

    摘要:依賴注入是向某個類或方法注入一個值,其中所用到的原理就是控制反轉。但發現更多時間是在調和的源碼。里面就是從中取出這個,完成控制反轉的??刂品崔D的優點最后來以我個人觀點談談控制反轉的優點吧??刂品崔D為了降低項目耦合,提高延伸性。 本章開始來學習下Spring的源碼,看看Spring框架最核心、最常用的功能是怎么實現的。網上介紹Spring,說源碼的文章,大多數都是生搬硬推,都是直接看來的...

    wing324 評論0 收藏0
  • 仿照 Spring 實現簡單 IOC 和 AOP - 下篇

    摘要:在上文中,我實現了一個很簡單的和容器。比如,我們所熟悉的就是在這里將切面邏輯織入相關中的。初始化的工作算是結束了,此時處于就緒狀態,等待外部程序的調用。其中動態代理只能代理實現了接口的對象,而動態代理則無此限制。 1. 背景 本文承接上文,來繼續說說 IOC 和 AOP 的仿寫。在上文中,我實現了一個很簡單的 IOC 和 AOP 容器。上文實現的 IOC 和 AOP 功能很單一,且 I...

    AlexTuan 評論0 收藏0

發表評論

0條評論

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