Eine kurze Diskussion der Kernideen des Frühlings

Ich erinnere mich noch daran, dass ich, als ich Spring zum ersten Mal lernte, immer noch eine XML-Datei nach der anderen schreiben musste. Ich wusste damals nicht warum. Ich folgte den Schritten im Internet, um sie einzeln zu konfigurieren. Wenn ich eine nicht übereinstimmte, Ich war lange verwirrt und habe mir den Fehler angesehen. Ich habe nur zufällige Änderungen vorgenommen, bis es am Ende laufen konnte. Ich seufze insgeheim, tmd, das Ding ist wirklich kompliziert.

Später, als ich SpringBoot verwendete, schien es, dass viele XML-Konfigurationen fehlten, und ich war insgeheim froh. Zuerst lief es normal gemäß der Standardkonfiguration. Später, als ich Änderungen vornehmen musste, wusste ich nicht, wo ich anfangen sollte.

Meistens ist die Verwendung etwas verwirrend, aber wenn Sie auf seltsame Probleme stoßen, müssen Sie Lao Li um Hilfe bitten.

Später entdeckte ich, dass es Spring Cloud gibt und die Ära der Microservices naht. Ich glaube, ich kann Spring Family Bucket nicht mehr so ​​verwenden.

Ich habe mich gleichzeitig mit verschiedenen detaillierten SpringCloud-Quellcodes befasst, in der Hoffnung, die wahre Bedeutung des Frameworks zu verstehen. Am Ende hatte ich keinen Erfolg und war niedergeschlagen. Ich beklagte erneut, dass tmd wirklich kompliziert ist.

Während dieser Zeit wurde mir klar, dass ich mit dem Spring-Grundgerüst nicht vertraut bin, was dazu führt, dass ich viele Kapselungspunkte nicht verstehe.

Schließlich basiert SpringCloud auf SpringBoot und SpringBoot basiert auf Spring.

Also ging ich zurück, um den Frühling erneut zu lernen. Anstatt mich in verschiedene Details zu vertiefen, änderte ich meine Strategie. Ich betrachte den Frühling zunächst aus einer hochdimensionalen Perspektive, verstehe die Kernprinzipien und erobere dann verschiedene Zweige.

Also wurde ich stärker.

Tatsächlich ist es dasselbe, wenn man etwas lernt: Man muss sich zuerst einen Überblick verschaffen, dann tief in die Materie einsteigen und es dann im Nachhinein zusammenfassen.

In diesem Artikel möchte ich mein eigenes Verständnis nutzen, um den Kern (die Idee) von Spring zu erläutern. Aufgrund meiner persönlichen Ausdrucksfähigkeit kann es zu Fehlern oder Ausführlichkeiten kommen. Bitte haben Sie Geduld. Wenn es Fehler gibt, weisen Sie sie bitte darauf hin .

Legen Sie IOC und DI beiseite und denken Sie darüber nach, warum der Frühling nötig ist

Wenn wir zum ersten Mal Java lernen, schreiben wir natürlich Code wie diesen:

public class ServiceA { 
  private ServiceB serviceB = new ServiceB();
}
复制代码

Wir kapseln etwas Logik in ServiceB , und wenn ServiceAdiese Logik verwendet werden muss, befindet sie sich ServiceAdarin .new ServiceB

Wenn die gekapselte Logik sehr allgemein ist, müssen andere Dinge darauf angewiesen ServiceB sein , was bedeutet, dass überall im Code neue benötigt werden . Wenn sich also die Konstruktionsmethode ändert, müssen Sie sie an allen Stellen verwenden . Gehen Sie dorthin und nehmen Sie Codeänderungen vor.ServiceCServiceFServiceB

Wenn Sie beispielsweise ServiceB eine Instanz erstellen müssen ServiceC , sollte der Code wie folgt geändert werden:

public class ServiceA { 
  private ServiceB serviceB = new ServiceB(new ServiceC());
}
复制代码

Es gibt tatsächlich dieses Problem.

Wenn wir jedoch die allgemeine serviceLogik kapseln, müssen wir nicht jedes Mal neue Instanzen erstellen. Mit anderen Worten: Eine einzelne Instanz reicht aus. Unser System benötigt nur neweine ServiceB für jedes Objekt, um dieses Problem zu lösen.

public class ServiceA { 
  private ServiceB serviceB = ServiceB.getInstance();
}

public class ServiceB {
    private static ServiceB instance = new ServiceB(new ServiceC());
    private ServiceB(){}
    public static ServiceB getInstance(){
        return instance;
    }
}
复制代码

Es sieht so aus, als wäre das Problem gelöst, aber das ist nicht der Fall.

Wenn das Projekt relativ klein ist, beispielsweise ein großer Universitätsauftrag, stellt der obige Vorgang eigentlich kein großes Problem dar, wird jedoch kompliziert, wenn es um Anwendungen auf Unternehmensebene geht.

Da viel Logik involviert ist, gibt es viele gekapselte Serviceklassen und die Abhängigkeiten zwischen ihnen sind ebenfalls kompliziert. Im Code kann es ServiceB1, ServiceB2... geben ServiceB100, und es kann Abhängigkeiten untereinander geben.

Abgesehen von den Abhängigkeiten nehmen Sie einfach ServiceBeinen einfachen Singleton-Logikcode. Wiederholte Logik muss möglicherweise in Hunderten oder Tausenden von Kopien geschrieben werden .

Und es ist nicht einfach zu erweitern . In der Vergangenheit waren für den Betrieb von ServiceB möglicherweise keine Transaktionen erforderlich, spätere Transaktionen sind jedoch erforderlich. Daher ServiceBmuss der Code geändert werden, um transaktionsbezogene Logik einzubetten.

Nicht lange ServiceCdanach waren auch Transaktionen erforderlich, und der exakt gleiche Code über Transaktionen musste auf ServiceC sowie D, E, F ... wiederholt werden.

Die Anforderungen für mehrere ServiceTransaktionen sind unterschiedlich, und es gibt auch das Problem verschachtelter Transaktionen, kurz gesagt, es ist etwas mühsam.

Ich war eine Weile damit beschäftigt, die Transaktionsanforderungen zu erfüllen, und ging online. Ich dachte, ich wäre endlich vom Albtraum des wiederholten Codes befreit und könnte mich gut ausruhen.

Dann kam eine weitere Anforderung: Da wir häufig Online-Probleme beheben müssen, müssen wir die Eingabeparameter der Schnittstelle protokollieren, um die Fehlerbehebung zu erleichtern, und wir müssen drastische Änderungen auf einmal vornehmen.

Es ist normal, bei Bedarf Änderungen vorzunehmen, aber jede Änderung erfordert eine Menge sich wiederholender Arbeit, die ermüdend ist, keinen technischen Inhalt hat und leicht zu übersehen ist . Das ist nicht elegant genug.

Also begannen einige Leute darüber nachzudenken, wie sie aus diesem Kopplungssumpf herauskommen könnten.

Erhebung und Abisolieren

Die meisten menschlichen Erfindungen sind auf Faulheit zurückzuführen. Menschen hassen sich wiederholende Arbeiten, und Computer lieben und eignen sich am besten für sich wiederholende Arbeiten .

Da es in der vorherigen Entwicklung viele sich wiederholende Arbeiten geben wird, warum nicht ein „Ding“ erstellen, das uns dabei hilft, solche sich wiederholenden Dinge zu tun ?

Genau wie in der Vergangenheit haben die Menschen Produkte Schritt für Schritt von Hand zusammengebaut und hergestellt, und die gleichen Schritte können jeden Tag Zehntausende Male wiederholt werden. Später entwickelten die Menschen vollautomatische Maschinen, die uns bei der Herstellung von Produkten helfen, die Hände der Menschen frei machen und sie verbessern Produktionseffizienz.

Nachdem wir diese Idee verbessert hatten, änderte sich die Codierungslogik. Wir Programmierer dachten und schrieben , dass ServiceA von einem bestimmten ServiceB abhängt, und tippten Buchstabe für Buchstabe den Code ein, wie ServiceB instanziiert wird. Wir kümmern uns nur um ServiceA abhängig von ServiceB, aber wir Es ist egal, wie ServiceB generiert wird, dieses „Ding“ hilft uns, es zu generieren und ServiceA und ServiceB zu verknüpfen.

public class ServiceA { 
  @注入
  private ServiceB serviceB;
}
复制代码

Es klingt vielleicht etwas unwirklich, ist es aber nicht.

Reden wir noch einmal über Maschinen. Wir erstellen diese Maschine. Wenn wir Produkt A herstellen wollen, müssen wir nur Zeichnung A zeichnen und Zeichnung A in diese Maschine stecken. Die Maschine erkennt Zeichnung A und produziert, was wir wollen, entsprechend dem Design von unsere Zeichnung A. Produkt A.

Spring ist diese Maschine , und die Zeichnungen basieren auf den von Spring verwalteten Objektcodes und diesen XML-Dateien (oder annotierten @ConfigurationKlassen).

Dann ändert sich die Logik. Programmierer wissen ServiceA, von welcher sie abhängig sind ServiceB, aber wir müssen nicht explizit die vollständige Logik zum Erstellen von ServiceB in den Code schreiben. Wir müssen nur die Konfigurationsdatei schreiben, und Spring hilft uns bei der spezifischen Erstellung und Zuordnung.

Nehmen wir weiterhin das Beispiel der Maschine: Wir erhalten die Zeichnungen (Konfiguration) und die Maschine hilft uns bei der Herstellung des Produkts. Wir müssen uns keine Gedanken darüber machen, wie wir es herstellen, aber wir wissen es, denn unsere Zeichnungen zeigen , ServiceAwas wird für die Fertigung benötigt ServiceB, und welche Art von Logik ServiceBwird benötigt ?ServiceC

Ich suche ein Zeichenbeispiel für die Konfiguration der Datenbank im Frühjahr:

Sie können sehen, dass unsere Zeichnungen sehr klar geschrieben sind. Beim Erstellen müssen mybatisSie MapperScannerConfigurerihm die Werte von zwei Attributen mitteilen. Das erste ist beispielsweise sqlSessionFactoryBeanNameund der Wert ist sqlSessionFactory.

Und essqlSessionFactory hängt davon ab dataSourceund dataSourcees muss konfiguriert werden driverClassNameusw.url

Daher wissen wir eigentlich sehr gut, was zum Erstellen eines Produkts (Bean) erforderlich ist, aber der Erstellungsprozess wird von Spring übernommen. Wir müssen es nur klar sagen.

Daher bedeutet dies nicht, dass wir uns bei Spring nicht mehr um ServiceAdie spezifischen Abhängigkeiten ServiceBund ServiceBderen erfolgreiche Erstellung kümmern, sondern dass Spring den Prozess der Zusammenstellung dieser Objekte für uns übernimmt.

Wir müssen immer noch genau wissen, wie das Objekt erstellt wird, da wir die richtige Zeichnung zeichnen müssen, um es Spring mitzuteilen.

Spring ist also tatsächlich eine Maschine, die basierend auf den Zeichnungen, die wir ihr geben, automatisch zugehörige Objekte erstellt, die wir verwenden können. Wir müssen den vollständigen Erstellungscode nicht explizit in den Code schreiben .

Diese von Spring erstellten Objektinstanzen werden Beans genannt.

Wenn wir diese Beans verwenden möchten, können wir sie von Spring erhalten. Spring fügt diese erstellten Singleton- Beans in eine Karte ein und wir können diese Beans nach Namen oder Typ abrufen.

Das ist IOC .

Gerade weil diese Beans von der Spring-Maschine erstellt werden müssen, anstatt sie träge in jeder Ecke des Codes zu erstellen, können wir auf der Grundlage dieser einheitlichen Schnittstelle viele Dinge problemlos erledigen.

Wenn unsere beispielsweise ServiceBmit einer Annotation markiert ist @Transactional, versteht Spring, dass diese Annotation ServiceBeine Transaktion erfordert, sodass er die gewebte Transaktion starten, festschreiben, zurücksetzen und andere Vorgänge ausführen kann.

Alles, was mit @Transactionaleiner Annotation markiert ist, fügt automatisch Transaktionslogik hinzu, wodurch für uns zu viel sich wiederholender Code reduziert wird. Solange wir @Transactionalden Methoden oder Klassen, die Transaktionen erfordern, Annotationen hinzufügen, hilft uns Spring dabei, die Transaktionsfunktion zu ergänzen. Wiederholte Vorgänge werden von Spring ausgeführt ist komplett.

In einem anderen Beispiel müssen wir die Anforderungseingabeparameter auf allen Controllern aufzeichnen. Dies ist ebenfalls sehr einfach. Wir müssen lediglich eine Konfiguration schreiben, um Spring mitzuteilen, dass sich die Eingabeparameter jeder Methode der Klasse unter dem Pfad xxx (Controller-Paketpfad) befinden ) müssen im Protokoll aufgezeichnet werden. , und schreiben Sie auch den Protokolldruck-Logikcode.

Spring hat diesen Befehl erhalten, nachdem er diese Konfiguration analysiert hat. Wenn wir also das nachfolgende Bean erstellen, werden wir sehen, ob das Paket, in dem es sich befindet, mit der obigen Konfiguration übereinstimmt. Wenn dies der Fall ist, fügen wir eine Protokolldrucklogik hinzu und verknüpfen sie mit der ursprünglichen Logik. .

Auf diese Weise werden die wiederholten Protokolldruckaktionsvorgänge in einer Konfiguration abstrahiert. Nachdem die Spring-Maschine die Konfiguration erkannt hat, führt sie unsere Befehle aus, um diese wiederholten Aktionen abzuschließen.

Dies wird als AOP bezeichnet .

An diesem Punkt glaube ich, dass Sie ein gewisses Verständnis für den Ursprung und die Kernkonzepte von Spring haben. Basierend auf den oben genannten Funktionen können viele Dinge getan werden.

Aufgrund der einheitlichen Abschlussverarbeitung von Spring können wir viele Erweiterungspunkte flexibel zu unterschiedlichen Zeiten bereitstellen, z. B. beim Parsen von Konfigurationsdateien, vor und nach der Bean-Initialisierung, vor und nach der Bean-Instanziierung usw.

Basierend auf diesen Erweiterungspunkten können viele Funktionen implementiert werden, wie z. B. das selektive Laden von Beans, das Ersetzen von Platzhaltern und die Generierung von Proxy-Klassen (Transaktionen usw.).

Wenn Sie beispielsweise SpringBoot Rediseinen Client auswählen, werden standardmäßig zwei Client-Konfigurationen von lettuceund importiert.jedis

Basierend auf der Konfigurationsreihenfolge wird zuerst Salat und dann Jedis importiert.

Wenn der Scan Salat findet, verwenden Sie die RedisConnectionFactory von Salat. Beim späteren Laden von Jedis wird darauf geachtet, @ConditionalOnMissingBean(RedisConnectionFactory.class)dass Jedis nicht injiziert wird, andernfalls wird es injiziert.

ps:@ConditionalOnMissingBean(xx.class) Wenn derzeit keine xx.class vorhanden ist, kann die durch diese Annotation geänderte Bean generiert werden.

Die obige Funktion wird basierend auf den von Spring bereitgestellten Erweiterungspunkten implementiert.

Es ist für uns sehr flexibel, den erforderlichen Redis-Client zu ersetzen, ohne den verwendeten Code zu ändern. Wir müssen nur die Abhängigkeit ändern. Um beispielsweise vom Standard-Salat zu Jedis zu wechseln, müssen wir nur die Maven-Konfiguration ändern und den Salat entfernen Abhängigkeit und Einführung von jedis:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <exclusions>
        <exclusion>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
复制代码

Was ich wirklich sagen möchte, ist, dass die von Spring Family Bucket bereitgestellten Erweiterungen und Kapselungen unsere vielen Anforderungen flexibel erfüllen können und diese Flexibilität auf den Kern-IOC und AOP von Spring basiert .

zu guter Letzt

Abschließend verwende ich einen Absatz, um das Prinzip des Frühlings kurz zu beschreiben:

Spring analysiert den Inhalt entsprechend der von uns bereitgestellten Konfigurationsklasse und XML-Konfigurationsdatei und erhält die Informationen zu den Beans, die verwaltet werden müssen, sowie die Beziehungen zwischen ihnen. Und Spring stellt viele Erweiterungspunkte zur Verfügung, die wir anpassen können, z. B. nur wir Dies muss BeanFactoryPostProcessorimplementiert werden BeanPostProcessor. Die Schnittstelle kann einige benutzerdefinierte Vorgänge ausführen.

Nachdem Spring die Bean-Informationen erhalten hat, erstellt es eine Bean-Instanz basierend auf Reflektion und stellt die Abhängigkeiten zwischen den Beans zusammen. Es wird native oder von uns definierte Abhängigkeiten einstreuen, um das Bean zu transformieren, einige Attribute zu ersetzen oder die ursprüngliche Bean-Logik zu ersetzen PostProcessor.

Nachdem schließlich alle Beans mit Konfigurationsanforderungen erstellt wurden, werden die Singleton-Beans in der Karte gespeichert und die BeanFactory wird uns bereitgestellt, um die Beans abzurufen und zu verwenden.

Dadurch müssen wir während des Codierungsprozesses nicht mehr darauf achten, wie das Bean erstellt wird, und ersparen uns außerdem viele sich wiederholende Codierungsvorgänge. Diese werden alle von der von uns erstellten Maschine – Spring – für uns erledigt.

Das ist wahrscheinlich alles, was ich zu sagen habe. Ich habe es mehrmals gelesen und weiß nicht, ob ich klar erklärt habe, was ich ausdrücken möchte. Tatsächlich habe ich ursprünglich über den Kern auf der Ebene des Quellcodes gesprochen, aber ich bin es Ich habe Angst, dass es schwieriger wird, es klar zu erklären.

Schließlich habe ich die Interviewantworten zu den IOC- und DI-Konzepten von Spring bereits geschrieben. Sie können einen Blick auf die URL werfen: https://yessimida.gitee.io/interview-of-legends/#/./docs/c-1Spring%E7%B2%BE%E9%80%89%E9%9D%A2%E8%AF%95%E9%A2%98%E8%A7%A3.

Supongo que te gusta

Origin blog.csdn.net/2301_76607156/article/details/130525822
Recomendado
Clasificación