主頁 > 軟體設計 > Bean生命周期的擴展點:Bean Post Processor

Bean生命周期的擴展點:Bean Post Processor

2023-06-29 08:56:17 軟體設計

摘要:在本篇文章中,我們將深入探討Spring框架中的重要組件——BeanPostProcessor,首先,我們將了解其設計理念和目標,然后通過實際的例子學習如何基礎使用它,如何通過BeanPostProcessor改變Bean的初始化結果以及如何利用它修改Bean的屬性,

本文分享自華為云社區《Spring高手之路6——Bean生命周期的擴展點:BeanPostProcessor》,作者:磚業洋__ ,

1. 探索Spring的后置處理器(BeanPostProcessor)

1.1 BeanPostProcessor的設計理念

BeanPostProcessor的設計目標主要是提供一種擴展機制,讓開發者可以在Spring Bean的初始化階段進行自定義操作,這種設計理念主要體現了Spring的一種重要原則,即“開放封閉原則”,開放封閉原則強調軟體物體(類、模塊、函式等等)應該對于擴展是開放的,對于修改是封閉的,在這里,Spring容器對于Bean的創建、初始化、銷毀等生命周期進行了管理,但同時開放了BeanPostProcessor這種擴展點,讓開發者可以在不修改Spring原始碼的情況下,實作對Spring Bean生命周期的自定義操作,這種設計理念大大提升了Spring的靈活性和可擴展性,

BeanPostProcessor不是Spring Bean生命周期的一部分,但它是在Spring Bean生命周期中起重要作用的組件,

1.2 BeanPostProcessor的檔案說明

我們來看看這個方法的檔案注釋,從圖中可以看到,BeanPostProcessor 介面定義了兩個方法,postProcessBeforeInitialization和postProcessAfterInitialization

postProcessBeforeInitialization方法會在任何bean初始化回呼(如InitializingBean的afterPropertiesSet方法或者自定義的init-method)之前被呼叫,也就是說,這個方法會在bean的屬性已經設定完畢,但還未進行初始化時被呼叫,

postProcessAfterInitialization方法在任何bean初始化回呼(比如InitializingBean的afterPropertiesSet或者自定義的初始化方法)之后被呼叫,這個時候,bean的屬性值已經被填充完畢,回傳的bean實體可能是原始bean的一個包裝,

2. BeanPostProcessor的使用

2.1 BeanPostProcessor的基礎使用示例

全部代碼如下:

首先定義兩個簡單的Bean:Lion和Elephant

Lion.java

package com.example.demo.bean;
public class Lion {
 private String name;
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
}

Elephant.java

package com.example.demo.bean;
public class Elephant {
 private String name;
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
}

然后定義一個簡單的BeanPostProcessor,它只是列印出被處理的Bean的名字:

package com.example.demo.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
 @Override
 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
 System.out.println("Before initialization: " + beanName);
 return bean;
 }
 @Override
 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
 System.out.println("After initialization: " + beanName);
 return bean;
 }
}

接著我們定義一個配置類,其中包含對Lion、Elephant類和MyBeanPostProcessor類的Bean定義:

package com.example.demo.configuration;
import com.example.demo.bean.Elephant;
import com.example.demo.bean.Lion;
import com.example.demo.processor.MyBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AnimalConfig {
 @Bean
 public Lion lion() {
 return new Lion();
 }
 @Bean
 public Elephant elephant() {
 return new Elephant();
 }
 @Bean
 public MyBeanPostProcessor myBeanPostProcessor() {
 return new MyBeanPostProcessor();
 }
}

最后,我們在主程式中創建ApplicationContext物件:

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
 public static void main(String[] args) {
 ApplicationContext context = new AnnotationConfigApplicationContext(AnimalConfig.class);
 ((AnnotationConfigApplicationContext)context).close();
 }
}

運行結果:

以上代碼在執行時,將先創建Lion和Elephant物件,然后在初始化程序中和初始化后呼叫postProcessBeforeInitialization和postProcessAfterInitialization方法,列印出被處理的Bean的名字,

細心的小伙伴可能觀察到這里有紅色日志
資訊: Bean 'animalConfig' of type [com.example.demo.configuration.AnimalConfig$$EnhancerBySpringCGLIB$$ee4adc7e] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

在Spring中,BeanPostProcessor是被特殊處理的,它們會在其他普通Bean之前被實體化和初始化,這樣設計的原因是BeanPostProcessor的存在可以影響其他Bean的創建和初始化程序, Spring應用背景關系中可以存在多個BeanPostProcessor,Spring本身就提供了很多內置的BeanPostProcessor,

但是,如果在初始化BeanPostProcessor的程序中需要依賴其他的Bean,那么這些被依賴的Bean會先于后置處理器進行初始化,然而,由于這些被依賴的Bean是在該BeanPostProcessor初始化完成之前就已經進行了初始化,它們就會錯過這個BeanPostProcessor的處理,在這個例子中,MyBeanPostProcessor就是這樣的一個BeanPostProcessor,而"animalConfig"是它所依賴的Bean,所以這個日志資訊就是說,'animalConfig'這個Bean在初始化的時候,沒有被所有的BeanPostProcessor處理,這里它無法得到MyBeanPostProcessor的處理,

我們只需要把實體化程序直接交給Spring容器來管理,而不是在配置類中手動進行實體化,就可以消除這個提示資訊,也就是在MyBeanPostProcessor上加@Component即可,

在第3節的例子中就使用了@Component處理這個MyBeanPostProcessor,這個提示就消失了,

2.2 利用BeanPostProcessor修改Bean的初始化結果的回傳值

還是上面的例子,我們只修改一下MyBeanPostProcessor 類的方法后再次運行

package com.example.demo.processor;
import com.example.demo.bean.Elephant;
import com.example.demo.bean.Lion;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
 @Override
 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
 System.out.println("Before initialization: " + bean);
 if (bean instanceof Lion) {
 return new Elephant();
 }
 return bean;
 }
 @Override
 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
 System.out.println("After initialization: " + bean);
 return bean;
 }
}

運行結果:

BeanPostProcessor的兩個方法都可以回傳任意的Object,這意味著我們可以在這兩個方法中更改回傳的bean,例如,如果我們讓postProcessBeforeInitialization方法在接收到Lion實體時回傳一個新的Elephant實體,那么我們將會看到Lion實體變成了Elephant實體,

那既然BeanPostProcessor的兩個方法都可以回傳任意的Object,那我搞點破壞回傳null會怎么樣,會不會因為初始化bean為null而導致例外呢?

答案是不會的,我們來看一下:

package com.example.demo.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
 @Override
 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
 System.out.println("Before initialization: " + bean);
 return null;
 }
 @Override
 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
 System.out.println("After initialization: " + bean);
 return bean;
 }
}

我們運行看結果

結果發現還是正常初始化的bean型別,不會有任何改變,我們繼續除錯看看是為什么

我們通過堆疊幀看到呼叫postProcessBeforeInitialization方法的上一個方法是applyBeanPostProcessorsBeforeInitialization,雙擊點開看一看這個方法

從我這個除錯圖中可以看到,如果postProcessBeforeInitialization回傳null,Spring仍然用原始的bean進行后續的處理,同樣的邏輯在postProcessAfterInitialization也是一樣,這就是為什么我們在BeanPostProcessor類的方法中回傳null,原始bean實體還是存在的原因,

2.3 通過BeanPostProcessor實作Bean屬性的動態修改

來看看是怎么攔截 bean 的初始化的

全部代碼如下:

首先,我們定義一個Lion類:

public class Lion {
 private String name;
 public Lion() {
 this.name = "Default Lion";
 }
 public Lion(String name) {
 this.name = name;
 }
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
 @Override
 public String toString() {
 return "Lion{" + "name='" + name + '\'' + '}';
 }
}

接下來,我們定義一個BeanPostProcessor,我們稱之為MyBeanPostProcessor :

package com.example.demo.processor;
import com.example.demo.bean.Lion;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
 @Override
 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
 System.out.println("Bean的初始化之前:" + bean);
 return bean;
 }
 @Override
 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
 System.out.println("Bean的初始化之后:" + bean);
 if (bean instanceof Lion) {
 ((Lion) bean).setName("Simba");
 }
 return bean;
 }
}

然后我們定義一個配置類,其中包含對Lion類的Bean定義和對MyBeanPostProcessor 類的Bean定義:

package com.example.demo.configuration;
import com.example.demo.bean.Lion;
import com.example.demo.processor.MyBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AnimalConfig {
 @Bean
 public Lion lion() {
 return new Lion();
 }
 @Bean
 public MyBeanPostProcessor myBeanPostProcessor() {
 return new MyBeanPostProcessor();
 }
}

