Spring常見拓展總結

通常彤守,應用程序開發(fā)人員不需要子類化ApplicationContext實現(xiàn)類醉途。相反毡熏,可以通過插入特殊集成接口的實現(xiàn)來擴展Spring IoC容器舍扰。下圖展示了Spring Bean的生命周期倦蚪。而在這其中,與一些拓展點是非常相關的边苹。也就是說陵且,這些拓展點作用了Bean的生命周期中。(在看下面的拓展點的時候个束,可以結合這個圖慕购,觀察拓展點所處于的生命周期位置)


image.png

1. FactoryBean(用于自定義實例化邏輯)

FactoryBean通常是用來創(chuàng)建比較復雜的bean,一般的bean 直接用xml配置即可茬底,但如果一個bean的創(chuàng)建過程中涉及到很多其他的bean 和復雜的邏輯沪悲,用xml配置比較困難,這時可以考慮用FactoryBean阱表。

  • 定義需要創(chuàng)建的Bean
public class Tool {
    private int id;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public Tool(int id) {
        this.id = id;
    }
}
  • 實現(xiàn)FactoryBean
public class ToolFactory implements FactoryBean<Tool> {

    private int factoryId;
    private int toolId;
    //獲取所創(chuàng)建的Bean
    @Override
    public Tool getObject() throws Exception {
        return new Tool(toolId);
    }
    //獲取對象類型
    @Override
    public Class<?> getObjectType() {
        return Tool.class;
    }
    public int getFactoryId() {
        return factoryId;
    }
    //設置是否單例
    @Override
    public boolean isSingleton() {
        return false;
    }
    public void setFactoryId(int factoryId) {
        this.factoryId = factoryId;
    }
    public int getToolId() {
        return toolId;
    }
    public void setToolId(int toolId) {
        this.toolId = toolId;
    }
}

創(chuàng)建Tool這個Bean的具體過程都交給了ToolFactory來管理,也就是創(chuàng)建的細節(jié)都有它控制.

  • FactoryBean創(chuàng)建Bean交給容器管理殿如。
@Configuration
public class FactoryBeanAppConfig implements InitializingBean,BeanPostProcessor {
   //注入到容器里面
    @Bean(name="tool")
    public ToolFactory toolFactory() {
        ToolFactory factory = new ToolFactory();
        factory.setFactoryId(7070);
        factory.setToolId(2);
        return factory;
    }
  • 通過name = "&tool"來獲取到ToolFactory,因為ToolFactory本身也是Bean,由Spring容器管理.
     //注入Tool
    @Autowired
    Tool tool;
   //注入ToolFactory
    @Resource(name = "&tool")
    ToolFactory toolFactory;

2. InitializingBean和DisposableBean

IInitializingBeanDisposableBean中前者是在容器對Bean必要的屬性做了初始化后,再做后續(xù)的初始化最爬。后者是容器對Bean銷毀之前做一個回調(diào)涉馁。

  • InitializingBean
    InitializingBean只有一個方法,允許你在初始化之后做個回調(diào)。
void afterPropertiesSet() throws Exception;

通常來說烂叔,不推薦使用InitializingBean,因為它和Spring耦合太緊密了谨胞。推薦使用 @PostConstruct 注解 或者一個具體的 POJO 初始化方法固歪。推薦使用的與InitializingBean效果是一樣的蒜鸡,但是前者就沒有和Spring耦合胯努。

<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>

@PostConstruct 注解 則需要在支持Servlet2.5的容器使用。

 public class CachingMovieLister {

    @PostConstruct
    public void populateMovieCache() {
        // populates the movie cache upon initialization...
    }

    @PreDestroy
    public void clearMovieCache() {
        // clears the movie cache upon destruction...
    }
}

這三種方法的效果是一樣的逢防,但是當同時配置的時候叶沛,按照Spring Bean的生命周期,執(zhí)行的順序如下:

  1. 使用@PostConstruct注解的方法忘朝。
  2. InitializingBean中的afterPropertiesSet()方法灰署。
  3. 自定義的init()方法。

對應的局嘁,銷毀中@PreDestroy,DisposableBean,自定義的destroy()效果一樣溉箕,執(zhí)行順序與初始化的順序對應一樣。這兩類在初始化之前和銷毀之前的回調(diào)通常用于緩存的初始加載和緩存的清除這樣的場景悦昵。

3. BeanNameAware,BeanFactoryAware,ApplicationContextAware

  • BeanNameAware使得對象能夠感知到bean的名稱肴茄。通常用于把beanName記錄在日志。
  • BeanFactoryAware使得我們可以獲取到BeanFactory,進而可以獲取到bean但指,或者判斷bean是否是單例寡痰。
  • ApplicationContextAware使得我們獲取到ApplicationContext的具體實現(xiàn)類這個容器。這個ApplicationContextBeanFactory功能更強大棋凳。

使用 BeanNameAware,BeanFactoryAware,ApplicationContextAware值需要實現(xiàn)接口里面相應的方法即可拦坠。通常來說,定義一個類變量來分別紀錄下感知的的Name,BeanFactory,ApplicationContext即可剩岳。

    @Override
    public void setBeanName(String s) {
        System.out.println(s);
        System.out.println("setBeanName方法被調(diào)用");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println(beanFactory.containsBean("person"));
        System.out.println(beanFactory.isSingleton("person"));
        System.out.println("setBeanFactory被調(diào)用,beanFactory");
    }
   //功能比beanFactory功能更強大些
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println(applicationContext.getId());
        System.out.println(applicationContext.containsBean("person"));
        System.out.println("setApplicationContext被調(diào)用");
    }

