Spring Boot Uygulamasını Programlı Olarak Başlatma

Yayınlanan: 2022-03-11

Bu makale, başka bir Java programından Spring Boot uygulamasının nasıl başlatılacağını gösterecektir. Bir Spring Boot uygulaması tipik olarak tek bir yürütülebilir JAR arşivinde yerleşiktir. İç içe JAR'lar olarak paketlenmiş tüm bağımlılıkları içerir.

Benzer şekilde, bir Spring Boot projesi genellikle tüm kirli işleri yapan sağlanan bir maven eklentisi tarafından yürütülebilir bir JAR dosyası olarak oluşturulur. Sonuç, başkalarıyla paylaşılması, bir sunucuda dağıtılması vb. kolay olan kullanışlı, tek bir JAR dosyasıdır.

Spring Boot uygulamasını başlatmak, java -jar mySpringProg.jar yazmak kadar kolaydır ve uygulama konsolda güzel biçimlendirilmiş bazı bilgi mesajlarını yazdıracaktır.

Peki ya bir Spring Boot geliştiricisi, insan müdahalesi olmadan başka bir Java programından bir uygulama çalıştırmak isterse?

Yuvalanmış JAR'lar Nasıl Çalışır?

Tüm bağımlılıkları olan bir Java programını çalıştırılabilir tek bir JAR dosyasında paketlemek için, JAR dosyaları olan bağımlılıkların da sağlanması ve bir şekilde son çalıştırılabilir JAR dosyası içinde saklanması gerekir.

“Gölgeleme” bir seçenektir. Gölgelendirme bağımlılıkları, bir uygulamanın (projenin) kendi koduyla birlikte paketlenmiş bir kopya oluşturmak için bağımlılıkları dahil etme ve yeniden adlandırma, sınıfları yeniden yerleştirme ve etkilenen bayt kodunu ve kaynakları yeniden yazma işlemidir.

Gölgeleme, kullanıcıların tüm sınıfları ve kaynakları bağımlılıklardan açmasına ve bunları çalıştırılabilir bir JAR dosyasına geri paketlemesine olanak tanır. Bu basit senaryolar için işe yarayabilir, ancak iki bağımlılık aynı kaynak dosyasını veya tam olarak aynı ada ve yola sahip sınıfı içeriyorsa, bunlar örtüşür ve program çalışmayabilir.

Spring Boot, farklı bir yaklaşım benimser ve bağımlılık JAR'larını çalıştırılabilir JAR'ın içinde iç içe JAR'lar olarak paketler.

 example.jar | +-META-INF | +-MANIFEST.MF +-org | +-springframework | +-boot | +-loader | +-<spring boot loader classes> +-BOOT-INF +-classes | +-mycompany | +-project | +-YourClasses.class +-lib +-dependency1.jar +-dependency2.jar

Bir JAR arşivi, standart bir Java çalıştırılabilir JAR dosyası olarak düzenlenir. Spring Boot yükleyici sınıfları org/springframework/boot/loader yolunda bulunurken, kullanıcı sınıfları ve bağımlılıkları BOOT-INF/classes ve BOOT-INF/lib .

Not: Spring'de yeniyseniz, En Yaygın İlk 10 Spring Framework Hatası makalemize de göz atmak isteyebilirsiniz .

Tipik bir Spring Boot JAR dosyası üç tür girdi içerir:

  • proje sınıfları
  • İç içe JAR kitaplıkları
  • Spring Boot yükleyici sınıfları

Spring Boot Classloader önce JAR kitaplıklarını sınıf yolunda ayarlayacak ve ardından sınıfları projelendirecek, bu da Spring Boot uygulamasını IDE (Eclipse, IntelliJ) ile konsoldan çalıştırmak arasında küçük bir fark yaratır.

Sınıf geçersiz kılmalar ve sınıf yükleyici hakkında ek bilgi için bu makaleye başvurabilirsiniz.

Spring Boot Uygulamalarını Başlatma

Spring Boot uygulamasını komut satırından veya kabuktan manuel olarak başlatmak, aşağıdakileri yazmak kadar kolaydır:

 java -jar example.jar

Ancak, Spring Boot uygulamasını başka bir Java programından programlı olarak başlatmak daha fazla çaba gerektirir. org/springframework/boot/loader/*.class kodunu yüklemek, JarFileArchive , JarLauncher başlatmak için biraz Java yansıması kullanmak ve launch(String[]) yöntemini çağırmak gereklidir.

Bunun nasıl başarıldığına aşağıdaki bölümlerde daha ayrıntılı bakacağız.

Spring Boot Loader Sınıflarının Yüklenmesi

Daha önce de belirttiğimiz gibi, Spring Boot JAR dosyası, herhangi bir JAR arşivi gibidir. org/springframework/boot/loader/*.class girişlerini yüklemek, Class nesneleri oluşturmak ve bunları daha sonra Spring Boot uygulamalarını başlatmak için kullanmak mümkündür.

 import java.net.URLClassLoader; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; . . . public static void loadJar(final String pathToJar) throws IOException . . . { // Class name to Class object mapping. final Map<String, Class<?>> classMap = new HashMap<>(); final JarFile jarFile = new JarFile(pathToJar); final Enumeration<JarEntry> jarEntryEnum = jarFile.entries(); final URL[] urls = { new URL("jar:file:" + pathToJar + "!/") }; final URLClassLoader urlClassLoader = URLClassLoader.newInstance(urls);

Burada classMap ilgili paket adlarıyla eşlenen Class nesnelerini tutacağını görebiliriz, örneğin, String değeri org.springframework.boot.loader.JarLauncher , JarLauncher.class nesnesine eşlenecek.

 while (jarEntryEnum.hasMoreElements()) { final JarEntry jarEntry = jarEntryEnum.nextElement(); if (jarEntry.getName().startsWith("org/springframework/boot") && jarEntry.getName().endsWith(".class") == true) { int endIndex = jarEntryName.lastIndexOf(".class"); className = jarEntryName.substring(0, endIndex).replace('/', '.'); try { final Class<?> loadedClass = urlClassLoader.loadClass(className); result.put(loadedClass.getName(), loadedClass); } catch (final ClassNotFoundException ex) { } } } jarFile.close();

while döngüsünün sonucu, Spring Boot yükleyici sınıfı nesneleriyle doldurulmuş bir haritadır.

Gerçek Başlatmayı Otomatikleştirme

Yüklemenin dışındayken, otomatik başlatmayı sonlandırabilir ve uygulamamızı gerçekten başlatmak için kullanabiliriz.

Java yansıması, öğreticimiz bağlamında oldukça yararlı olan yüklü sınıflardan nesnelerin oluşturulmasına izin verir.

İlk adım, bir JarFileArchive nesnesi oluşturmaktır.

 // Create JarFileArchive(File) object, needed for JarLauncher. final Class<?> jarFileArchiveClass = result.get("org.springframework.boot.loader.archive.JarFileArchive"); final Constructor<?> jarFileArchiveConstructor = jarFileArchiveClass.getConstructor(File.class); final Object jarFileArchive = jarFileArchiveConstructor.newInstance(new File(pathToJar));

JarFileArchive nesnesinin yapıcısı, argüman olarak bir File(String) nesnesi alır, bu nedenle sağlanması gerekir.

Sonraki adım, yapıcısında Archive gerektiren bir JarLauncher nesnesi oluşturmaktır.

 final Class<?> archiveClass = result.get("org.springframework.boot.loader.archive.Archive"); // Create JarLauncher object using JarLauncher(Archive) constructor. final Constructor<?> jarLauncherConstructor = mainClass.getDeclaredConstructor(archiveClass); jarLauncherConstructor.setAccessible(true); final Object jarLauncher = jarLauncherConstructor.newInstance(jarFileArchive);

Karışıklığı önlemek için, lütfen Archive aslında bir arayüz olduğunu, JarFileArchive ise uygulamalardan biri olduğunu unutmayın.

İşlemdeki son adım, yeni oluşturulan jarLauncher launch(String[]) yöntemini çağırmaktır. Bu nispeten basittir ve sadece birkaç satır kod gerektirir.

 // Invoke JarLauncher#launch(String[]) method. final Class<?> launcherClass = result.get("org.springframework.boot.loader.Launcher"); final Method launchMethod = launcherClass.getDeclaredMethod("launch", String[].class); launchMethod.setAccessible(true); launchMethod.invoke(jarLauncher, new Object[]{new String[0]});

invoke(jarLauncer, new Object[]{new String[0]}) yöntemi sonunda Spring Boot uygulamasını başlatacak. Ana iş parçacığının duracağını ve Spring Boot uygulamasının sona ermesini burada bekleyeceğini unutmayın.

Spring Boot Classloader Hakkında Bir Kelime

Spring Boot JAR dosyamızı incelemek aşağıdaki yapıyı ortaya çıkaracaktır:

 +--- mySpringApp1-0.0.1-SNAPSHOT.jar +--- META-INF +--- BOOT-INF | +--- classes # 1 - project classes | | | | | +--- com.example.mySpringApp1 | | \--- SpringBootLoaderApplication.class | | | +--- lib # 2 - nested jar libraries | +--- javax.annotation-api-1.3.1 | +--- spring-boot-2.0.0.M7.jar | \--- (...) | +--- org.springframework.boot.loader # 3 - Spring Boot loader classes +--- JarLauncher.class +--- LaunchedURLClassLoader.class \--- (...)

Üç tür girişe dikkat edin:

  • proje sınıfları
  • İç içe JAR kitaplıkları
  • Spring Boot yükleyici sınıfları

Hem proje sınıfları ( BOOT-INF/classes ) hem de iç içe JAR'lar ( BOOT-INF/lib ) aynı sınıf yükleyici LaunchedURLClassLoader tarafından işlenir. Bu yükleyici, Spring Boot JAR uygulamasının kökünde bulunur.

LaunchedURLClassLoader , IDE'den farklı olan kitaplık içeriğinden ( BOOT-INF/lib ) sonra sınıf içeriğini ( BOOT-INF/classes ) yükleyecektir. Örneğin, Eclipse önce sınıf içeriğini sınıf yoluna ve ardından kitaplıklara (bağımlılıklar) yerleştirir.

LaunchedURLClassLoader , sınıf yükleme için kullanılacak bir dizi URL ile oluşturulan java.net.URLClassLoader genişletir. URL, JAR arşivi veya sınıflar klasörü gibi bir konuma işaret edebilir. Sınıf yüklemesi yapılırken, URL'ler tarafından belirtilen tüm kaynaklar, URL'lerin sağlandığı sırayla geçilecek ve aranan sınıfı içeren ilk kaynak kullanılacaktır.

Toplama

Klasik bir Java uygulaması, tüm bağımlılıkların sınıf yolu argümanında numaralandırılmasını gerektirir, bu da başlatma prosedürünü biraz hantal ve karmaşık hale getirir.

Buna karşılık, Spring Boot uygulamaları kullanışlıdır ve komut satırından başlatılması kolaydır. Tüm bağımlılıkları yönetirler ve son kullanıcının ayrıntılar hakkında endişelenmesine gerek yoktur.

Ancak, başka bir Java programından bir Spring Boot uygulaması başlatmak, Spring Boot'un yükleyici sınıflarının yüklenmesini, JarFileArchive ve JarLauncher gibi özel nesnelerin oluşturulmasını ve ardından launch yöntemini çağırmak için Java yansımasının kullanılmasını gerektirdiğinden, prosedürü daha karmaşık hale getirir.

Alt satır : Spring Boot, kaputun altındaki birçok küçük görevi halledebilir ve geliştiricilerin zaman kazanmalarına ve yeni özellikler oluşturma, test etme vb. gibi daha faydalı çalışmalara odaklanmalarına olanak tanır.