最后,我們在主程式中創建ApplicationContext物件,并獲取Lion物件:

package com.example.demo;
import com.example.demo.bean.Lion;
import com.example.demo.configuration.AnimalConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
 public static void main(String[] args) {
 ApplicationContext context = new AnnotationConfigApplicationContext(AnimalConfig.class);
 Lion lion = context.getBean("lion", Lion.class);
 System.out.println(lion);
 ((AnnotationConfigApplicationContext)context).close();
 }
}

運行結果:

上面代碼在執行時,先創建一個Lion物件,然后在初始化程序中和初始化后呼叫postProcessBeforeInitialization和postProcessAfterInitialization方法,修改Lion的名字為"Simba",最后在主程式中輸出Lion物件,顯示其名字為"Simba",

3. 深度剖析BeanPostProcessor的執行時機

3.1 后置處理器在Bean生命周期中的作用及執行時機

在這個例子中,我們將創建一個名為Lion和Elephant 的Bean,它會展示屬性賦值和生命周期的各個步驟的執行順序,同時,我們還將創建一個BeanPostProcessor來列印訊息并顯示它的執行時機,

全部代碼如下:

首先,我們定義我們的Lion:

package com.example.demo.bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
public class Lion implements InitializingBean, DisposableBean {
 private String name;
 private Elephant elephant;
 public Lion() {
 System.out.println("1. Bean Constructor Method Invoked!");
 }
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 System.out.println("2. Bean Setter Method Invoked! name: " + name);
 }
 /**
     * setter注入
     * @param elephant
     */
 @Resource
 public void setElephant(Elephant elephant) {
 this.elephant = elephant;
 System.out.println("2. Bean Setter Method Invoked! elephant: " + elephant);
 }
 @PostConstruct
 public void postConstruct() {
 System.out.println("4. @PostConstruct Method Invoked!");
 }
 @Override
 public void afterPropertiesSet() throws Exception {
 System.out.println("5. afterPropertiesSet Method Invoked!");
 }
 public void customInitMethod() {
 System.out.println("6. customInitMethod Method Invoked!");
 }
 @PreDestroy
 public void preDestroy() {
 System.out.println("8. @PreDestroy Method Invoked!");
 }
 @Override
 public void destroy() throws Exception {
 System.out.println("9. destroy Method Invoked!");
 }
 public void customDestroyMethod() {
 System.out.println("10. customDestroyMethod Method Invoked!");
 }
}

創建Lion所依賴的Elephant

package com.example.demo.bean;
import org.springframework.stereotype.Component;
@Component
public class Elephant {
 private String name;
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
}

然后,我們定義一個簡單的BeanPostProcessor:

package com.example.demo.processor;
import com.example.demo.bean.Lion;
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(bean instanceof Lion) {
 System.out.println("3. postProcessBeforeInitialization Method Invoked!");
 }
 return bean;
 }
 @Override
 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
 if(bean instanceof Lion) {
 System.out.println("7. postProcessAfterInitialization Method Invoked!");
 }
 return bean;
 }
}

創建一個配置類AnimalConfig

package com.example.demo.configuration;
import com.example.demo.bean.Lion;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AnimalConfig {
 @Bean(initMethod = "customInitMethod", destroyMethod = "customDestroyMethod")
 public Lion lion() {
 Lion lion = new Lion();
 lion.setName("my lion");
 return lion;
 }
}

主程式:

package com.example.demo;
import com.example.demo.bean.Lion;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
 public static void main(String[] args) {
 System.out.println("容器初始化之前...");
 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.example");
 System.out.println("容器初始化完成");
 Lion bean = context.getBean(Lion.class);
 bean.setName("oh!!! My Bean set new name");
 System.out.println("容器準備關閉...");
 context.close();
 System.out.println("容器已經關閉");
 }
}

控制臺上看到所有的方法呼叫都按照預期的順序進行,這可以更好地理解Bean屬性賦值和生命周期以及BeanPostProcessor的作用,

