CommandLineRunner & ApplicationRunner in Spring
توضیحات جلسه
جزوه و مستندات
مفاهیم کلیدی
- CommandLineRunner
اینترفیس تابعی (Functional Interface) در اسپرینگ بوت که متد run(String... args) را تعریف میکند؛ بینهایی که این اینترفیس را پیادهسازی کنند، بلافاصله پس از بارگذاری کامل کانتکست و سیمکشی تمام بینها اجرا میشوند و آرگومانهای خط فرمان را به صورت آرایه خام دریافت میکنند.
- ApplicationRunner
اینترفیس تابعی مشابه CommandLineRunner در اسپرینگ بوت با متد run(ApplicationArguments args)؛ این اینترفیس آرگومانهای خط فرمان را به صورت شیء پارسشده و ساختاریافته در اختیار توسعهدهنده قرار میدهد.
- Startup Data Seeding
رویکرد مقداردهی اولیه پایگاه داده در لحظه بالا آمدن برنامه با استفاده از کدهای جاوا و ریپازیتوریها، به عنوان جایگزینی پویا و مستقل از نوع دیتابیس برای اسکریپتهای ایستا مانند data.sql.
- ApplicationArguments
کلاس ارائهشده توسط اسپرینگ بوت برای مدیریت آرگومانهای خط فرمان با متدهای کاربردی نظیر getOptionValues()، که امکان دسترسی مستقیم به گزینهها و مقادیر سوئیچهای ترمینال (مانند مقادیر دارای پیشوند --) را بدون نیاز به پیمایش دستی آرایه فراهم میسازد.
- Database-Agnostic Preloading
مزیت بارگذاری اولیه دادهها از طریق لایه ریپازیتوری (Repository-based Preloading) که باعث میشود منطق مقداردهی اولیه نه تنها روی پایگاههای داده رابطهای، بلکه روی دیتابیسهای غیررابطهای (NoSQL) نیز بدون وابستگی به سینتکس SQL اجرا شود.
موارد مصاحبه ای
- تفاوت دقیق بین CommandLineRunner و ApplicationRunner چیست؟
هر دو در یک زمان از چرخه حیات برنامه اجرا میشوند، اما ورودی متد run در CommandLineRunner یک آرایه خام از نوع String... است؛ در حالی که ApplicationRunner ورودی را به صورت نمونهای از ApplicationArguments دریافت میکند که متدهای تفکیکشده برای آرگومانهای گزینهای (Option Arguments) و بدون گزینه (Non-option Arguments) ارائه میدهد.
- چرا استفاده از Runnerها نسبت به اسکریپت data.sql در مقداردهی اولیه انعطافپذیرتر است؟
اسکریپت data.sql وابسته به موتور پایگاه داده رابطهای و سینتکس SQL است؛ در حالی که استفاده از Runnerها به شما اجازه میدهد از اشیاء دامنه و متدهای ریپازیتوری بهره ببرید، منطق شرطی یا اعتبارسنجی بنویسید و دادهها را به شکل یکپارچه در پایگاههای داده رابطهای و غیررابطهای ذخیره کنید.
- متدهای run در اینترفیسهای Startup Runner دقیقاً در چه مرحلهای از چرخه حیات اپلیکیشن اجرا میشوند؟
این متدها پس از راهاندازی کامل ApplicationContext، ایجاد تمام بینها و تزریق وابستگیها، اما پیش از پردازش هرگونه ترافیک ورودی یا اجرای منطقهای اصلی سرویس فراخوانی میشوند.
- چگونه میتوان بدون ساخت یک کلاس مجزا از CommandLineRunner یا ApplicationRunner استفاده کرد؟
از آنجا که هر دو اینترفیس تابعی هستند، میتوان آنها را درون یک کلاس پیکربندی (@Configuration) به صورت یک متد با انوتیشن @Bean تعریف کرد که یک عبارت لامبدا (Lambda Expression) برمیگرداند.
سناریو کاربردی
- مقداردهی اولیه مواد تشکیلدهنده (Ingredients) با استفاده از Bean مبتنی بر لامبدا
در این سناریو، به جای اجرای کوئریهای متنی INSERT در فایل data.sql، یک بین از نوع CommandLineRunner تعریف شده و ریپازیتوری مستقیماً به آن تزریق میشود تا موجودیتها با استفاده از متد save() در پایگاه داده ذخیره شوند:
@Configuration
public class DataLoaderConfig {
@Bean
public CommandLineRunner dataLoader(IngredientRepository repo) {
return args -> {
repo.save(new Ingredient("FLTO", "Flour Tortilla", Type.WRAP));
repo.save(new Ingredient("COTO", "Corn Tortilla", Type.WRAP));
repo.save(new Ingredient("GRBF", "Ground Beef", Type.PROTEIN));
repo.save(new Ingredient("CARN", "Carnitas", Type.PROTEIN));
repo.save(new Ingredient("TMTO", "Diced Tomatoes", Type.VEGGIES));
repo.save(new Ingredient("LETC", "Lettuce", Type.VEGGIES));
repo.save(new Ingredient("CHED", "Cheddar", Type.CHEESE));
repo.save(new Ingredient("JACK", "Monterrey Jack", Type.CHEESE));
repo.save(new Ingredient("SLSA", "Salsa", Type.SAUCE));
repo.save(new Ingredient("SRCR", "Sour Cream", Type.SAUCE));
};
}
}
مراحل کار:
۱. تزریق خودکار IngredientRepository به عنوان ورودی متد بین.
۲. اجرای بدنه لامبدا بلافاصله پس از تکمیل استارتاپ اسپرینگ.
۳. ذخیره امن دادههای اولیه از طریق ریپازیتوری با حفظ یکپارچگی مدلهای دامنه.
بیشتر بدانید
- دریافت پارامترهای تکرارپذیر با getOptionValues
متد getOptionValues("optionName") در شیء ApplicationArguments یک List<String> برمیگرداند؛ این ویژگی برای مواقعی کاربرد دارد که یک گزینه در خط فرمان چندین بار تکرار شده باشد (مانند --profile=dev --profile=debug).
- نادیدهگرفتن آرگومانهای ورودی در کدهای Seed
اگر در منطق لود اولیه نیازی به خواندن متغیرهای محیطی یا ورودیهای ترمینال ندارید، نادیده گرفتن پارامتر ورودی لامبدا (args) کاملاً استاندارد است و تاثیری در روند اجرای متد save() ندارد.
- اهمیت ترتیب اجرا با انوتیشن Order
در صورت تعریف چند بین از نوع CommandLineRunner یا ApplicationRunner، میتوانید با استفاده از انوتیشن @Order اولویت و ترتیب دقیق اجرای هر کدام را در زمان بالا آمدن برنامه مشخص کنید.
