JavaRush /Java Blog /Random-IT /Quadro primaverile. introduzione
Marchello
Livello 20
Санкт-Петербург

Quadro primaverile. introduzione

Pubblicato nel gruppo Random-IT
Ciao! Mentre l'amministrazione JavaRush sta lavorando a nuovi livelli, voglio iniziare una serie di articoli di formazione sullo Spring Framework. Sì, so che c'è già molto materiale su questo argomento su Internet, ma, come dimostra la pratica, sono tutti a livello Hello World. Non voglio parlare di come posizionare correttamente le annotazioni, ma di come funziona tutto "sotto il cofano". L'articolo è destinato a coloro che hanno già lavorato con questo framework in un modo o nell'altro e hanno familiarità con i concetti di base. Quadro primaverile.  Introduzione - 1

Inizializzazione del contesto.

Quindi cominciamo con le basi. Secondo me uno dei punti più importanti è capire come viene impostato il contesto e come vengono inizializzati i bean. Come sai, prima che Spring inizi a funzionare, deve essere configurato. In epoca antidiluviana, ciò veniva fatto utilizzando file xml (su alcuni progetti, principalmente quelli vecchi, continuano a farlo fino ad oggi). Ecco un piccolo esempio di tale file di configurazione:
<?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>
In generale, questo è sufficiente per creare un paio di controller e avviare una startup (che non decollerà). Ma come farà questa configurazione a far funzionare Spring? Ed è qui che le cose si fanno interessanti. Affinché la nostra configurazione possa essere compresa entro Spring, esiste un file XmlBeanDefinitionReader. BeanDefinitionQuesto è un componente Spring interno che scansiona (analizza) xml e crea in base a ciò che abbiamo scritto lì . BeanDefinitionè un oggetto che memorizza informazioni sul bean. Ciò include: da quale classe deve essere creato (il bean); scopo; se è installata l'inizializzazione lenta; È necessario inizializzare prima di questo bean un'altra e altre proprietà descritte in xml. Tutti BeanDefinitioni messaggi ricevuti vengono aggiunti a HashMap, in cui l'identificatore è il nome del bean (impostato da te o assegnato da Spring) e BeanDefinitionl'oggetto stesso. Dopo che tutto BeanDefinitionè stato creato, sul palco appare un nuovo eroe: BeanFactory. Questo oggetto esegue un'iterazione su HashMap’es BeanDefinition, crea bean basati su di essi e li inserisce in un contenitore IoC. C'è una sfumatura qui, infatti, all'avvio dell'applicazione, il contenitore IoC conterrà bean che hanno un ambito Singleton (impostato per impostazione predefinita), mentre il resto viene creato quando necessario (prototipo, richiesta, sessione). E ora una piccola digressione, facciamo conoscenza con un altro personaggio.

Scopri BeanPostProcessor. (BPP)

post processore di fagioliIl fatto è che un bean non è necessariamente una classe di logica aziendale per la tua applicazione. Un bean è anche chiamato bean di infrastruttura. In breve, un bean dell'infrastruttura è una classe che configura i bean della logica aziendale (sì, troppi bean). Di seguito ti dirò di più, ma per rendere un po' più chiaro cosa configura esattamente BPP, farò un esempio. Tutti conoscono il riassunto @Autowired? Quindi, AutowiredAnnotationBeanPostProcessorsei responsabile di garantire che tutte le tue classi siano integrate l'una nell'altra. non lo so

Torniamo a BeanFactory

Conoscendo ora BPP, è necessario chiarire che quando si esegue l'iterazione su HashMap, BeanDefinitiontutti i ' vengono prima creati e posizionati separatamente (non nel contenitore IoC) BeanPostProcessor. Successivamente, vengono creati i bean regolari della nostra logica di business, inseriti in un contenitore IoC e la loro configurazione inizia utilizzando BPP differiti separatamente. Ed è così che succede, ogni BPP ha 2 metodi:
postProcessorBeforeInitialization(Object bean, String beanName);
postProcessorAfterInitialization(Object bean, String beanName);
Scorre i nostri contenitori due volte. La prima volta che viene chiamato il metodo postProcessorBeforeInitializatione la seconda volta che viene chiamato il metodo postProcessorAfterInitialization. Sicuramente è sorta la domanda sul perché siano necessari due metodi, lasciatemi spiegare. Il fatto è che per elaborare alcune annotazioni (come @Transactionalad esempio ), il nostro bean viene sostituito da una classe proxy. Per capire perché viene fatto questo, bisogna sapere come funziona @Transactional, ed è così che funziona. È necessario aggiungere al volo un altro paio di righe di codice al metodo contrassegnato con questa annotazione. Come farlo? Esatto, creando una classe proxy, all'interno della quale verrà aggiunto il codice necessario al metodo richiesto. Ora immagina questa situazione, abbiamo una classe:
class A {
    @Autowired
    private SomeClass someClass;

    @Transactional
    public void method() {
        // модификатор доступа обязательно public
    }
}
Questa classe ha 2 annotazioni @Autowirede @Transactional. Entrambe le annotazioni vengono elaborate da diversi BPP. Se funziona prima AutowiredBPP, andrà tutto bene, altrimenti incontreremo questo problema. Il fatto è che quando viene creata la classe proxy, tutte le metainformazioni vanno perse. In altre parole, non ci saranno informazioni sull'annotazione @Autowirednella classe proxy, e quindi AutowiredBPPnon funzionerà, il che significa che il nostro campo someClassavrà il valore null, che molto probabilmente porterà a un NPE. Vale anche la pena sapere che tra le chiamate al metodo, postProcessorBeforeInitializationviene postProcessorAfterInitializationchiamato il metodo init, se ce n'è uno. Questo è fondamentalmente il secondo costruttore, ma la differenza è che in questo momento tutte le nostre dipendenze sono già integrate nella classe e possiamo accedervi dal initmetodo -. Quindi, ancora una volta l'algoritmo di inizializzazione del contesto:
  1. XmlBeanDefinitionReaderesegue la scansione del nostro file di configurazione xml.
  2. Crea BeanDefinitione li inserisce HashMap.
  3. Viene BeanFactorye da questo HashMapsomma separatamente tutti i BeanPostProcessor'.
  4. Crea BeanDefinitionbean da e li inserisce in un contenitore IoC.
  5. Qui arrivano i BPP e configurano questi bean utilizzando 2 metodi.
  6. Pronto.
In realtà è tutto, scrivi se l'articolo ti è piaciuto e se vale la pena continuare a scrivere tutorial del genere.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION