JavaRush /Blog Java /Random-PL /Ramy wiosenne. Wstęp
Marchello
Poziom 20
Санкт-Петербург

Ramy wiosenne. Wstęp

Opublikowano w grupie Random-PL
Cześć! Podczas gdy administracja JavaRush pracuje nad nowymi poziomami, chcę rozpocząć serię artykułów szkoleniowych na temat Spring Framework. Tak, wiem, że w Internecie jest już mnóstwo materiałów na ten temat, jednak jak pokazuje praktyka, wszystkie są na poziomie Hello World. Chcę porozmawiać nie o tym, jak poprawnie umieszczać adnotacje, ale o tym, jak to wszystko działa „pod maską”. Artykuł jest przeznaczony dla tych, którzy już w taki czy inny sposób pracowali z tym frameworkiem i są zaznajomieni z podstawowymi pojęciami. Ramy wiosenne.  Wprowadzenie - 1

Inicjowanie kontekstu.

Zacznijmy więc od podstaw. Moim zdaniem jedną z najważniejszych kwestii jest zrozumienie, w jaki sposób tworzony jest kontekst i inicjowane są komponenty bean. Jak wiadomo, zanim Spring zacznie działać, należy go skonfigurować. W czasach przedpotopowych robiono to za pomocą plików XML (w niektórych projektach, głównie starych, robi się to do dziś). Oto mały przykład takiego pliku konfiguracyjnego:
<?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>
Ogólnie rzecz biorąc, wystarczy utworzyć kilka kontrolerów i uruchomić startup (który nie wystartuje). Ale w jaki sposób ta konfiguracja sprawi, że Spring będzie działał? I tu zaczyna się robić ciekawie. Aby nasza konfiguracja była zrozumiała dla Springa, istnieje plik XmlBeanDefinitionReader. BeanDefinitionJest to wewnętrzny komponent Springa, który skanuje (parsuje) XML i tworzy pliki XML na podstawie tego, co tam napisaliśmy . BeanDefinitionto obiekt przechowujący informacje o fasoli. Obejmuje to: z jakiej klasy powinien zostać utworzony komponent bean; zakres; czy zainstalowana jest leniwa inicjalizacja; Czy konieczne jest zainicjowanie przed tym komponentem bean innych i innych właściwości opisanych w xml. Wszystkie otrzymane BeanDefinition''' są dodawane do HashMap, w którym identyfikatorem jest nazwa komponentu bean (ustawiona przez Ciebie lub nadana przez Springa) oraz BeanDefinitionsam obiekt. Gdy wszystko BeanDefinitionjest już gotowe, na scenie pojawia się nowy bohater – BeanFactory. Obiekt ten iteruje po HashMap’es BeanDefinition, tworzy na ich podstawie komponenty bean i umieszcza je w kontenerze IoC. Jest tu pewien niuans, tak naprawdę po uruchomieniu aplikacji kontener IoC będzie zawierał komponenty bean, które mają zakres Singleton (domyślnie ustawiony), natomiast pozostałe tworzone są wtedy, gdy są potrzebne (prototyp, żądanie, sesja). A teraz mała dygresja, zapoznajmy się z inną postacią.

Poznaj BeanPostProcessor. (BPP)

postprocesor fasoliFaktem jest, że komponent bean niekoniecznie jest klasą logiki biznesowej dla Twojej aplikacji. Fasola nazywana jest także fasolą infrastrukturalną. Krótko mówiąc, komponent bean infrastruktury to klasa, która konfiguruje komponenty logiki biznesowej (tak, za dużo komponentów bean). Opowiem Wam o tym więcej poniżej, ale żeby było trochę jaśniej, co dokładnie konfiguruje BPP, podam przykład. Czy wszyscy znają podsumowanie @Autowired? Jesteś zatem AutowiredAnnotationBeanPostProcessorodpowiedzialny za upewnienie się, że wszystkie klasy są ze sobą osadzone. nieświadomy

Wróćmy do BeanFactory

Wiedząc teraz o BPP, musisz wyjaśnić, że podczas iteracji po HashMap„, BeanDefinitionwszystkie” są najpierw tworzone i umieszczane osobno (nie w kontenerze IoC) BeanPostProcessor. Następnie tworzone są regularne ziarna naszej logiki biznesowej, umieszczane w kontenerze IoC i rozpoczynana jest ich konfiguracja przy użyciu oddzielnie odroczonych BPP. A tak to się dzieje, każdy BPP ma 2 metody:
postProcessorBeforeInitialization(Object bean, String beanName);
postProcessorAfterInitialization(Object bean, String beanName);
Dwukrotnie przegląda nasze pojemniki. Przy pierwszym wywołaniu metody postProcessorBeforeInitializationi przy drugim wywołaniu metody postProcessorAfterInitialization. Z pewnością pojawiło się pytanie, dlaczego potrzebne są dwie metody, pozwólcie, że wyjaśnię. Faktem jest, że aby przetworzyć niektóre adnotacje (takie jak @Transactionalnp. ), nasz komponent bean zostaje zastąpiony klasą proxy. Aby zrozumieć, dlaczego tak się dzieje, musisz wiedzieć, jak to działa @Transactionali tak to działa. Musisz na bieżąco dodać jeszcze kilka linijek kodu do metody oznaczonej tą adnotacją. Jak to zrobić? Zgadza się, tworząc klasę proxy, wewnątrz której niezbędny kod zostanie dodany do wymaganej metody. Teraz wyobraźmy sobie taką sytuację, mamy klasę:
class A {
    @Autowired
    private SomeClass someClass;

    @Transactional
    public void method() {
        // модификатор доступа обязательно public
    }
}
Ta klasa ma 2 adnotacje @Autowiredi @Transactional. Obie adnotacje są przetwarzane przez różne procesy BPP. Jeśli to zadziała najpierw AutowiredBPP, wszystko będzie dobrze, ale jeśli nie, napotkamy ten problem. Faktem jest, że po utworzeniu klasy proxy wszystkie metainformacje zostają utracone. @AutowiredInnymi słowy, w klasie proxy nie będzie informacji o adnotacji , a co za tym idzie AutowiredBPP, nie będzie ona działać, co oznacza, że ​​nasze pole someClassbędzie miało wartość null, co najprawdopodobniej doprowadzi do NPE. Warto też wiedzieć, że pomiędzy wywołaniami metod wywoływana postProcessorBeforeInitializationjest metoda -o ile taka istnieje. Jest to w zasadzie drugi konstruktor, z tą różnicą, że w tym momencie wszystkie nasze zależności są już osadzone w klasie i mamy do nich dostęp poprzez metodę -. Zatem jeszcze raz algorytm inicjalizacji kontekstu: postProcessorAfterInitializationinitinit
  1. XmlBeanDefinitionReaderskanuje nasz plik konfiguracyjny XML.
  2. Tworzy BeanDefinitioni umieszcza je HashMap.
  3. Przychodzi BeanFactoryi z tego HashMapoddzielnie sumuje się wszystkie BeanPostProcessor„”.
  4. Tworzy komponenty BeanDefinitionbean z 's i umieszcza je w kontenerze IoC.
  5. Tutaj BPP przychodzą i konfigurują te komponenty bean przy użyciu 2 metod.
  6. Gotowy.
Właściwie to wszystko, napisz czy artykuł przypadł Ci do gustu i czy warto dalej pisać takie tutoriale.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION