JavaRush /Java-Blog /Random-DE /Frühlingsrahmen. Einführung
Marchello
Level 20
Санкт-Петербург

Frühlingsrahmen. Einführung

Veröffentlicht in der Gruppe Random-DE
Hallo! Während die JavaRush-Administration an neuen Ebenen arbeitet, möchte ich eine Reihe von Schulungsartikeln zum Spring Framework starten. Ja, ich weiß, dass es im Internet bereits viel Material zu diesem Thema gibt, aber wie die Praxis zeigt, sind sie alle auf dem Niveau von Hello World. Ich möchte nicht darüber sprechen, wie man Anmerkungen richtig platziert, sondern darüber, wie das alles „unter der Haube“ funktioniert. Der Artikel richtet sich an diejenigen, die bereits auf die eine oder andere Weise mit diesem Framework gearbeitet haben und mit den Grundkonzepten vertraut sind. Frühlingsrahmen.  Einleitung - 1

Den Kontext initialisieren.

Beginnen wir also mit den Grundlagen. Einer der wichtigsten Punkte ist meiner Meinung nach, zu verstehen, wie der Kontext aufgebaut und Beans initialisiert werden. Wie Sie wissen, muss Spring konfiguriert werden, bevor es funktioniert. In vorsintflutlichen Zeiten geschah dies mithilfe von XML-Dateien (bei einigen Projekten, vor allem alten, wird dies bis heute getan). Hier ist ein kleines Beispiel einer solchen Konfigurationsdatei:
<?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>
Im Großen und Ganzen reicht dies aus, um ein paar Controller zu erstellen und ein Startup zu starten (das nicht startet). Aber wie wird diese Konfiguration dafür sorgen, dass Spring funktioniert? Und hier wird es interessant. Damit unsere Konfiguration von Spring verstanden wird, gibt es eine XmlBeanDefinitionReader. BeanDefinitionDies ist eine interne Spring-Komponente, die XML scannt (analysiert) und basierend auf dem , was wir dort geschrieben haben, erstellt. BeanDefinitionist ein Objekt, das Informationen über die Bean speichert. Dazu gehört: aus welcher Klasse es (die Bean) erstellt werden soll; Umfang; ob die verzögerte Initialisierung installiert ist; Ist es notwendig, vor dieser Bean weitere und andere Eigenschaften zu initialisieren, die in XML beschrieben sind? Alle empfangenen BeanDefinitionwerden zu hinzugefügt HashMap, wobei der Bezeichner der Name der Bean (von Ihnen festgelegt oder von Spring zugewiesen) und BeanDefinitiondas Objekt selbst ist. Nachdem alles BeanDefinitionerschaffen ist, erscheint ein neuer Held auf der Bühne – BeanFactory. Dieses Objekt durchläuft HashMap’es BeanDefinition, erstellt darauf basierende Beans und legt sie in einem IoC-Container ab. Hier gibt es eine Nuance: Wenn die Anwendung gestartet wird, enthält der IoC-Container Beans mit einem Singleton-Bereich (standardmäßig festgelegt), während der Rest bei Bedarf erstellt wird (Prototyp, Anfrage, Sitzung). Und jetzt ein kleiner Exkurs: Lernen wir einen anderen Charakter kennen.

Lernen Sie BeanPostProcessor kennen. (BPP)

Bean-PostprozessorTatsache ist, dass eine Bean nicht unbedingt eine Klasse von Geschäftslogik für Ihre Anwendung ist. Eine Bean wird auch Infrastruktur-Bean genannt. Kurz gesagt ist eine Infrastruktur-Bean eine Klasse, die Ihre Geschäftslogik-Beans konfiguriert (ja, zu viele Beans). Ich werde Ihnen weiter unten mehr darüber erzählen, aber um etwas klarer zu machen, was genau BPP konfiguriert, werde ich ein Beispiel geben. Kennt jeder die Zusammenfassung @Autowired? Sie sind also AutowiredAnnotationBeanPostProcessordafür verantwortlich, sicherzustellen, dass alle Ihre Klassen ineinander eingebettet sind. uknowimean

Kehren wir zurück zur BeanFactory

Da Sie sich jetzt mit BPP auskennen, müssen Sie klarstellen, dass bei der Iteration über HashMap„s“ BeanDefinitionalle „s“ zunächst separat erstellt und platziert werden (nicht im IoC-Container) BeanPostProcessor. Danach werden reguläre Beans unserer Geschäftslogik erstellt, in einen IoC-Container gestellt und ihre Konfiguration beginnt mithilfe separat verzögerter BPPs. Und so passiert es, jedes BPP verfügt über 2 Methoden:
postProcessorBeforeInitialization(Object bean, String beanName);
postProcessorAfterInitialization(Object bean, String beanName);
Durchläuft unsere Behälter zweimal. Beim ersten Mal wird die Methode aufgerufen postProcessorBeforeInitializationund beim zweiten Mal wird die Methode aufgerufen postProcessorAfterInitialization. Sicherlich hat sich die Frage gestellt, warum zwei Methoden benötigt werden, lassen Sie mich das erklären. Tatsache ist, dass zur Verarbeitung einiger Annotationen (z. @TransactionalB.) unsere Bean durch eine Proxy-Klasse ersetzt wird. Um zu verstehen, warum dies geschieht, müssen Sie wissen, wie es funktioniert @Transactional, und zwar so. Sie müssen der mit dieser Annotation markierten Methode im laufenden Betrieb ein paar weitere Codezeilen hinzufügen. Wie kann man das machen? Richtig, indem Sie eine Proxy-Klasse erstellen, in der der erforderliche Code zur erforderlichen Methode hinzugefügt wird. Stellen Sie sich nun diese Situation vor, wir haben eine Klasse:
class A {
    @Autowired
    private SomeClass someClass;

    @Transactional
    public void method() {
        // модификатор доступа обязательно public
    }
}
Diese Klasse hat 2 Anmerkungen @Autowiredund @Transactional. Beide Annotationen werden von unterschiedlichen BPPs verarbeitet. Wenn es zuerst funktioniert AutowiredBPP, ist alles in Ordnung, aber wenn nicht, werden wir auf dieses Problem stoßen. Tatsache ist, dass beim Erstellen der Proxy-Klasse alle Metainformationen verloren gehen. Mit anderen Worten: Es gibt keine Informationen über die Annotation @Autowiredin der Proxy-Klasse und daher AutowiredBPPwird sie nicht funktionieren, was bedeutet, dass unser Feld someClassden Wert hat null, was höchstwahrscheinlich zu einem NPE führen wird. Es ist auch wichtig zu wissen, dass zwischen Methodenaufrufen die -Methode aufgerufen postProcessorBeforeInitializationwird , sofern vorhanden. Dies ist im Grunde der zweite Konstruktor, aber der Unterschied besteht darin, dass zu diesem Zeitpunkt alle unsere Abhängigkeiten bereits in die Klasse eingebettet sind und wir über die -Methode auf sie zugreifen können. Also noch einmal der Kontextinitialisierungsalgorithmus: postProcessorAfterInitializationinitinit
  1. XmlBeanDefinitionReaderscannt unsere XML-Konfigurationsdatei.
  2. Erstellt BeanDefinition's und fügt sie ein HashMap.
  3. Kommt und addiert BeanFactorydaraus separat alle 's.HashMapBeanPostProcessor
  4. Erstellt BeanDefinitionBeans aus 's und platziert sie in einem IoC-Container.
  5. Hier kommen BPPs und konfigurieren diese Beans mit zwei Methoden.
  6. Bereit.
Das ist eigentlich alles. Schreiben Sie, ob Ihnen der Artikel gefallen hat und ob es sich lohnt, weiterhin solche Tutorials zu schreiben.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION