In diesem Artikel möchte ich ein Problem mitteilen, auf das ich kürzlich gestoßen bin und das meiner Meinung nach für Sie von Interesse sein könnte.
Was ist das Problem?
Der Quellcode für die Test- und Produktionsumgebung ist derselbe, und sowohl die lokale als auch die Testumgebung laufen gut. Nur die Produktionsumgebung, die mit einem NPE einer Serviceklasse ausgeführt wird, konnte nicht geladen werden, was die neuen Anforderungen betraf. Diese Klasse erbt die Schnittstelle vom Customize-Paket (einem selbst entwickelten Toolkit).
Die Projektstruktur
Das Design von Customize basiert auf Spring, um APIs und Dienste zu verwalten. Beim automatischen Spring-Scan werden die gemeinsamen Klassen ApiEnhancer und ServiceEnhancer beim Initialisieren der Klassen geladen und Instanzen über ApplicationContext abgerufen. Beim Debuggen wurde festgestellt, dass der ApplicationContext beim Laden null ist und noch nicht initialisiert wurde. Es wird in der setApplicationContext-Methode durch Implementierung von ApplicationContextAware initialisiert, daher wird spekuliert, dass die setApplicationContext-Methode nicht ausgeführt wurde.
Während des Ladevorgangs der ApplicationContextProvider-Klasse werden die statischen Methoden während der Initialisierungsphase in den Methodenbereich geladen. Wenn Sie jedoch ApplicationContext zum Abrufen von Bean-Instanzen verwenden, werden die statischen Methoden direkt über den Klassennamen aufgerufen. Solange die API erstellt wird, bevor dem ApplicationContextProvider Speicher im Heap zugewiesen und instanziiert wurde, wird die setApplicationContext-Methode nicht zur Initialisierung aufgerufen.
Der applicationContextProvider verwendet die Annotation @Component und die API verwendet die Annotation @RestController, und die beiden Klassen befinden sich im selben Pfad. Wenn Spring sie jedoch scannt und lädt, gibt es keine bestimmte Reihenfolge, was bedeutet, dass jede der beiden Klassen vor der anderen erstellt werden kann. In der Produktionsumgebung wird die API vor dem applicationContextProvider erstellt. Dies führt dazu, dass der applicationContext NICHT initialisiert wurde.
, wenn die statische Methode direkt über den Klassennamen aufgerufen wird, um Beans abzurufenDie Lösungen
Wenn die setApplicationContext-Methode der Implementierungsklasse der ApplicationContextAware-Schnittstelle nicht ausgeführt wurde, prüfen Sie zunächst, ob die Implementierungsklasse auf Lazy Loading eingestellt ist oder ob das Projekt globales Lazy Loading konfiguriert hat.
In diesem Projekt wurde das Problem durch die Erstellungsreihenfolge der Implementierungsklassen der Schnittstellen ApiEnhancer und ApplicationContextAware verursacht, und die Api-Klasse ist nur eine reguläre RESTful-API, die Geschäftslogik verarbeitet und geladen werden kann, wenn sie von der Front aufgerufen wird. Endseite. Daher wurde das Problem durch die Umstellung auf verzögertes Laden gelöst.
Es ist ratsam, die Abhängigkeitsbeziehung zwischen Klassen hinsichtlich der Ladereihenfolge zu minimieren. Wenn dies unvermeidbar ist, können Lazy Loading oder Anmerkungen wie @DependsOn, @Order, @Priority verwendet werden, um die Ladereihenfolge von Beans zu steuern.
Warum ist die Erstellungsreihenfolge der Produktionsumgebung und der Testumgebung unterschiedlich?
Lassen Sie uns debuggen, um den Scanvorgang von Spring zu überprüfen.
Beginnend mit der Scan-Methode von ClassPathBeanDeterminationScanner.
doScan-Methode
scanCandidateComponents-Methode von ClassPathScanningCandidateComponentProvider
findAllClassPathResources-Methode von PathMatchingResourcePatternResolver
doFindPathMatchingJarResources-Methode
JarFile ist eine Klasse in der Java-Standardbibliothek unter dem Paket java.util.jar, die ZipFile erbt und erweitert. jarFile.entries() gibt einen Iterator namens JarEntryIterator.
zurückJarExitIterator ist eine Implementierung des Iterator Pattern, das die Einträge der übergeordneten Klasse von JarFile iteriert.
Die Einträge-Methode von ZipFile gibt einen Iterator namens ZipExitIterator zurück.
Die nextElement-Methode von ZipExitIterator ruft die nächste Methode auf, die wiederum die getNextEntry-Methode aufruft.
getNextEntry ist eine native Methode.
Die native Methode wird in Nicht-Java-Sprachen implementiert und innerhalb der Java Virtual Machine aufgerufen, um die zugrunde liegende Funktionalität zu implementieren, die je nach Umgebung (Betriebssystem oder JDK-Version) variieren kann. JAR-Pakete selbst haben keine Reihenfolge, daher kann die tatsächliche Durchlaufreihenfolge je nach verschiedenen JAR-Paketierungstools und -umgebungen variieren.
Das obige ist der detaillierte Inhalt vonDas Ausführungsproblem der setApplicationContext-Methode der applicationContextAware-Schnittstelle führte dazu, dass Spring Beans nicht abgerufen werden konnten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!