根據列印日志我們可以分析出

  1. 首先,Bean Constructor Method Invoked! 表明 Lion 的構造器被呼叫,創建了一個新的 Lion 實體,
  2. 接著,Bean Setter Method Invoked! name: my lion 和 Bean Setter Method Invoked! elephant: com.example.demo.bean.Elephant@7364985f 說明 Spring 對 Lion 實體的依賴注入,在這一步,Spring 呼叫了 Lion 的 setter 方法,為 name 屬性設定了值 “my lion”,同時為 elephant 屬性注入了一個 Elephant 實體,
  3. 然后,postProcessBeforeInitialization Method Invoked! 說明 MyBeanPostProcessor 的 postProcessBeforeInitialization 方法被呼叫,這是在初始化 Lion 實體之前,
  4. @PostConstruct Method Invoked! 說明 @PostConstruct 注解的方法被呼叫,這是在 Bean 初始化之后,但是在 Spring 執行任何進一步初始化之前,
  5. afterPropertiesSet Method Invoked! 說明 Spring 呼叫了 InitializingBean 的 afterPropertiesSet 方法
  6. customInitMethod Method Invoked! 表示呼叫了 Lion 實體的 init-method 方法,
  7. postProcessAfterInitialization Method Invoked! 說明 MyBeanPostProcessor 的 postProcessAfterInitialization 方法被呼叫,這是在初始化 Lion 實體之后,
    然后 Spring 完成了整個初始化程序,
  8. 主程式中手動呼叫了 Lion 實體的 setter 方法,因此在 Bean Setter Method Invoked! name: oh!!! My Bean set new name 可見,name 屬性被設定了新的值 "oh!!! My Bean set new name",
    當容器準備關閉時:
  9. @PreDestroy Method Invoked! 說明 @PreDestroy 注解的方法被呼叫,這是在 Bean 銷毀之前,
  10. destroy Method Invoked! 表示 Lion 實體開始銷毀,在這一步,Spring 呼叫了 DisposableBean 的 destroy 方法,
  11. customDestroyMethod Method Invoked! 表示 Lion 實體開始銷毀,呼叫了Lion 實體的 destroy-method 方法,

最后,Spring 完成了整個銷毀程序,容器關閉,

這個日志提供了 Spring Bean 生命周期的完整視圖,顯示了從創建到銷毀程序中的所有步驟,

注意:DisposableBean 的 destroy 方法和 destroy-method 方法呼叫,這個銷毀程序不意味著bean實體就被立即從記憶體中洗掉了,Java的垃圾收集機制決定了物件什么時候被從記憶體中洗掉,Spring容器無法強制進行這個操作,比如解除bean之間的關聯和清理快取,這并不是Spring在銷毀bean時會做的,而是由Java的垃圾回收器在一個物件不再被參考時做的事情,

BeanPostProcessor 的執行順序是在 Spring Bean 的生命周期中非常重要的一部分,例如,如果一個 Bean 實作了 InitializingBean 介面,那么 afterPropertiesSet 方法會在所有的 BeanPostProcessor 的 postProcessBeforeInitialization 方法之后呼叫,以確保所有的前置處理都完成了,同樣,BeanPostProcessor 的 postProcessAfterInitialization 方法會在所有的初始化回呼方法之后呼叫,以確保 Bean 已經完全初始化了,

我們可以注冊多個 BeanPostProcessor,在這種情況下,Spring 會按照它們的 Ordered 介面或者 @Order 注解指定的順序來呼叫這些后置處理器,如果沒有指定順序,那么它們的執行順序是不確定的,

3.2 圖解:Bean生命周期與后置處理器的互動時序

綜合上面的執行結果,我們來總結一下,下面是Spring Bean生命周期的時序圖,它詳細地描繪了Spring Bean從實體化到準備使用的整個程序,包括Bean的實體化、屬性賦值、生命周期方法的執行和后置處理器的呼叫,

 

點擊關注,第一時間了解華為云新鮮技術~

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/556255.html

標籤:架構設計

上一篇:說說設計模式~委派模式

下一篇:返回列表

