spring ioc控制器總結(jié)

bean的作用域

范圍 描述
singleton 單例
prototype 原型
request ApplicationContext
session ApplicationContext
application ApplicationContext
websocket WebSocket

singleton與prototype都是spring內(nèi)置的赂毯,默認(rèn)是singleton。prototype是每次獲取bean都會創(chuàng)建新的bean. request拣宰、session党涕、application都是在web應(yīng)用中生效。websocket是指在一個(gè)websocket鏈接中生效巡社。

自定義scope,實(shí)現(xiàn)org.springframework.beans.factory.config.Scope接口即可膛堤。參考o(jì)rg.springframework.context.support.SimpleThreadScope

@Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Map<String, Object> scope = this.threadScope.get();
        Object scopedObject = scope.get(name);
        if (scopedObject == null) {
            scopedObject = objectFactory.getObject();
            scope.put(name, scopedObject);
        }
        return scopedObject;
    }

prototype范圍的bean生命周期創(chuàng)建后,不受spring容器管理晌该。即<bean id="person" class="com.test.Person" init-method="init" destroy-method="destory" > init方法會調(diào)用肥荔,但是destory不會調(diào)用绿渣。prototype范圍的bean銷毀要交給客戶端代碼銷毀。

自定義bean的屬性

  1. Lifecycle Callbacks(生命周期回調(diào))
    初始化回調(diào):1. 實(shí)現(xiàn)InitializingBean接口燕耿,則會回調(diào)afterPropertiesSet()方法
  2. 方法上加注解@PostConstruct中符。3. 指定init-method方法
    銷毀回調(diào):1. 實(shí)現(xiàn)DisposableBean接口,則會回調(diào)destroy()方法誉帅。2. 方法加注解

調(diào)用順序
初始化:

  1. Methods annotated with @PostConstruct

2.afterPropertiesSet() as defined by the InitializingBean callback interface

  1. A custom configured init() method

銷毀:Destroy methods are called in the same order:

  1. Methods annotated with @PreDestroy

  2. destroy() as defined by the DisposableBean callback interface

  3. A custom configured destroy() method

Lifecycle接口

淀散。。蚜锨。档插。。踏志。

Aware接口阀捅,事件回調(diào)機(jī)制

ApplicationContextAware、ApplicationEventPublisherAware针余、BeanFactoryAware、ServletContextAware

ApplicationEventPublisherAware實(shí)現(xiàn)了該接口的bean凄诞,可以獲取applicationEventPublisher圆雁,用來發(fā)布事件。如下代碼可以實(shí)現(xiàn)事件的監(jiān)聽機(jī)制帆谍。

  1. 事件信息載體
package com.league.chase.event;

public class User {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  1. 事件
package com.league.chase.event;

import org.springframework.context.ApplicationEvent;

public class RegisterEvent extends ApplicationEvent {
    /**
     * Create a new ApplicationEvent.
     *
     * @param source the component that published the event (never {@code null})
     */
    private User user;

    public RegisterEvent(Object source, User user) {
        super(source);
        this.user = user;
    }

    public User getUser() {
        return user;
    }
}
  1. 事件發(fā)布者
package com.league.chase.event;


import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;

@Service
public class UserService implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher applicationEventPublisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;

    }

    public void register(String userName){
        applicationEventPublisher.publishEvent(new RegisterEvent(this,new User()));
    }

    public void sayHello(){
        System.out.println("userService sayHello");
    };
}

  1. 事件監(jiān)聽者
package com.league.chase.event;

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Service;

@Service
public class RegisterEventListener implements ApplicationListener<RegisterEvent> {

    @Override
    public void onApplicationEvent(RegisterEvent applicationEvent) {
        System.out.println("事件---"+applicationEvent.getSource().getClass().getName());
        UserService service = (UserService) applicationEvent.getSource();
        service.sayHello();

    }

}

spring的擴(kuò)展點(diǎn)

BeanPostProcessor

在bean創(chuàng)建伪朽、實(shí)例化之后,初始化調(diào)用前后進(jìn)行一些邏輯的操作汛蝙,可以修改bean的屬性烈涮,返回等等。



