最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring BeanPostProcessor源碼示例解析

 更新時(shí)間:2023年01月15日 15:48:21   作者:陳湯姆  
這篇文章主要為大家介紹了Spring BeanPostProcessor源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

BeanPostProcessor對(duì)于Spring開(kāi)發(fā)者來(lái)說(shuō)一定不陌生,平時(shí)開(kāi)發(fā)過(guò)程中如果涉及對(duì)中間件做增強(qiáng)處理或者需要對(duì)某個(gè)實(shí)際Bean做初始化前的處理,一般都可以使用該接口來(lái)實(shí)現(xiàn)。

對(duì)于自己來(lái)說(shuō)自己在對(duì)接RocketMQ、RabbitMQ過(guò)程中需要實(shí)現(xiàn)一個(gè)快速接入SpringBoot的中間插件,最快速的就是實(shí)現(xiàn)該接口對(duì)中間件中的Bean做增強(qiáng)處理,能夠快速接入SpringBoot。

1. BeanPostProcessor介紹

BeanPostProcessor是一個(gè)接口,該接口提供給開(kāi)發(fā)者使用,開(kāi)發(fā)者可以實(shí)現(xiàn)該接口,然后在實(shí)現(xiàn)類(lèi)中對(duì)想要處理的類(lèi)做增強(qiáng)處理。

該接口中提供了兩個(gè)基礎(chǔ)方法:

  • postProcessBeforeInitialization:Bean初始化前對(duì)Bean的增強(qiáng)處理
  • postProcessAfterInitialization:Bean初始化后對(duì)Bean的增強(qiáng)處理
public interface BeanPostProcessor {
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

下面舉一個(gè)最簡(jiǎn)單的例子來(lái)看一下BeanPostProcessor的使用。

2. BeanPostProcessor的使用

@Service
public class UserService {
    private String name = "陳tom";
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
@Component
public class MyPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("userService".equals(beanName)) {
            UserService userService = (UserService) bean;
            userService.setName("陳湯姆");
            userService.setAge(21);
        }
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}
@SpringBootApplication
public class BootApplication {
    @Resource
    private DefaultListableBeanFactory defaultListableBeanFactory;
    public static void main(String[] args) {
        SpringApplication.run(BootApplication.class,args);
    }
    @PostConstruct
    public void init() {
        UserService userService = defaultListableBeanFactory.getBean("userService", UserService.class);
        System.out.println("測(cè)試結(jié)果:姓名:"+userService.getName()+";年齡:"+userService.getAge());
    }
}

以上的實(shí)現(xiàn)中做了最簡(jiǎn)單的實(shí)現(xiàn),通過(guò)MyPostProcessor實(shí)現(xiàn)BeanPostProcessor接口,然后在前置增強(qiáng)處理中加入對(duì)Bean的修改。

然后通過(guò)PostConstruct在Bean初始化后做Bean的查詢(xún),得到通過(guò)BeanPostProcessor操作的結(jié)果。

所以BeanPostProcessor在使用上來(lái)說(shuō)很簡(jiǎn)單,對(duì)于開(kāi)發(fā)者來(lái)說(shuō)它很方便的提供了對(duì)于Bean對(duì)象的修改操作,提高了Spring的擴(kuò)展性和靈活性。

3. BeanPostProcessor的作用

說(shuō)完了最基礎(chǔ)的BeanPostProcessor的使用,通過(guò)以上的實(shí)現(xiàn)來(lái)梳理下BeanPostProcessor的作用。

  • 對(duì)Bean的修改操作,通過(guò)實(shí)現(xiàn)該接口可以很快的實(shí)現(xiàn)對(duì)Bean的操作
  • 提供前置和后置兩個(gè)處理,提供開(kāi)發(fā)者可以在初始化前做處理以及初始化后做處理
  • 對(duì)于Spring框架的靈活性,使用Spring框架也可以很方便的做自己的邏輯處理

自己對(duì)于BeanPostProcessor最大的感受就是太靈活了,開(kāi)發(fā)者只要實(shí)現(xiàn)該接口,然后重寫(xiě)其中的方法就可以實(shí)現(xiàn)自己的邏輯。這樣也保證了Spring容器對(duì)于開(kāi)發(fā)者來(lái)說(shuō)并不是一個(gè)黑盒,開(kāi)發(fā)者可以通過(guò)Spring提供的鑰匙讓Spring容器暴露在開(kāi)發(fā)者眼中,想要做什么處理都可以根據(jù)提供的鑰匙實(shí)現(xiàn)。(這里其實(shí)還有一個(gè)配套的BeanFactoryPostProcessor,面試的時(shí)候也經(jīng)常被問(wèn)到BeanPostProcessor和BeanFactoryPostProcessor的區(qū)別,有興趣的可以自己了解下,區(qū)別只是最終服務(wù)的對(duì)象不一樣)

這里不得不說(shuō)Spring YYDS?。?!

4. BeanPostProcessor注冊(cè)

Q:既然開(kāi)發(fā)者通過(guò)自己的實(shí)現(xiàn)類(lèi)實(shí)現(xiàn)了BeanPostProcessor,那么Spring又是如何將開(kāi)發(fā)者做的實(shí)現(xiàn)類(lèi)加入到Spring中并且執(zhí)行開(kāi)發(fā)者重寫(xiě)的前置和后置增強(qiáng)邏輯呢?

這里就要提到Spring對(duì)于BeanPostProcessor的設(shè)計(jì),在Spring中初始化了一個(gè)CopyOnWriteArrayList作為存儲(chǔ)所有實(shí)現(xiàn)BeanPostProcessor的列表。

從實(shí)現(xiàn)上可以看到該列表是一個(gè)寫(xiě)復(fù)制的列表,通俗點(diǎn)講就是向該列表中添加元素時(shí),不直接往當(dāng)前容器添加,而是先將當(dāng)前容器進(jìn)行Copy,復(fù)制出一個(gè)新的容器,然后新的容器里添加元素,添加完元素之后,再將原容器的引用指向新的容器。這里不展開(kāi)說(shuō)只要知道就是一個(gè)列表就可以。

Spring向該容器中添加的邏輯源碼如下:

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
	//存儲(chǔ)BeanPostProcessor列表
	private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
	@Override
	public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
		Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
		// Remove from old position, if any
		this.beanPostProcessors.remove(beanPostProcessor);
		// Track whether it is instantiation/destruction aware
		if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
			this.hasInstantiationAwareBeanPostProcessors = true;
		}
		if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
			this.hasDestructionAwareBeanPostProcessors = true;
		}
		// 將BeanPostProcessor加入beanPostProcessors列表中
		this.beanPostProcessors.add(beanPostProcessor);
	}
}

這里展示的只是最終寫(xiě)入的邏輯,那么從源頭到寫(xiě)入BeanPostProcessor的邏輯是怎么樣呢?

以ClassPatchXmlApplicationContext為例:

  • org.springframework.context.support.ClassPathXmlApplicationContext#ClassPathXmlApplicationContext
  • org.springframework.context.support.AbstractApplicationContext#refresh
  • org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, org.springframework.context.support.AbstractApplicationContext)
  • org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List<org.springframework.beans.factory.config.BeanPostProcessor>)
  • org.springframework.beans.factory.support.AbstractBeanFactory#addBeanPostProcessor

時(shí)序圖如下:

5. BeanPostProcessor調(diào)用

說(shuō)完如何注冊(cè)BeanPostProcessor,最后來(lái)說(shuō)如何將注冊(cè)到beanPostProcessors的實(shí)現(xiàn)類(lèi)進(jìn)行調(diào)用。

前一篇聊Spring容器時(shí)也提到了Spring在初始化Bean時(shí)會(huì)執(zhí)行BeanPostProcessor的增強(qiáng)處理,具體的調(diào)用源碼如下:

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
		implements AutowireCapableBeanFactory {
	//初始化Bean
	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}
		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//調(diào)用BeanPostProcesso#postProcessBeforeInitialization:前置處理
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}
		try {
			//執(zhí)行初始化方法
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			//調(diào)用調(diào)用BeanPostProcesso#postProcessAfterInitialization:后置處理
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
		return wrappedBean;
	}
	//BeanPostProcessor前置邏輯處理
	@Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {
		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			//執(zhí)行實(shí)現(xiàn)BeanPostProcessor的實(shí)現(xiàn)類(lèi)的前置增強(qiáng)邏輯
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}
	//BeanPostProcessor后置邏輯處理
	@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {
		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			//執(zhí)行實(shí)現(xiàn)BeanPostProcessor的實(shí)現(xiàn)類(lèi)的后置增強(qiáng)邏輯
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}
}

從以上源碼中可以看到在初始化Bean時(shí)調(diào)用前置和后置增強(qiáng),并且這里也做了明確的邊界,前置增強(qiáng)處理一定是在invokeInitMethods之前,后置增強(qiáng)一定是在invokeInitMethods之后。這樣就保證了BeanPostProcessor的執(zhí)行順序,也可以讓開(kāi)發(fā)者在使用過(guò)程中只要掌握Bean的生命周期,那么就可以自主的對(duì)Bean進(jìn)行增強(qiáng)處理。

6. 總結(jié)

以上是對(duì)Spring中BeanPostProcessor的源碼梳理,對(duì)BeanPostProcessor的介紹到使用、作用、注冊(cè)實(shí)現(xiàn)和調(diào)用實(shí)現(xiàn),完成了對(duì)BeanPostProcessor的源碼分析。

對(duì)于文中提到的BeanFactoryPostProcessor有興趣的可以從源碼按照這個(gè)過(guò)程梳理一下,其實(shí)跟BeanPostProcessor作用是相同的。