在大多數(shù)情況下贞滨,我們應該避免使用這些Aware接口,因為它和Spring耦合太多拍棕。

4. BeanPostProcessor疲迂,BeanFactoryPostProcessor

  • BeanPostProcessor是在整個bean已經(jīng)創(chuàng)建,并且設置好類成員屬性之后莫湘,即spring容器已經(jīng)實例化一個bean后尤蒿。通過回調(diào)方法去實現(xiàn)自定義的實例邏輯.通常用于檢查bean屬性的有效性,每個bean在初始化(init-method,InitializingBean等初始化方法)前后幅垮,都會回調(diào)BeanPostProcessor中的方法腰池。
  • BeanFactoryPostProcessor 主要用于改變bean的Metadata。Spring容器允許BeanFactoryPostProcessor去讀取配置元屬性忙芒,并改變它示弓。它在BeanPostProcessor之前執(zhí)行。
  public class MyBeanPostProcessor implements BeanPostProcessor,BeanFactoryPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        if(bean instanceof Person) {
            ((Person) bean).setName("sb");
        }
        System.out.println("postProcessBeforeInitialization被調(diào)用");
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("postProcessAfterInitialization被調(diào)用");
        return bean;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("BeanFactoryPostProcessor被調(diào)用");
    }
}

這樣呵萨,SpringBean的生命周期就被串聯(lián)起來了奏属。如下

  • 首先容器啟動后,會對scope為singleton且非懶加載的bean進行實例化潮峦,

  • 按照Bean定義信息配置信息囱皿,注入所有的屬性勇婴,

  • 如果Bean實現(xiàn)了BeanNameAware接口,會回調(diào)該接口的setBeanName()方法嘱腥,傳入該Bean的id耕渴,此時該Bean就獲得了自己在配置文件中的id,

  • 如果Bean實現(xiàn)了BeanFactoryAware接口,會回調(diào)該接口的setBeanFactory()方法齿兔,傳入該Bean的BeanFactory橱脸,這樣該Bean就獲得了自己所在的BeanFactory,

  • 如果Bean實現(xiàn)了ApplicationContextAware接口,會回調(diào)該接口的setApplicationContext()方法分苇,傳入該Bean的ApplicationContext添诉,這樣該Bean就獲得了自己所在的ApplicationContext,

  • 如果有Bean實現(xiàn)了BeanPostProcessor接口医寿,則會回調(diào)該接口的postProcessBeforeInitialzation()方法吻商,

  • 如果Bean實現(xiàn)了InitializingBean接口,則會回調(diào)該接口的afterPropertiesSet()方法糟红,(初始化之一)

  • 如果Bean配置了init-method方法艾帐,則會執(zhí)行init-method配置的方法,(初始化之一)

  • 如果有Bean實現(xiàn)了BeanPostProcessor接口盆偿,則會回調(diào)該接口的postProcessAfterInitialization()方法柒爸,

  • 經(jīng)過流程9之后,就可以正式使用該Bean了,對于scope為singleton的Bean,Spring的ioc容器中會緩存一份該bean的實例事扭,而對于scope為prototype的Bean,每次被調(diào)用都會new一個新的對象捎稚,期生命周期就交給調(diào)用方管理了,不再是Spring容器進行管理了

  • 容器關閉后求橄,如果Bean實現(xiàn)了DisposableBean接口今野,則會回調(diào)該接口的destroy()方法,

  • 如果Bean配置了destroy-method方法罐农,則會執(zhí)行destroy-method配置的方法条霜,至此,整個Bean的生命周期結束涵亏。

參考文章:
spring官方文檔
Spring Bean生命周期

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宰睡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子气筋,更是在濱河造成了極大的恐慌拆内,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宠默,死亡現(xiàn)場離奇詭異麸恍,居然都是意外死亡,警方通過查閱死者的電腦和手機搀矫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門抹沪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刻肄,“玉大人,你說我怎么就攤上這事采够∫薹剑” “怎么了冰垄?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵蹬癌,是天一觀的道長。 經(jīng)常有香客問我虹茶,道長逝薪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任蝴罪,我火速辦了婚禮董济,結果婚禮上,老公的妹妹穿的比我還像新娘要门。我一直安慰自己虏肾,他們只是感情好,可當我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布欢搜。 她就那樣靜靜地躺著封豪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪炒瘟。 梳的紋絲不亂的頭發(fā)上吹埠,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天,我揣著相機與錄音疮装,去河邊找鬼缘琅。 笑死,一個胖子當著我的面吹牛廓推,可吹牛的內(nèi)容都是我干的刷袍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼樊展,長吁一口氣:“原來是場噩夢啊……” “哼做个!你這毒婦竟也來了?” 一聲冷哼從身側響起滚局,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤居暖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后藤肢,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體太闺,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年嘁圈,在試婚紗的時候發(fā)現(xiàn)自己被綠了省骂。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蟀淮。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖钞澳,靈堂內(nèi)的尸體忽然破棺而出怠惶,到底是詐尸還是另有隱情,我是刑警寧澤轧粟,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布策治,位于F島的核電站,受9級特大地震影響兰吟,放射性物質(zhì)發(fā)生泄漏通惫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一混蔼、第九天 我趴在偏房一處隱蔽的房頂上張望履腋。 院中可真熱鬧,春花似錦惭嚣、人聲如沸遵湖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽延旧。三九已至,卻和暖如春载矿,著一層夾襖步出監(jiān)牢的瞬間垄潮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工闷盔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留弯洗,地道東北人。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓逢勾,卻偏偏與公主長得像牡整,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子溺拱,可洞房花燭夜當晚...
    茶點故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內(nèi)容