package org.springframework.beans.factory.config;

import org.springframework.beans.BeansException;


public interface BeanPostProcessor {

    //@PostConstruct注解方法窖剑、InitializingBean接口的afterPropertiesSet方法坚洽、init-method方法**調(diào)用之前執(zhí)行**。
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

    //@PostConstruct注解方法西土、InitializingBean接口的afterPropertiesSet方法讶舰、init-method方法**調(diào)用之后執(zhí)行**。
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}

demo如下代碼

package com.league.chase.beanPostProcessor;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;

@Service
public class BeanPostProcessorService implements InitializingBean {

    private int age = 1;

    @PostConstruct
    public void init(){
        System.out.println("BeanPostProcessorService----> init");
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("BeanPostProcessorService----> afterPropertiesSet");
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

package com.league.chase.beanPostProcessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;


@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(beanName.equals("beanPostProcessorService")){
            System.out.println("postProcessBeforeInitialization beanName---->"+beanName);
            BeanPostProcessorService newBean = (BeanPostProcessorService) bean;
            ((BeanPostProcessorService) bean).setAge(2);

        }

        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(beanName.equals("beanPostProcessorService")){
            System.out.println("postProcessAfterInitialization beanName---->"+beanName);
            System.out.println("postProcessAfterInitialization beanName---->"+((BeanPostProcessorService)bean).getAge());
            BeanPostProcessorService newBean  = new BeanPostProcessorService();
            newBean = new BeanPostProcessorService();
            newBean.setAge(3);
            return newBean;
        }

        return bean;
    }
}

輸出
postProcessBeforeInitialization beanName---->beanPostProcessorService
BeanPostProcessorService----> init
BeanPostProcessorService----> afterPropertiesSet
postProcessAfterInitialization beanName---->beanPostProcessorService
postProcessAfterInitialization beanName---->2

AutowiredAnnotationBeanPostProcessor實(shí)現(xiàn)了BeanPostProcessor接口

AutowiredAnnotationBeanPostProcessor.png

AutowiredAnnotationBeanPostProcessor的調(diào)用堆椥枇耍可以看出跳昼,spring的Autowired注解注入是通過BeanPostProcessor實(shí)現(xiàn)的。
AutowiredAnnotationBeanPostProcessor調(diào)用堆棧.png

BeanFactoryPostProcessor

在bean實(shí)例化之前肋乍,對bean的元數(shù)據(jù)進(jìn)行邏輯操作處理
PropertySourcesPlaceholderConfigurer對@Value屬性進(jìn)行解析鹅颊。
下面的demo,模擬PropertySourcesPlaceholderConfigurer,對bean的屬性進(jìn)行注入值墓造。

package com.league.chase.beanFactoryPostProcessor;


import org.springframework.stereotype.Service;

/**
 * BeanFactoryPostProcessor實(shí)現(xiàn)類
 * @author chase
 */
@Service
public class BeanFactoryPostProcessorService {

    private String name;


    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "BeanFactoryPostProcessorService{" +
                "name='" + name + '\'' +
                '}';
    }
}
package com.league.chase.beanFactoryPostProcessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.PriorityOrdered;
import org.springframework.stereotype.Service;

/**
 * @author chase
 */
@Service
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor, PriorityOrdered {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

        //configurableListableBeanFactory可以修改bean的定義堪伍,注冊新的bean等锚烦。
        BeanDefinition service = configurableListableBeanFactory.getBeanDefinition("beanFactoryPostProcessorService");

        //模擬 PropertySourcesPlaceholderConfigurer向 bean的屬性設(shè)置值。
        MutablePropertyValues pvs = new MutablePropertyValues();
        pvs.addPropertyValue(new PropertyValue("name","zhangsan"));
        ((ScannedGenericBeanDefinition) service).setPropertyValues(pvs);

        System.out.println("MyBeanFactoryPostProcessor postProcessBeanFactory():"+service.getBeanClassName());
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

package com.league.chase.beanFactoryPostProcessor;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyBeanFactoryPostProcessorTest {

    @Autowired
    private BeanFactoryPostProcessorService service;

    @Test
    public void postProcessBeanFactoryTest() {
        System.out.println("MyBeanFactoryPostProcessorTest---->"+service.getName());
    }
}

輸出如下杠娱,從輸出可以看出BeanFactoryPostProcessor是作用于實(shí)例化之前挽牢,BeanPostProcessor作用于bean實(shí)例化之后,且初始化方法調(diào)用之前后摊求。


MyBeanFactoryPostProcessor postProcessBeanFactory():com.league.chase.beanFactoryPostProcessor.BeanFactoryPostProcessorService
2021-05-11 17:02:54.756 INFO 28341 --- [ main] trationDelegateBeanPostProcessorChecker : Bean 'spring.cloud.sentinel-com.alibaba.cloud.sentinel.SentinelProperties' of type [com.alibaba.cloud.sentinel.SentinelProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2021-05-11 17:02:54.759 INFO 28341 --- [ main] trationDelegateBeanPostProcessorChecker : Bean 'com.alibaba.cloud.sentinel.custom.SentinelAutoConfiguration' of type [com.alibaba.cloud.sentinel.custom.SentinelAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
postProcessBeforeInitialization beanName---->beanPostProcessorService
BeanPostProcessorService----> init
BeanPostProcessorService----> afterPropertiesSet
postProcessAfterInitialization beanName---->beanPostProcessorService
postProcessAfterInitialization beanName---->2

2021-05-11 17:02:56.195 INFO 28341 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2021-05-11 17:02:56.282 INFO 28341 --- [ main] c.a.c.s.SentinelWebAutoConfiguration : [Sentinel Starter] register SentinelWebInterceptor with urlPatterns: [/**].
2021-05-11 17:02:57.814 INFO 28341 --- [ main] o.s.cloud.commons.util.InetUtils : Cannot determine local hostname
2021-05-11 17:02:57.896 INFO 28341 --- [ main] c.l.c.b.MyBeanFactoryPostProcessorTest : Started MyBeanFactoryPostProcessorTest in 1454.614 seconds (JVM running for 1456.377)

MyBeanFactoryPostProcessorTest---->zhangsan


自定義bean的實(shí)例化邏輯接口FactoryBean

Environment Abstraction

禽拔。。室叉。睹栖。。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末茧痕,一起剝皮案震驚了整個(gè)濱河市野来,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌踪旷,老刑警劉巖曼氛,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異令野,居然都是意外死亡舀患,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門气破,熙熙樓的掌柜王于貴愁眉苦臉地迎上來聊浅,“玉大人,你說我怎么就攤上這事现使〉统祝” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵碳锈,是天一觀的道長顽冶。 經(jīng)常有香客問我,道長殴胧,這世上最難降的妖魔是什么渗稍? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮团滥,結(jié)果婚禮上竿屹,老公的妹妹穿的比我還像新娘。我一直安慰自己灸姊,他們只是感情好拱燃,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著力惯,像睡著了一般碗誉。 火紅的嫁衣襯著肌膚如雪召嘶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天哮缺,我揣著相機(jī)與錄音弄跌,去河邊找鬼。 笑死尝苇,一個(gè)胖子當(dāng)著我的面吹牛铛只,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播糠溜,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼淳玩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了非竿?” 一聲冷哼從身側(cè)響起蜕着,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎红柱,沒想到半個(gè)月后承匣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锤悄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年悄雅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铁蹈。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖众眨,靈堂內(nèi)的尸體忽然破棺而出握牧,到底是詐尸還是另有隱情,我是刑警寧澤娩梨,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布沿腰,位于F島的核電站,受9級特大地震影響狈定,放射性物質(zhì)發(fā)生泄漏颂龙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一纽什、第九天 我趴在偏房一處隱蔽的房頂上張望措嵌。 院中可真熱鬧,春花似錦芦缰、人聲如沸企巢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽浪规。三九已至始花,卻和暖如春龙优,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工朴摊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人锅知。 一個(gè)月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓舔稀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親绍填。 傳聞我的和親對象是個(gè)殘疾皇子霎桅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

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