以上就是Spring BeanPostProcessor源碼示例解析的詳細(xì)內(nèi)容,更多關(guān)于Spring BeanPostProcessor的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 深入理解Spring事務(wù)的傳播行為

    深入理解Spring事務(wù)的傳播行為

    Spring在TransactionDefinition接口中規(guī)定了7種類(lèi)型的事務(wù)傳播行為。下面這篇文章主要給大家介紹了關(guān)于Spring事務(wù)傳播行為的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • 詳解Spring中使用xml配置bean的細(xì)節(jié)

    詳解Spring中使用xml配置bean的細(xì)節(jié)

    本篇文章主要介紹了Spring中使用xml配置bean的細(xì)節(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • Java關(guān)鍵字instanceof的兩種用法實(shí)例

    Java關(guān)鍵字instanceof的兩種用法實(shí)例

    這篇文章主要介紹了Java關(guān)鍵字instanceof的兩種用法實(shí)例,本文給出了instanceof關(guān)鍵字用于判斷一個(gè)引用類(lèi)型變量所指向的對(duì)象是否是一個(gè)類(lèi)(或接口、抽象類(lèi)、父類(lèi))及用于數(shù)組比較,需要的朋友可以參考下
    2015-03-03
  • SpringBoot集成JWT實(shí)現(xiàn)Token登錄驗(yàn)證的示例代碼

    SpringBoot集成JWT實(shí)現(xiàn)Token登錄驗(yàn)證的示例代碼

    隨著技術(shù)的發(fā)展,分布式web應(yīng)用的普及,通過(guò)session管理用戶(hù)登錄狀態(tài)成本越來(lái)越高,因此慢慢發(fā)展成為token的方式做登錄身份校驗(yàn),本文就來(lái)介紹一下SpringBoot集成JWT實(shí)現(xiàn)Token登錄驗(yàn)證的示例代碼,感興趣的可以了解一下
    2023-12-12
  • openEuler?搭建java開(kāi)發(fā)環(huán)境的詳細(xì)過(guò)程

    openEuler?搭建java開(kāi)發(fā)環(huán)境的詳細(xì)過(guò)程

    這篇文章主要介紹了openEuler?搭建java開(kāi)發(fā)環(huán)境,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • java list中包含某個(gè)字符串的兩種方法實(shí)現(xiàn)

    java list中包含某個(gè)字符串的兩種方法實(shí)現(xiàn)

    在Java開(kāi)發(fā)中,經(jīng)常需要判斷一個(gè)List中是否包含特定的字符串,包括使用contains()方法和循環(huán)遍歷判斷,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • 手把手帶你掌握SpringBoot RabbitMQ延遲隊(duì)列

    手把手帶你掌握SpringBoot RabbitMQ延遲隊(duì)列

    RabbitMQ 是一個(gè)由Erlang語(yǔ)言開(kāi)發(fā)的AMQP的開(kāi)源實(shí)現(xiàn),支持多種客戶(hù)端。用于在分布式系統(tǒng)中存儲(chǔ)轉(zhuǎn)發(fā)消息,在易用性、擴(kuò)展性、高可用性等方面表現(xiàn)不俗,下文將帶你深入了解 RabbitMQ 延遲隊(duì)列
    2021-09-09
  • shiro多驗(yàn)證登錄代碼實(shí)例及問(wèn)題解決

    shiro多驗(yàn)證登錄代碼實(shí)例及問(wèn)題解決

    這篇文章主要介紹了shiro多驗(yàn)證登錄代碼實(shí)例及問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • java中自定義Spring Security權(quán)限控制管理示例(實(shí)戰(zhàn)篇)

    java中自定義Spring Security權(quán)限控制管理示例(實(shí)戰(zhàn)篇)

    本篇文章主要介紹了java中自定義Spring Security權(quán)限控制管理示例(實(shí)戰(zhàn)篇) ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-02-02
  • 舉例講解Java設(shè)計(jì)模式編程中Decorator裝飾者模式的運(yùn)用

    舉例講解Java設(shè)計(jì)模式編程中Decorator裝飾者模式的運(yùn)用

    這篇文章主要介紹了Java設(shè)計(jì)模式編程中Decorator裝飾者模式的運(yùn)用,裝飾者模式就是給一個(gè)對(duì)象動(dòng)態(tài)的添加新的功能,裝飾者和被裝飾者實(shí)現(xiàn)同一個(gè)接口,裝飾者持有被裝飾者的實(shí)例,需要的朋友可以參考下
    2016-05-05

最新評(píng)論

寿光市| 西吉县| 宁津县| 阿巴嘎旗| 安仁县| 偃师市| 江川县| 阳原县| 昌都县| 元氏县| 富顺县| 新野县| 呼和浩特市| 陵水| 四平市| 米泉市| 龙山县| 南昌县| 鸡泽县| 广汉市| 全椒县| 湖口县| 潮安县| 稻城县| 正蓝旗| 保康县| 象山县| 沽源县| 崇州市| 静乐县| 墨竹工卡县| 资溪县| 通江县| 庆城县| 山西省| 临江市| 克什克腾旗| 卢氏县| 菏泽市| 财经| 博白县|