JavaRush /Java Blog /Random-TW /Spring框架。介紹
Marchello
等級 20
Санкт-Петербург

Spring框架。介紹

在 Random-TW 群組發布
你好!當 JavaRush 管理部門正在努力提高新水平時,我想開始撰寫一系列有關 Spring 框架的培訓文章。是的,我知道互聯網上已經有很多關於這個主題的材料,但是,正如實踐所示,它們都處於 Hello World 級別。我不想談論如何正確放置註釋,而是談論它在“幕後”如何工作。本文面向那些已經以某種方式使用過該框架並熟悉基本概念的人。 Spring框架。 簡介 - 1

初始化上下文。

那麼就讓我們從基礎開始吧。在我看來,最重要的一點是了解上下文是如何設定的以及 beans 是如何初始化的。如您所知,在Spring開始工作之前,需要對其進行配置。在遠古時代,這是使用 xml 檔案完成的(在某些專案中,主要是舊項目,他們至今仍在這樣做)。這是此類設定檔的一個小範例:
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="helloWorld" class="ru.javarush.HelloWorld">
       <property name="message" value="Hello World!"/>
   </bean>

</beans>
總的來說,這足以創建幾個控制器並啟動一個啟動程序(這不會啟動)。但是這個配置將如何讓 Spring 運作呢?這就是事情變得有趣的地方。為了讓 Spring 能夠理解我們的配置,有一個XmlBeanDefinitionReader. 這是一個內部 Spring 元件,它掃描(解析)xml 並根據我們在那裡編寫的內容創建BeanDefinitionxml 。BeanDefinition是一個儲存有關 bean 資訊的物件。這包括:應該從哪個類別(bean)創建;範圍; 是否安裝了延遲初始化;是否有必要在此 bean 之前初始化另一個以及 xml 中描述的其他屬性。所有收到的BeanDefinition都會被添加到 中HashMap,其中標識符是 bean 的名稱(由您設定或由 Spring 分配)和BeanDefinition物件本身。一切都創建完成後BeanDefinition,一個新的英雄出現在舞台上— BeanFactory。該物件迭代HashMap’es BeanDefinition,基於它們建立 bean 並將它們放入 IoC 容器中。這裡有一個細微差別,事實上,當應用程式啟動時,IoC 容器將包含具有 Singleton 範圍的 bean(預設),而其餘的 bean 在需要時建立(原型、請求、會話)。現在扯個小題外話,讓我們來認識另一個角色。

來認識 BeanPostProcessor。(BPP)

Bean 後處理器事實上,bean 不一定是應用程式的業務邏輯類別。bean 也稱為基礎設施 bean。簡而言之,基礎架構 bean 是配置業務邏輯 bean 的類別(是的,bean 太多了)。我將在下面告訴您更多相關信息,但為了讓您更清楚 BPP 的具體配置,我將舉一個範例。大家都熟悉這個摘要嗎@Autowired?因此,您AutowiredAnnotationBeanPostProcessor有責任確保所有類別都相互嵌入。 烏克維意思

讓我們回到BeanFactory

現在了解了 BPP,您需要澄清的是,在迭代HashMap' 時,BeanDefinition首先創建所有 ' 並單獨放置(不在 IoC 容器中)BeanPostProcessor。此後,我們的業務邏輯的常規 bean 被創建,放入 IoC 容器中,並且它們的配置開始使用單獨的延遲 BPP。事情就是這樣的,每個 BPP 有 2 個方法:
postProcessorBeforeInitialization(Object bean, String beanName);
postProcessorAfterInitialization(Object bean, String beanName);
遍歷我們的垃圾箱兩次。第一次呼叫該方法postProcessorBeforeInitialization,第二次呼叫該方法postProcessorAfterInitialization。當然,問題是為什麼需要兩種方法,讓我解釋一下。事實是,為了處理一些註解(例如@Transactional),我們的 bean 被替換為代理類別。要理解為什麼要這樣做,您需要知道它是如何工作的@Transactional,這就是它的工作原理。您需要在標有此註解的方法上新增幾行程式碼。怎麼做?沒錯,透過建立一個代理類,在其中將必要的程式碼新增到所需的方法中。現在想像一下這種情況,我們有一個類:
class A {
    @Autowired
    private SomeClass someClass;

    @Transactional
    public void method() {
        // модификатор доступа обязательно public
    }
}
該類別有 2 個註釋@Autowired@Transactional. 兩個註釋都由不同的 BPP 處理。如果它首先起作用AutowiredBPP,那麼一切都會好起來,但如果沒有,那麼我們就會遇到這個問題。事實是,當創建代理類別時,所有元資訊都會遺失。換句話說,@Autowired代理類別中不會有關於註釋的信息,因此AutowiredBPP它將不起作用,這意味著我們的欄位someClass將具有值null,這很可能會導致 NPE。還值得知道的是,在方法呼叫之間,postProcessorBeforeInitializationpostProcessorAfterInitialization呼叫-method init(如果有)。這基本上是第二個建構函數,但不同的是,此時我們所有的依賴項都已經嵌入到類別中,我們可以從init- 方法存取它們。因此,再次介紹上下文初始化演算法:
  1. XmlBeanDefinitionReader掃描我們的 xml 設定檔。
  2. 創建BeanDefinition並將它們放入HashMap.
  3. BeanFactory和由此HashMap分別將所有的相加BeanPostProcessor
  4. 從 's建立BeanDefinitionbean 並將它們放入 IoC 容器中。
  5. 這裡 BPP 使用 2 種方法來設定這些 bean。
  6. 準備好。
其實就這些了,如果你喜歡這篇文章,以及是否值得繼續寫這樣的教程,就寫吧。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION