في المقالة السابقة
، شرحت بإيجاز ما هو الربيع وما هي الفاصوليا والسياق. الآن حان الوقت لتجربته. سأفعل ذلك باستخدام IntelliJ IDEA Enterprise Edition. ولكن يجب أن تعمل جميع الأمثلة الخاصة بي أيضًا في الإصدار المجاني من IntelliJ IDEA Community Edition. في لقطات الشاشة، إذا رأيت أن لدي نافذة ليست لديك، فلا تقلق - فهذا ليس مهمًا لهذا المشروع :) أولاً، أنشئ مشروع 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 بإصدار Java الذي أستخدمه في ملفاتي المصدرية والإصدار الذي يجب تجميعه. هذا فقط حتى لا تحذرني IDEA من أنني أستخدم إصدارًا قديمًا من Java. هذا اختياري :) توضح النافذة اليمنى أنه على الرغم من أننا قمنا بتوصيل وحدة السياق الربيعي فقط، إلا أنها قامت تلقائيًا بسحب وحدات الربيع الأساسية والفاصوليا الربيعية والزنبرك aop والتعبير الربيعي. كان بإمكاننا ربط كل وحدة على حدة، وكتابة تبعية لكل وحدة مع الإصدار الصريح في ملف 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());
}
أولاً، نقوم بإنشاء كائن سياق، لإخبار المنشئ بالحزمة التي يجب البحث فيها للعثور على الحبوب. بمعنى آخر، سوف يستعرض Spring هذه الحزمة ويحاول العثور على فئات مميزة بتعليقات توضيحية خاصة تشير إلى أنها حبوب. ثم يقوم بإنشاء كائنات هذه الفئات ويضعها في السياق. بعد ذلك نحصل على قطة من هذا السياق. نستدعي كائن السياق ليعطينا حبة (كائن)، تشير إلى فئة الكائن الذي نريده (بالمناسبة، يمكننا أيضًا تحديد الواجهات، وليس الفئات فقط). بعد ذلك، يقوم Spring بإرجاع كائن من الفئة المطلوبة، والذي نقوم بعد ذلك بحفظه في متغير. بعد ذلك، نطلب من الربيع أن يحضر لنا حبة فول تسمى "كلب". عندما ينشئ Spring Dog
كائنًا، فإنه يمنح الكائن اسمًا قياسيًا (ما لم يتم تعيين اسم صريح للفاصوليا التي تم إنشاؤها)، وهو اسم الفئة ولكن بحرف صغير أولي. في هذه الحالة، يُسمى الفصل الخاص بنا Dog
، لذا يكون اسم الحبة "كلب". إذا كنا بحاجة إلى BufferedReader
كائن هناك، فسيقوم Spring بتسميته "bufferedReader". ولأن Java لا يمكنها التأكد بنسبة 100% من الفئة التي نريدها، فإنها تقوم بإرجاع كائن Object
، والذي نقوم بعد ذلك بتحويله يدويًا إلى النوع المطلوب، على سبيل المثال Dog
. يعد الخيار الذي يتم فيه الإشارة إلى الفصل بشكل صريح أكثر ملاءمة. الخيار الثالث هو الحصول على الفول حسب اسم الفئة واسم الفول. من الممكن أن يحتوي السياق على عدة حبوب من فئة واحدة. من أجل الإشارة إلى الحبة المحددة التي نحتاجها، نشير إلى اسمها. نظرًا لأننا نشير أيضًا بوضوح إلى الفصل هنا، فلم يعد يتعين علينا إجراء عملية التمثيل. مهم!إذا وجد Spring العديد من الحبوب التي تتوافق مع متطلباتنا، فلن يتمكن من تحديد الحبوب التي سيقدمها لنا، لذلك سيطرح استثناءً. وفقًا لذلك، لتجنب هذا الموقف، يجب أن تحاول أن تكون محددًا قدر الإمكان في إخبار سبرينج بالفاصوليا التي تحتاجها. إذا بحث Spring في سياقه وفشل في العثور على حبة واحدة تتوافق مع متطلباتنا، فسوف يقوم أيضًا بطرح استثناء. وأخيرًا، نقوم ببساطة بعرض أسماء حيواناتنا للتحقق من أننا حصلنا بالفعل على العناصر التي نحتاجها. لكن إذا قمنا بتشغيل البرنامج الآن، فسنرى أن سبرينج غير سعيد - فهو لا يستطيع العثور على الحيوانات التي نحتاجها في سياقه. هذا لأنه لم يخلق هذه الحبوب. كما قلت سابقًا، عندما يقوم Spring بفحص الفصول الدراسية، فإنه يبحث عن التعليقات التوضيحية الربيعية الخاصة به. وإذا لم يجد Spring هذه التعليقات التوضيحية، فلا يعتقد أن هذه الفئات تتوافق مع الحبوب التي يحتاج إلى إنشائها. إصلاح هذا يتطلب ببساطة إضافة @Component
التعليق التوضيحي أمام كل فئة من فئات الحيوانات لدينا.
@Component
public class Cat {
private String name = "Oscar";
...
}
ولكن هناك المزيد. إذا أردنا أن نقول صراحةً لـ Spring أن حبة هذه الفئة يجب أن يكون لها اسم محدد، فسنشير إلى الاسم بين قوسين بعد التعليق التوضيحي. على سبيل المثال، لنطلب من Spring أن يعطي الاسم " parrot-polly
" لفاصوليا الببغاء، وهو الاسم الذي سنستخدمه للحصول على هذا الببغاء في الطريقة main
، يجب أن نفعل شيئًا مثل هذا:
@Component("parrot-polly")
public class Parrot {
private String name = "Polly";
...
}
هذا هو بيت القصيد من التكوين التلقائي . تكتب فصولك الدراسية، وتضع علامة عليها بالتعليقات التوضيحية اللازمة، وتخبر Spring بالحزمة التي تحتوي على فصولك الدراسية. هذه هي الحزمة التي سيتم تشغيل إطار العمل من خلالها للعثور على التعليقات التوضيحية وإنشاء كائنات من هذه الفئات. بالمناسبة، الربيع لا يبحث فقط عن @Component
التعليقات التوضيحية، ولكن أيضًا عن جميع التعليقات التوضيحية الأخرى التي ترث هذه التعليقات التوضيحية. على سبيل المثال، @Controller
و @RestController
، @Service
و، @Repository
و، والمزيد، والتي سنقدمها في المقالات القادمة. سنحاول الآن القيام بنفس الشيء باستخدام التكوين المستند إلى Java . للبدء، قم بإزالة @Component
التعليقات التوضيحية من فصولنا. ولجعل الأمور أكثر صعوبة، تخيل أننا لم نكتب هذه الفئات، لذلك لا يمكننا تعديلها بسهولة، مما يعني أننا لا نستطيع إضافة التعليقات التوضيحية. يبدو الأمر كما لو أن هذه الفئات مجمعة في بعض المكتبات. في هذه الحالة، لا توجد طريقة يمكننا من خلالها تعديل هذه الفئات حتى يتعرف عليها Spring. لكننا بحاجة إلى كائنات من هذه الفئات! نحتاج هنا إلى التكوين المستند إلى Java لإنشاء الكائنات. للبدء، قم بإنشاء حزمة باسم مثل configs
. في هذه الحزمة، أنشئ فئة Java عادية، مثل MyConfig
, وقم بوضع علامة عليها باستخدام @Configuration
التعليق التوضيحي.
@Configuration
public class MyConfig {
}
الآن نحن بحاجة إلى تعديل main()
الطريقة، وتغيير كيفية إنشاء السياق. يمكننا إما أن نشير بوضوح إلى الفئة التي تحتوي على إعداداتنا:
ApplicationContext context =
new AnnotationConfigApplicationContext(MyConfig.class);
إذا كان لدينا العديد من الفئات المختلفة التي تنشئ الحبوب ونريد ربط العديد منها في وقت واحد، فإننا ببساطة نشير إليها جميعًا هناك، مفصولة بفواصل:
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
، مما يعني أن هذه الأساليب تُرجع الفاصوليا (الكائنات) التي سيضيفها Spring إلى السياق. والآن سنقوم بإنشاء فاصوليا للقطط والكلاب والببغاء في فصلنا باستخدام التكوين المستند إلى Java. هذا أمر بسيط جدًا:
@Bean
public Cat getCat() {
return new Cat();
}
نحن هنا ننشئ قطتنا يدويًا ونسلمها إلى Spring، الذي يحمل الكائن في سياقه. نظرًا لأننا لم نعطي اسمًا صريحًا للفاصوليا الخاصة بنا، فسيعطيها Spring نفس اسم اسم الطريقة. في حالتنا، سيتم تسمية حبة القطة بـ " getCat
". ولكن نظرًا لأننا نستخدم الفئة، وليس الاسم، للحصول على حبة القطة في الطريقة main
، فإن اسم الحبة ليس مهمًا بالنسبة لنا. وبالمثل، أنشئ حبة كلبية، مع الأخذ في الاعتبار أن 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;
}
هنا سيرى سبرينج أنه من أجل إنشاء هذه الحبة، يجب أن يمر الإطار في حبة الببغاء التي تم إنشاؤها مسبقًا. وفقًا لذلك، سيقوم بترتيب السلسلة الضرورية من استدعاءات الأساليب: أولاً، يتم استدعاء طريقة إنشاء الببغاء ثم يقوم الإطار بتمرير الببغاء الجديد إلى طريقة إنشاء القطة. وهنا يأتي دور حقن التبعية : يقوم الربيع نفسه بتمرير حبة الببغاء المطلوبة إلى طريقتنا. إذا انزعجت IDEA بشأن parrot
المتغير، فلا تنس تغيير نوع الإرجاع لطريقة إنشاء الببغاء من Object
إلى Parrot
. بالإضافة إلى ذلك، يتيح لك التكوين المستند إلى Java تشغيل أي تعليمات برمجية Java على الإطلاق في طرق إنشاء الفول الخاصة بك. يمكنك حقًا فعل أي شيء: إنشاء كائنات مساعدة أخرى، واستدعاء أي طرق أخرى، حتى تلك التي لم يتم تمييزها بتعليقات Spring التوضيحية، وإنشاء حلقات، وشروط منطقية - أيًا كان ما يتبادر إلى ذهنك! هذا ليس كل شيء ممكنًا مع التكوين التلقائي، وحتى أقل من ذلك مع تكوين XML. الآن دعونا نفكر في مشكلة أكثر متعة. تعدد الأشكال والواجهات :) سنقوم بإنشاء WeekDay
واجهة وإنشاء 7 فئات تنفذ هذه الواجهة: Monday
, Tuesday
, Wednesday
, Thursday
, Friday
, Saturday
, Sunday
. سنعطي الواجهة String getWeekDayName()
طريقة، والتي ستعيد اسم يوم الأسبوع للفئة المقابلة. بمعنى آخر، Monday
سيعود الفصل " Monday
"، وما إلى ذلك. عند بدء التطبيق، لنفترض أن مهمتنا هي وضع حبة تتوافق مع اليوم الحالي من الأسبوع في السياق. ليست حبوبًا لجميع الفئات التي تنفذ الواجهة WeekDay
— فقط حبة الفول الوحيدة التي نحتاجها. يمكنك القيام بذلك مثل هذا:
@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 في سياقه عن الحبة التي تنفذ الواجهة وسيعيدها. ثم يتبين أن WeekDay
المتغير لدينا ينتهي بكائن Sunday، وينطبق المفهوم المألوف لتعدد الأشكال أثناء تعاملنا مع هذا المتغير. :) الآن بضع كلمات حول النهج المدمج ، حيث يتم إنشاء بعض الحبوب تلقائيًا بواسطة Spring، وبعضها عن طريق مسح الحزم بحثًا عن الفئات ذات @Component
التعليقات التوضيحية، والبعض الآخر عن طريق التكوين المستند إلى Java. عندما نفكر في هذا، سنعود إلى الإصدار الأصلي، حيث تم تمييز الفئات و و و مع Cat
التعليق Dog
التوضيحي . لنفترض أننا نريد إنشاء حبة لحيواناتنا من خلال جعل Spring يقوم بمسح الحزمة تلقائيًا ، لكننا نريد أيضًا إنشاء حبة مع يوم الأسبوع، كما فعلنا للتو. كل ما عليك فعله هو إضافة التعليق التوضيحي على مستوى الفصل ، والذي نشير إليه عند إنشاء السياق في ، ونشير بين قوسين إلى الحزمة التي يجب فحصها وإنشاء وحدات من الفئات الضرورية تلقائيًا: Parrot
@Component
entities
@ComponentScan
MyConfig
main()
@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
الحزمة " " وإنشاء وحدات من تلك الفئات، وبعد ذلك ينفذ طريقة MyConfig
الفصل getDay()
ويضيف WeekDay
وحدة إلى السياق. في هذه main()
الطريقة، أصبح لدينا الآن إمكانية الوصول إلى جميع الفاصوليا التي نحتاجها: كل من العناصر الحيوانية وحبة الفاصوليا مع يوم الأسبوع. إذا كنت بحاجة في أي وقت إلى جعل Spring يلتقط أيضًا بعض ملفات تكوين XML، فيمكنك إجراء بحث الويب الخاص بك للعثور على تفسير :) الملخص:
- حاول استخدام التكوين التلقائي
- أثناء التكوين التلقائي، قم بالإشارة إلى اسم الحزمة التي تحتوي على الفئات التي يجب إنشاء وحداتها
- يتم وضع علامة على هذه الفئات مع
@Component
الشرح - يمر الربيع عبر كل هذه الفئات، ويخلق الكائنات، ويضعها في السياق؛
- إذا لم يناسبنا التكوين التلقائي لسبب ما، فإننا نستخدم التكوين المستند إلى Java
- في هذه الحالة، نقوم بإنشاء فئة Java عادية تقوم أساليبها بإرجاع الكائنات التي نحتاجها. نقوم بوضع علامة على هذه الفئة مع
@Configuration
التعليق التوضيحي إذا كنا سنقوم بفحص الحزمة بأكملها بدلاً من الإشارة إلى فئة معينة مع التكوين عند إنشاء السياق - يتم تمييز طرق هذه الفئة التي تقوم بإرجاع الفاصوليا بالتعليق
@Bean
التوضيحي
@ComponentScan
التوضيحي.
GO TO FULL VERSION