در مقاله قبل
به طور خلاصه توضیح دادم که بهار چیست و لوبیا و بافت چیست. اکنون زمان آن است که آن را امتحان کنید. من قصد دارم این کار را با استفاده از IntelliJ IDEA Enterprise Edition انجام دهم. اما همه نمونههای من باید در نسخه رایگان انجمن IntelliJ IDEA نیز کار کنند. در اسکرین شات ها، اگر دیدید که من پنجره ای دارم که شما ندارید، نگران نباشید - برای این پروژه مهم نیست :)
ابتدا یک پروژه خالی Maven ایجاد کنید. من نحوه انجام این کار را در مقاله در این پیوند
نشان دادم . تا کلمات " وقت آن رسیده است که پروژه Maven خود را به یک پروژه وب تبدیل کنیم. " - پس از آن، مقاله نحوه ساخت یک پروژه وب را نشان می دهد، اما ما در حال حاضر به آن نیاز نداریم. در پوشه src/main/java ، یک بسته ایجاد کنید (در مورد من، آن را " نامیدم
در پنجره سمت چپ، می توانید ساختار پروژه را با بسته و کلاس مشاهده کنید

en.codegym.info.fatfaggy.animals
. می توانید آن را هر چه می خواهید صدا کنید. فقط فراموش نکنید که نام بسته من را با نام بسته خود در مکان های مناسب جایگزین کنید. حالا Main
کلاس را ایجاد کنید و یک متد اضافه کنید
public static void main(String[] args) {
...
}
پس از آن فایل pom.xml را باز کرده و dependencies
قسمت را اضافه کنید. اکنون به مخزن Maven
بروید و زمینه Spring را برای آخرین نسخه پایدار پیدا کنید. آنچه را که پیدا کردیم در dependencies
بخش قرار دهید. من این فرآیند را در این مقاله دیگر CodeGym
با جزئیات بیشتر توضیح دادم (به بخش " اتصال وابستگی ها در Maven " مراجعه کنید). سپس خود Maven وابستگی های لازم را پیدا و دانلود می کند. در پایان، شما باید چیزی شبیه به این دریافت کنید: 
Main
. پنجره وسط نشان می دهد که pom.xml چگونه برای من به نظر می رسد. یک قسمت خواص هم بهش اضافه کردم . این بخش به Maven می گوید که من از کدام نسخه جاوا در فایل های منبع خود استفاده می کنم و کدام نسخه را کامپایل کنم. این فقط برای این است که IDEA به من هشدار نمی دهد که از نسخه قدیمی جاوا استفاده می کنم. این اختیاری است :) پنجره سمت راست نشان می دهد که حتی اگر ما فقط ماژول زمینه فنری را وصل کرده ایم، به طور خودکار ماژول های فنری-هسته، فنری-بیان، فنری-آوپ و فنر-اکسپرسیون را وارد می کند. ما میتوانستیم هر ماژول را جداگانه وصل کنیم، و برای هر ماژول یک وابستگی با نسخه صریح در فایل pom.xml بنویسیم، اما در حال حاضر از همه چیز راضی هستیم. حالا entities
بسته را ایجاد کنید و 3 کلاس در آن ایجاد کنید: Cat
, Dog
, Parrot
. بیایید به هر حیوان یک نام بدهیم ( private String name
- میتوانید برخی از مقادیر را در آنجا کدگذاری کنید). گیرندگان/ تنظیم کننده ها عمومی هستند. Main
حالا به کلاس و متد می رویم main()
و چیزی شبیه این می نویسیم:
public static void main(String[] args) {
// Create an empty Spring context that will look for its own beans based on the annotations in the specified package
ApplicationContext context =
new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals.entities");
Cat cat = context.getBean(Cat.class);
Dog dog = (Dog) context.getBean("dog");
Parrot parrot = context.getBean("parrot-polly", Parrot.class);
System.out.println(cat.getName());
System.out.println(dog.getName());
System.out.println(parrot.getName());
}
ابتدا یک آبجکت متنی ایجاد می کنیم و به سازنده می گوییم که کدام بسته را برای یافتن beans جستجو کند. به عبارت دیگر، Spring از این بسته عبور می کند و سعی می کند کلاس هایی را پیدا کند که با حاشیه نویسی خاصی مشخص شده است که نشان می دهد آنها لوبیا هستند. سپس آبجکت های این کلاس ها را ایجاد می کند و در متن قرار می دهد. پس از آن، ما یک گربه از این زمینه می گیریم. ما از آبجکت متنی فرا میخوانیم تا یک bean (ابجکت) به ما بدهد، که کلاس شی مورد نظر را نشان میدهد (به هر حال، ما همچنین میتوانیم رابطها را مشخص کنیم، نه فقط کلاسها). پس از آن، Spring یک شی از کلاس درخواستی را برمی گرداند که سپس آن را در یک متغیر ذخیره می کنیم. بعد از بهار می خواهیم لوبیایی به نام سگ برای ما بیاورد. هنگامی که Spring یک Dog
شی را ایجاد می کند، به شی یک نام استاندارد می دهد (مگر اینکه به bean ایجاد شده به صراحت یک نام اختصاص داده شده باشد)، که نام کلاس است اما با یک حرف کوچک اولیه. در این مورد، کلاس ما نامیده می شود Dog
، بنابراین نام لوبیا "سگ" است. اگر به یک شی در آنجا نیاز داشتیم BufferedReader
، اسپرینگ نام آن را "bufferedReader" می گذاشت. و از آنجایی که جاوا نمی تواند 100% مطمئن باشد که کدام کلاس را می خواهیم، یک Object
شی را برمی گرداند، که سپس آن را به صورت دستی به نوع دلخواه، یعنی Dog
. گزینه ای که کلاس به صراحت نشان داده شده است راحت تر است. گزینه سوم این است که یک لوبیا را با نام کلاس و با نام لوبیا دریافت کنید. این امکان وجود دارد که زمینه ممکن است چندین دانه از یک کلاس واحد داشته باشد. برای نشان دادن لوبیا خاصی که نیاز داریم، نام آن را مشخص می کنیم. از آنجایی که ما در اینجا به صراحت کلاس را نیز نشان میدهیم، دیگر نیازی به اجرای بازیگران نداریم. مهم!اگر اسپرینگ چندین لوبیا پیدا کند که با نیازهای ما مطابقت داشته باشد، نمی تواند تعیین کند که کدام لوبیا را به ما بدهد، بنابراین یک استثنا ایجاد می کند. بر این اساس، برای جلوگیری از این وضعیت، باید سعی کنید تا حد امکان در گفتن اینکه به چه لوبیا نیاز دارید، دقیق باشید. اگر Spring زمینه خود را جستجو کند و نتواند یک لوبیا را پیدا کند که با نیازهای ما مطابقت داشته باشد، یک استثنا نیز ایجاد خواهد کرد. در نهایت، ما به سادگی نام حیوانات خود را نشان می دهیم تا بررسی کنیم که واقعاً اشیاء مورد نیاز خود را دریافت کرده ایم. اما اگر اکنون برنامه را اجرا کنیم، خواهیم دید که بهار ناراضی است - نمی تواند حیواناتی را که ما به آن نیاز داریم در زمینه خود بیابد. این به این دلیل است که این دانه ها را ایجاد نکرده است. همانطور که قبلاً گفتم، وقتی Spring کلاس ها را اسکن می کند، به دنبال حاشیه نویسی Spring خودش می گردد. و اگر اسپرینگ این حاشیهنویسیها را پیدا نکرد، پس فکر نمیکند که این کلاسها با لوبیاهایی که باید ایجاد کند مطابقت دارند. رفع این مشکل به سادگی مستلزم اضافه کردن @Component
حاشیه نویسی در جلوی هر یک از کلاس های حیوانات است.
@Component
public class Cat {
private String name = "Oscar";
...
}
اما موارد بیشتری وجود دارد. اگر بخواهیم صریحاً به Spring بگوییم که bean برای این کلاس باید یک نام خاص داشته باشد، نام را در پرانتز بعد از حاشیهنویسی نشان میدهیم. به عنوان مثال، برای اینکه به اسپرینگ بگوییم که نام " parrot-polly
" را به لوبیا طوطی بدهد، این نامی است که برای دریافت این طوطی در متد استفاده می کنیم main
، باید این کار را انجام دهیم:
@Component("parrot-polly")
public class Parrot {
private String name = "Polly";
...
}
این تمام نکته پیکربندی خودکار است . شما کلاس های خود را می نویسید، آنها را با حاشیه نویسی های لازم علامت گذاری می کنید و بسته ای که کلاس های شما را دارد به Spring بگویید. این بسته ای است که چارچوب برای یافتن حاشیه نویسی و ایجاد اشیاء از این کلاس ها اجرا می شود. به هر حال، بهار فقط به دنبال حاشیه نویسی نیست @Component
، بلکه همه حاشیه نویسی های دیگری را نیز به ارث می برند. به عنوان مثال @Controller
،،،،،، و موارد دیگر که در مقالات بعدی به معرفی @RestController
آنها خواهیم پرداخت. اکنون سعی خواهیم کرد همین کار را با استفاده از پیکربندی مبتنی بر جاوا انجام دهیم . برای شروع، حاشیهنویسیها را از کلاسهای ما حذف کنید. برای چالشبرانگیزتر کردن مسائل، تصور کنید که ما این کلاسها را ننوشتهایم، بنابراین نمیتوانیم به راحتی آنها را تغییر دهیم، به این معنی که نمیتوانیم حاشیهنویسی اضافه کنیم. مثل این است که این کلاس ها در یک کتابخانه بسته بندی شده اند. در این صورت، هیچ راهی برای ما وجود ندارد که این کلاس ها را طوری ویرایش کنیم که توسط Spring شناسایی شوند. اما ما به آبجکت هایی از این کلاس ها نیاز داریم! در اینجا برای ایجاد اشیاء به پیکربندی مبتنی بر جاوا نیاز داریم. برای شروع، یک بسته با نامی مانند ایجاد کنید . در این بسته، یک کلاس جاوای معمولی، چیزی شبیه به ایجاد کنید و آن را با حاشیهنویسی علامت بزنید. @Service
@Repository
@Component
configs
MyConfig
@Configuration
@Configuration
public class MyConfig {
}
اکنون باید main()
روش را تغییر دهیم و نحوه ایجاد زمینه را تغییر دهیم. ما می توانیم به صراحت مشخص کنیم که کدام کلاس پیکربندی ما را دارد:
ApplicationContext context =
new AnnotationConfigApplicationContext(MyConfig.class);
اگر چندین کلاس مختلف داشته باشیم که bean ها را ایجاد می کنند و بخواهیم چند تا از آنها را همزمان به هم وصل کنیم، به سادگی همه آنها را در آنجا نشان می دهیم و با کاما از هم جدا می شوند:
ApplicationContext context =
new AnnotationConfigApplicationContext(MyConfig.class, MyAnotherConfig.class);
و اگر تعداد زیادی از آنها داریم و می خواهیم همه آنها را همزمان وصل کنیم، نام بسته ای که آنها در آن قرار دارند را به سادگی نشان می دهیم:
ApplicationContext context =
new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals.configs");
در این حالت، Spring از بسته عبور می کند و تمام کلاس هایی که با @Configuration
حاشیه نویسی مشخص شده اند را پیدا می کند. خوب، و اگر ما یک برنامه واقعا بزرگ داریم که در آن تنظیمات به بستههای مختلف تقسیم میشوند، به سادگی فهرستی از نام بستههایی که حاوی تنظیمات هستند با کاما مشخص میکنیم:
ApplicationContext context =
new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals.database.configs",
"en.codegym.info.fatfaggy.animals.root.configs",
"en.codegym.info.fatfaggy.animals.web.configs");
یا نام بسته ای که برای همه آنها مشترک است:
ApplicationContext context =
new AnnotationConfigApplicationContext("en.codegym.info.fatfaggy.animals");
شما می توانید آن را هر طور که می خواهید انجام دهید، اما به نظر من اولین گزینه، که به سادگی یک کلاس با تنظیمات را نشان می دهد، بهترین گزینه برای برنامه ما خواهد بود. هنگام ایجاد یک زمینه، Spring به دنبال کلاس هایی است که با @Configuration
حاشیه نویسی مشخص شده اند و اشیاء خود را از این کلاس ها ایجاد می کند. سعی میکند متدهایی را که با @Bean
حاشیهنویسی مشخص شدهاند فراخوانی کند، به این معنی که این روشها beans (اشیاء) را که Spring به متن اضافه میکند، برمیگردانند. و اکنون ما برای یک گربه، سگ و طوطی در کلاس خود با پیکربندی مبتنی بر جاوا، لوبیا ایجاد می کنیم. انجام این کار بسیار ساده است:
@Bean
public Cat getCat() {
return new Cat();
}
در اینجا ما به صورت دستی گربه خود را ایجاد می کنیم و آن را به Spring می دهیم، که سپس شی ما را در بافت خود نگه می دارد. از آنجایی که ما صراحتاً نامی برای bean خود نگذاشتیم، Spring آن را همان نام روش نامگذاری می کند. در مورد ما، لوبیا گربه " getCat
" نامیده می شود. اما از آنجا که ما از کلاس استفاده می کنیم، نه از نام، برای دریافت cat bean در روش main
، نام bean برای ما مهم نیست. به طور مشابه، یک لوبیا سگ ایجاد کنید، به خاطر داشته باشید که Spring نام روش را به لوبیا می دهد. برای نامگذاری صریح لوبیا طوطی خود، به سادگی نام آن را در داخل پرانتز بعد از @Bean
حاشیه نویسی نشان می دهیم:
@Bean("parrot-polly")
public Object weNeedMoreParrots() {
return new Parrot();
}
همانطور که می بینید، در اینجا من یک Object
نوع بازگشتی را نشان دادم و به روش یک نام دلخواه دادم. این روی نام لوبیا تاثیری ندارد، زیرا ما به صراحت نام را در اینجا مشخص کرده ایم. با این حال، بهتر است یک مقدار بازگشتی کم و بیش معنی دار و نام روش را نشان دهید. این کار را در صورتی انجام دهید که به هیچ دلیل دیگری به غیر از این که یک سال دیگر پروژه را بازگشایی می کنید، به خودتان لطفی کنید. :) حالا شرایطی را در نظر بگیرید که برای ایجاد یک لوبیا دیگر به یک لوبیا نیاز داریم . به عنوان مثال، فرض کنید می خواهیم نام گربه در لوبیا گربه، نام طوطی به اضافه رشته "-killer" باشد. مشکلی نیست!
@Bean
public Cat getCat(Parrot parrot) {
Cat cat = new Cat();
cat.setName(parrot.getName() + "-killer");
return cat;
}
در اینجا Spring می بیند که برای ایجاد این bean، چارچوب باید در parrot bean که قبلا ایجاد شده بود عبور کند. بر این اساس، زنجیره لازم از فراخوانی های متد را ترتیب می دهد: ابتدا روش ایجاد طوطی فراخوانی می شود و سپس چارچوب طوطی جدید را به روش گربه آفرینی منتقل می کند. اینجاست که تزریق وابستگی وارد عمل میشود: اسپرینگ خود دانههای طوطی مورد نیاز را به روش ما منتقل میکند. اگر IDEA در مورد متغیر ناراحت شد parrot
، فراموش نکنید که نوع برگشت روش ایجاد طوطی را از Object
به تغییر دهید Parrot
. علاوه بر این، پیکربندی مبتنی بر جاوا به شما این امکان را می دهد که مطلقاً هر کد جاوا را در روش های ایجاد bean اجرا کنید. شما واقعاً می توانید هر کاری انجام دهید: اشیاء کمکی دیگری ایجاد کنید، هر روش دیگری را فراخوانی کنید، حتی آنهایی که با حاشیه نویسی Spring مشخص نشده اند، ایجاد حلقه ها، شرایط بولی - هر آنچه به ذهنتان می رسد! این همه با پیکربندی خودکار امکان پذیر نیست، و حتی کمتر با پیکربندی XML. حالا بیایید مشکلی را در نظر بگیریم که کمی سرگرم کننده تر است. چند شکلی و رابط ها :) ما یک WeekDay
رابط ایجاد می کنیم و 7 کلاس ایجاد می کنیم که این رابط را پیاده سازی می کند : Monday
, Tuesday
, Wednesday
, Thursday
, Friday
, Saturday
. Sunday
به اینترفیس String getWeekDayName()
متدی می دهیم که نام روز هفته را برای کلاس مربوطه برمی گرداند. به عبارت دیگر، Monday
کلاس برمیگردد " Monday
"، و غیره. با شروع برنامه، فرض کنید وظیفه ما این است که یک Bean مربوط به روز جاری هفته را در متن قرار دهیم. نه bean برای همه کلاسهایی که WeekDay
رابط را پیادهسازی میکنند - فقط یک bean که ما به آن نیاز داریم. شما می توانید این کار را به صورت زیر انجام دهید:
@Bean
public WeekDay getDay() {
DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
switch (dayOfWeek) {
case MONDAY: return new Monday();
case TUESDAY: return new Tuesday();
case WEDNESDAY: return new Wednesday();
case THURSDAY: return new Thursday();
case FRIDAY: return new Friday();
case SATURDAY: return new Saturday();
default: return new Sunday();
}
}
در اینجا نوع بازگشت رابط ما است. این متد بسته به روز جاری هفته، یک شی واقعی از یکی از کلاسهایی که رابط را پیادهسازی میکنند، برمیگرداند. حالا در main()
متد می توانیم کارهای زیر را انجام دهیم:
WeekDay weekDay = context.getBean(WeekDay.class);
System.out.println("Today is " + weekDay.getWeekDayName() + "!");
برای من، برنامه به من می گوید یکشنبه است :) من مطمئن هستم که اگر فردا برنامه را اجرا کنم، متن حاوی یک شی کاملاً متفاوت خواهد بود. توجه داشته باشید که ما به سادگی با استفاده از رابط کاربری زیر را دریافت می کنیم: context.getBean(WeekDay.class)
. Spring زمینه خود را برای Bean که رابط را پیاده سازی می کند جستجو می کند و آن را برمی گرداند. سپس معلوم می شود که WeekDay
متغیر ما به یک شی یکشنبه ختم می شود، و مفهوم آشنای چندشکلی در حین کار با این متغیر اعمال می شود. :) اکنون چند کلمه در مورد رویکرد ترکیبی@Component
، که در آن برخی از دانهها بهطور خودکار توسط Spring، برخی با اسکن بستهها برای کلاسهای دارای حاشیهنویسی، و برخی دیگر با پیکربندی مبتنی بر جاوا ایجاد میشوند . همانطور که این موضوع را در نظر می گیریم، به نسخه اصلی باز می گردیم، جایی که Cat
, Dog
و Parrot
کلاس ها با @Component
حاشیه نویسی مشخص شده اند. فرض کنید میخواهیم با اسکن خودکار بستهبندی به صورت خودکار ، برای حیوانات خود لوبیا ایجاد کنیم entities
، اما همچنین میخواهیم مانند کاری که انجام دادیم، یک لوبیا با روز هفته ایجاد کنیم. تنها کاری که باید انجام دهید این است که @ComponentScan
حاشیه نویسی را در سطح کلاس اضافه کنید MyConfig
، که هنگام ایجاد زمینه در آن نشان می دهیم main()
، و بسته ای را که باید اسکن شود در پرانتز نشان می دهیم و به طور خودکار beans از کلاس های لازم را ایجاد می کنیم:
@Configuration
@ComponentScan("en.codegym.info.fatfaggy.animals.entities")
public class MyConfig {
@Bean
public WeekDay getDay() {
DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
switch (dayOfWeek) {
case MONDAY: return new Monday();
case TUESDAY: return new Tuesday();
case WEDNESDAY: return new Wednesday();
case THURSDAY: return new Thursday();
case FRIDAY: return new Friday();
case SATURDAY: return new Saturday();
default: return new Sunday();
}
}
}
هنگام ایجاد زمینه، Spring می بیند که باید MyConfig
کلاس را پردازش کند. وارد کلاس می شود و می بیند که باید en.codegym.info.fatfaggy.animals.entities
بسته " " را اسکن کند و bean های آن کلاس ها را ایجاد کند، پس از آن متد MyConfig
کلاس را اجرا می کند getDay()
و یک WeekDay
bean به متن اضافه می کند. در main()
روش، ما اکنون به تمام حبوبات مورد نیاز خود دسترسی داریم: هم اشیاء حیوانی و هم یک لوبیا با روز هفته. اگر زمانی نیاز دارید که Spring را نیز برخی از فایلهای پیکربندی XML را انتخاب کنید، میتوانید جستجوی وب خود را برای یافتن توضیحی انجام دهید :) خلاصه:
- سعی کنید از تنظیمات خودکار استفاده کنید
- در طول پیکربندی خودکار، نام بستهای را که شامل کلاسهایی است که باید beans ایجاد شود، مشخص کنید
- این کلاس ها با
@Component
حاشیه نویسی مشخص شده اند - Spring در تمام این کلاس ها می گذرد، اشیا را ایجاد می کند و آنها را در زمینه قرار می دهد.
- اگر پیکربندی خودکار به دلایلی برای ما مناسب نیست، از پیکربندی مبتنی بر جاوا استفاده می کنیم
- در این حالت یک کلاس جاوای معمولی ایجاد می کنیم که متدهای آن اشیاء مورد نیاز ما را برمی گرداند.
@Configuration
اگر بخواهیم کل بسته را اسکن کنیم به جای نشان دادن یک کلاس خاص با پیکربندی هنگام ایجاد زمینه، این کلاس را با حاشیهنویسی علامتگذاری میکنیم. - روشهای این کلاس که beans را برمیگردانند با
@Bean
حاشیهنویسی مشخص میشوند
@ComponentScan
حاشیه نویسی استفاده می کنیم.
GO TO FULL VERSION