標籤雲
其他(161825) Python(38259) JavaScript(25516) Java(18273) C(15238) 區塊鏈(8273) C#(7972) AI(7469) 爪哇(7425) MySQL(7271) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4607) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2438) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1985) HtmlCss(1976) 功能(1967) Web開發(1951) C++(1942) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • Bean生命周期的擴展點:Bean Post Processor

    摘要:在本篇文章中,我們將深入探討Spring框架中的重要組件——BeanPostProcessor。首先,我們將了解其設計理念和目標,然后通過實際的例子學習如何基礎使用它,如何通過BeanPostProcessor改變Bean的初始化結果以及如何利用它修改Bean的屬性。 本文分享自華為云社區《S ......

    uj5u.com 2023-06-29 08:56:17 more
  • 說說設計模式~委派模式

    [回到目錄](https://www.cnblogs.com/lori/p/3896484.html) # 概述 委派模式(Delegate Pattern)又叫作委托模式,是一種面向物件的設計模式,允許物件組合實作與繼承相同的代碼重用。它的基本作用就是負責任務的呼叫和分配,是一種特殊的靜態代理模式 ......

    uj5u.com 2023-06-28 11:02:11 more
  • 說說設計模式~責任鏈模式

    [回到目錄](https://www.cnblogs.com/lori/p/3896484.html) # 責任鏈模式 它是一種設計模塊,主要將操作流程與具體操作解耦,讓每個操作都可以設定自己的操作流程,這對于作業流應用是一個不錯的選擇! 下面是官方標準的定義:責任鏈模式是一種設計模式。在責任鏈模式 ......

    uj5u.com 2023-06-28 11:02:04 more
  • 說說設計模式~責任鏈模式

    [回到目錄](https://www.cnblogs.com/lori/p/3896484.html) # 責任鏈模式 它是一種設計模塊,主要將操作流程與具體操作解耦,讓每個操作都可以設定自己的操作流程,這對于作業流應用是一個不錯的選擇! 下面是官方標準的定義:責任鏈模式是一種設計模式。在責任鏈模式 ......

    uj5u.com 2023-06-28 11:01:46 more
  • 說說設計模式~委派模式

    [回到目錄](https://www.cnblogs.com/lori/p/3896484.html) # 概述 委派模式(Delegate Pattern)又叫作委托模式,是一種面向物件的設計模式,允許物件組合實作與繼承相同的代碼重用。它的基本作用就是負責任務的呼叫和分配,是一種特殊的靜態代理模式 ......

    uj5u.com 2023-06-28 10:56:15 more
  • 驅動開發:取行程模塊的函式地址

    在筆者上一篇文章`《驅動開發:內核取應用層模塊基地址》`中簡單為大家介紹了如何通過遍歷`PLIST_ENTRY32`鏈表的方式獲取到`32位`應用程式中特定模塊的基地址,由于是入門系列所以并沒有封裝實作太過于通用的獲取函式,本章將繼續延申這個話題,并依次實作通用版`GetUserModuleBase... ......

    uj5u.com 2023-06-28 10:09:39 more
  • 高并發整體可用性:一文詳解降級、限流和熔斷

    水滿則溢,月盈則虧,任何事物都不可能無限制的發展,我們的系統服務能力也一樣。



    當隨著流量的不斷增長,達到或超過服務本身的可承載范圍,系統服務的自我保護機制的建立就顯得很重要了。



    本文希望可以用最通俗的解釋和貼切的實體來帶大家了解什么是限流、降級和熔斷。 ......

    uj5u.com 2023-06-28 10:09:22 more
  • 讀發布!設計與部署穩定的分布式系統(第2版)筆記14_穩態

    ![](https://img2023.cnblogs.com/blog/3076680/202306/3076680-20230627102336712-1268258427.png) # 1. 最大限度地避免直接對生產系統進行人為操作最為妥善 ## 1.1. 人為干預生產環境會導致問題 ### ......

    uj5u.com 2023-06-28 10:09:06 more
  • 微服務架構基本原理學習筆記(三)

    上一篇:微服務架構基本原理學習筆記(二) 五、微服務之間的通信 微服務通信模式 微服務本身并沒有規定通信規則,換句話說,一個微服務并沒有規定可以被哪些應用程式訪問,或者被哪些其它的微服務呼叫。應用程式與微服務間的直接通信,或者微服務與微服務間的直接呼叫,往往會因為其中錯綜復雜的關系而導致級聯故障,任 ......

    uj5u.com 2023-06-28 10:08:46 more
  • 如何做好垂直域穩定性

    一個小小的故障就可能造成巨大的負面影響,因此穩定性作業復雜卻又至關重要。本文將通過故障預防、修復、復盤來講解該如何建設一個穩定性體系。



    來到阿里后,我的作業內容一直都是商品中心的穩定性,這份作業對于我個人在技術和經驗上的成長提升是無比巨大的。在我看來,穩定性是一個極為復雜的作業,對人的能力考驗... ......

    uj5u.com 2023-06-28 10:08:10 more