Salam! JavaRush administrasiyası yeni səviyyələr üzərində işləyərkən mən Spring Framework ilə bağlı bir sıra təlim məqalələrinə başlamaq istəyirəm. Bəli, bilirəm ki, İnternetdə bu mövzuda çoxlu material var, amma təcrübədən göründüyü kimi, hamısı Salam Dünya səviyyəsindədir. Annotasiyaları necə düzgün yerləşdirmək barədə deyil, hamısının "başlıq altında" necə işlədiyi barədə danışmaq istəyirəm. Məqalə bu və ya digər şəkildə bu çərçivə ilə artıq işləmiş və əsas anlayışlarla tanış olanlar üçün nəzərdə tutulmuşdur.
Kontekstin işə salınması.
Beləliklə, əsaslardan başlayaq. Məncə, ən vacib məqamlardan biri kontekstin necə qurulduğunu və lobyaların necə işə salındığını başa düşməkdir. Bildiyiniz kimi, Bahar işə başlamazdan əvvəl onu konfiqurasiya etmək lazımdır. Antidiluvian dövrlərində bu, xml faylları ilə həyata keçirilirdi (bəzi layihələrdə, əsasən köhnə layihələrdə, bu günə qədər bunu davam etdirirlər). Belə bir konfiqurasiya faylının kiçik bir nümunəsi:<?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>
Ümumiyyətlə, bu, bir neçə nəzarətçi yaratmaq və başlanğıcı işə salmaq üçün kifayətdir (bu, qalxmayacaq). Bəs bu konfiqurasiya Baharı necə işlədəcək? Və burada işlər maraqlı olur. Konfiqurasiyamızın Bahar tərəfindən başa düşülməsi üçün bir XmlBeanDefinitionReader
. Bu, xml-ni skan edən (analizləyən) və orada yazdıqlarımız əsasında BeanDefinition
's yaradan daxili Spring komponentidir. BeanDefinition
paxla haqqında məlumat saxlayan obyektdir. Bura daxildir: o (lobya) hansı sinifdən yaradılmalıdır; əhatə dairəsi; tənbəl başlatma quraşdırılıbmı; Bu lobyadan əvvəl xml-də təsvir olunan başqa və digər xüsusiyyətləri işə salmaq lazımdırmı. Bütün qəbul edilənlər identifikator paxlanın adı (sizin tərəfindən təyin edilmiş və ya Bahar tərəfindən təyin edilmiş) və obyektin özü olan BeanDefinition
-ə əlavə olunur . Hər şey yaradıldıqdan sonra səhnədə yeni bir qəhrəman görünür - . Bu obyekt s üzərində təkrarlanır , onların əsasında lobya yaradır və onları IoC konteynerinə qoyur. Burada bir nüans var, əslində, proqram işə salındıqda, IoC konteynerində Singleton əhatə dairəsi (standart olaraq təyin edilmiş) olan lobya olacaq, qalanları isə lazım olduqda yaradılır (prototip, sorğu, sessiya). İndi isə kiçik bir ekskursiya, başqa bir xarakterlə tanış olaq. HashMap
BeanDefinition
BeanDefinition
BeanFactory
HashMap’e
BeanDefinition
BeanPostProcessor ilə tanış olun. (BPP)
Fakt budur ki, lobya tətbiqiniz üçün mütləq biznes məntiqi sinfi deyil. Lobyaya infrastruktur paxlası da deyilir. Qısacası, infrastruktur lobyası biznes məntiqinizi konfiqurasiya edən bir sinifdir (bəli, çoxlu lobya). Aşağıda sizə bu barədə ətraflı məlumat verəcəyəm, lakin BPP-nin tam olaraq nəyi konfiqurasiya etdiyini bir az daha aydınlaşdırmaq üçün bir nümunə verəcəyəm. Hər kəs xülasə ilə tanışdırmı@Autowired
? Beləliklə, AutowiredAnnotationBeanPostProcessor
bütün siniflərinizin bir-birinə daxil olmasını təmin etmək üçün məsuliyyət daşıyırsınız.
BeanFactory-ə qayıdaq
İndi BPP haqqında bildiyimiz üçün aydınlaşdırmaq lazımdır kiHashMap
, 's üzərində təkrarlanan zaman BeanDefinition
bütün'lər əvvəlcə yaradılır və ayrıca yerləşdirilir (IoC konteynerində deyil) BeanPostProcessor
. Bundan sonra, biznes məntiqimizin müntəzəm lobyaları yaradılır, IoC konteynerinə qoyulur və onların konfiqurasiyası ayrıca təxirə salınmış BPP-lərdən istifadə etməyə başlayır. Və bu belə olur, hər BPP-nin 2 üsulu var:
postProcessorBeforeInitialization(Object bean, String beanName);
postProcessorAfterInitialization(Object bean, String beanName);
Zibil qutularımızı iki dəfə təkrarlayır. Birinci dəfə metod çağırılır postProcessorBeforeInitialization
, ikinci dəfə isə metod çağırılır postProcessorAfterInitialization
. Şübhəsiz ki, sual yarandı ki, niyə iki üsula ehtiyac var, icazə verin izah edim. Fakt budur ki, bəzi annotasiyaları (məsələn @Transactional
, məsələn) emal etmək üçün lobyamız proxy sinfi ilə əvəz olunur. Bunun niyə edildiyini anlamaq üçün bunun necə işlədiyini bilməlisiniz @Transactional
və bu necə işləyir. Tez bu annotasiya ilə qeyd olunan metoda daha bir neçə sətir kod əlavə etməlisiniz. Bunu necə etmək olar? Doğrudur, bir proxy sinfi yaratmaqla, içərisində lazımi kod tələb olunan metoda əlavə olunacaq. İndi bu vəziyyəti təsəvvür edin, bir sinifimiz var:
class A {
@Autowired
private SomeClass someClass;
@Transactional
public void method() {
// модификатор доступа обязательно public
}
}
Bu sinifdə 2 annotasiya @Autowired
və @Transactional
. Hər iki annotasiya müxtəlif BPP-lər tərəfindən işlənir. Əvvəlcə işləyirsə AutowiredBPP
, onda hər şey yaxşı olacaq, amma yoxsa, bu problemlə qarşılaşacağıq. Məsələ burasındadır ki, proksi sinfi yaradılanda bütün meta məlumat itirilir. @Autowired
Başqa sözlə, proxy sinfində annotasiya haqqında heç bir məlumat olmayacaq və buna görə də AutowiredBPP
işləməyəcək, yəni sahəmiz çox güman ki, NPE-ə səbəb olacaq someClass
dəyərə sahib olacaq . Metod çağırışları arasında, əgər varsa, -metodunun çağırıldığını da bilmək null
lazımdır . Bu, əsasən ikinci konstruktordur, lakin fərq ondadır ki, hazırda bizim bütün asılılıqlarımız artıq sinifə daxil edilib və biz onlara -metoddan daxil ola bilərik . Beləliklə, bir daha kontekst başlatma alqoritmi: postProcessorBeforeInitialization
postProcessorAfterInitialization
init
init
XmlBeanDefinitionReader
xml konfiqurasiya faylımızı skan edir.- 's yaradır
BeanDefinition
və onları qoyurHashMap
. - Gəlir
BeanFactory
və bundanHashMap
ayrı-ayrılıqda bütün 'ları toplayırBeanPostProcessor
. - 's lobya yaradır
BeanDefinition
və onları IoC konteynerinə yerləşdirir. - Burada BPP-lər gəlib bu paxlaları 2 üsuldan istifadə edərək konfiqurasiya edirlər.
- Hazır.
GO TO FULL VERSION