تُستخدم تعليقة Autowired في الربيع لحقن التبعية تلقائيًا. يعتمد إطار الربيع على حقن التبعية ونحن نقوم بحقن تبعيات الفئة من خلال ملف تكوين حبوب الربيع.
تعليقة الربيع Autowired
- عادةً ما نقدم تفاصيل تكوين الحبوب في ملف تكوين حبوب الربيع ونحدد أيضًا الحبوب التي سيتم حقنها في حبوب أخرى باستخدام سمة
ref
. ولكن إطار الربيع يوفر أيضًا ميزات التوصيل التلقائي حيث لا نحتاج إلى تقديم تفاصيل حقن الحبوب بشكل صريح. هناك طرق مختلفة يمكننا من خلالها حقن حبوب الربيع تلقائيًا. توصيل تلقائي بالاسم – في هذا النوع من التوصيل التلقائي، يتم استخدام طريقة الضبط لحقن التبعية. كما يجب أن يكون اسم المتغير متطابقًا في الفئة التي سنقوم بحقن التبعية فيها وفي ملف تكوين حبوب الربيع. - autowire byType – لهذا النوع من التوصيل التلقائي، يتم استخدام نوع الفئة. لذا يجب أن يكون هناك صنف واحد فقط مكون لهذا النوع في ملف تكوين فولف الفاصلة.
- autowire by constructor – هذا يشبه تقريبًا autowire byType، الفارق الوحيد هو استخدام البناء لحقن التبعية.
- autowire by autodetect – إذا كنت على Spring 3.0 أو الإصدارات الأقدم، هذا هو أحد خيارات التوصيل التلقائي المتاحة. تم استخدام هذا الخيار للتوصيل التلقائي بواسطة البناء أو بواسطة النوع، حسب تحديد حاوية Spring. نظرًا لأن لدينا بالفعل العديد من الخيارات، فقد تم إهمال هذا الخيار. لن أغطي هذا الخيار في هذا البرنامج التعليمي.
@Autowired
التعليق – يمكننا استخدام تعليق @Autowired لتوصيل الفولف الربيعي. يمكن تطبيق التعليق @Autowired على المتغيرات والطرق لتوصيل الفئة. يمكن أيضًا استخدام @Autowired التعليق على البناء لتوصيل الربيع بناءً على البناء. لكي يعمل @Autowired التعليق، نحتاج أيضًا إلى تمكين التكوين القائم على التعليق في ملف تكوين فولف الفاصلة الربيعي. يمكن القيام بذلك عن طريق context:annotation-config العنصر أو عن طريق تعريف فولف نوعorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
.تعليق @Qualifier - يتم استخدام هذا التعليق لتجنب التضارب في تعيين الفولاذة ونحتاج إلى توفير اسم الفولاذة التي ستُستخدم للتوصيل التلقائي. بهذه الطريقة يمكننا تجنب المشاكل التي تنشأ عند تعريف فولاذات متعددة لنفس النوع. هذا التعليق عادةً ما يعمل بالتعاون مع التعليق @Autowired. بالنسبة للمنشآت ذات الوسائط المتعددة، يمكننا استخدام هذا التعليق مع أسماء الوسائط في الطريقة.
بشكل افتراضي، يتم إيقاف تشغيل توصيل الفولاذات الربيعية. قيمة الوسائط الربيعية الافتراضية هي “افتراضي” مما يعني عدم القيام بأي توصيل تلقائي. قيمة الوسائط “لا” لها نفس السلوك أيضًا. لعرض استخدام توصيل الفولاذات الربيعية، دعونا نقوم بإنشاء مشروع Spring Maven بسيط. سيبدو مشروعنا النهائي كما هو موضح في الصورة أدناه. دعونا نلقي نظرة على كل من خيارات التوصيل التلقائي واحدًا تلو الآخر. لذلك سنقوم بإنشاء فولاذة نموذجية وفئة خدمة حيث سنقوم بحقن الفولاذة النموذجية.
الربيع @Autowired التعليق – تبعيات Maven
بالنسبة لتوصيل الربيع، لا نحتاج إلى إضافة أي تبعيات إضافية. ملف pom.xml لدينا يحتوي على تبعيات إطار الربيع الأساسية ويبدو كما هو موضح أدناه.
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.samples</groupId>
<artifactId>SpringBeanAutowiring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<!-- Generic properties -->
<java.version>1.6</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring -->
<spring-framework.version>4.0.2.RELEASE</spring-framework.version>
<!-- Logging -->
<logback.version>1.0.13</logback.version>
<slf4j.version>1.7.5</slf4j.version>
</properties>
<dependencies>
<!-- Spring and Transactions -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
الربيع@Autowired التعليق – نموذج الفاصلة
لنقم بإنشاء فولدر جافا بسيط، يسمى موظف. سيحتوي هذا الفولدر على خاصية واحدة فقط مع أساليب الحصول وتعيين. سنقوم بتهيئة قيمة هذه الخاصية في ملف تكوين فولدر الربيع.
package com.journaldev.spring.autowiring.model;
public class Employee {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
الربيع@Autowired التعليق – فئة الخدمة
لنقم بإنشاء فئتنا الخدمية التي سنحقق فيها فولدر الموظف من خلال توصيل الربيع تلقائيًا.
package com.journaldev.spring.autowiring.service;
import com.journaldev.spring.autowiring.model.Employee;
public class EmployeeService {
private Employee employee;
// يتم استخدام المُنشئ للتوصيل تلقائيًا بواسطة المُنشئ
public EmployeeService(Employee emp) {
System.out.println("Autowiring by constructor used");
this.employee = emp;
}
// المُنشئ الافتراضي لتجنب إثارة الاستثناءات لعدم تمكين توليد الفولدر
// بالاسم أو بالنوع
public EmployeeService() {
System.out.println("Default Constructor used");
}
// تستخدم للتوصيل بالاسم وبالنوع
public void setEmployee(Employee emp) {
this.employee = emp;
}
public Employee getEmployee() {
return this.employee;
}
}
سنستخدم نفس فئة الخدمة لأداء سبرينغ التوصيل الآلي حسب الاسم وحسب النوع وعبر البناء. سيتم استخدام طريقة الضبط للتوصيل الآلي بواسطة الاسم وحسب النوع بينما سيتم استخدام حقن البناء بواسطة سمة الضبط بواسطة البناء. عندما نستخدم سبرينغ التوصيل الآلي حسب الاسم أو حسب النوع، يتم استخدام البناء الافتراضي. ولهذا السبب قمنا بتعريف البناء الافتراضي بوضوح لفئة EmployeeService.
الربيع
@Autowired
تعليق – مثال على التوصيل الآلي حسب النوع
لنقم بإنشاء فئة منفصلة مع تعليق @Autowired لسبرينغ للتوصيل الآلي حسب النوع.
package com.journaldev.spring.autowiring.service;
import org.springframework.beans.factory.annotation.Autowired;
import com.journaldev.spring.autowiring.model.Employee;
public class EmployeeAutowiredByTypeService {
// تعليق @Autowired على المتغير/المعين يعادل autowire="byType"
@Autowired
private Employee employee;
@Autowired
public void setEmployee(Employee emp){
this.employee=emp;
}
public Employee getEmployee(){
return this.employee;
}
}
يرجى ملاحظة أنني قمت بتوسيم كل من المتغير وطريقة ضبطه لـ Employee بتوسيم @Autowired، ومع ذلك يكفي واحدة فقط من هاتين لتوصيل الفاصلة الربيع.
الربيع@Autowired التعليق وتشغيل Bean عن طريق مثال بناء الجملة
لنقم بإنشاء فئة خدمة أخرى حيث سنستخدم @Autowired التعليق لحقن البناء. كما سنرى أيضًا استخدام @Qualifier التعليق.
package com.journaldev.spring.autowiring.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import com.journaldev.spring.autowiring.model.Employee;
public class EmployeeAutowiredByConstructorService {
private Employee employee;
// تعليق Autowired على البناء معادل لـ autowire="constructor"
@Autowired(required=false)
public EmployeeAutowiredByConstructorService(@Qualifier("employee") Employee emp){
this.employee=emp;
}
public Employee getEmployee() {
return this.employee;
}
}
عندما يتم تهيئة هذا الحبوب بواسطة إطار العمل الربيع، سيتم استخدام الحبوب بالاسم “employee” للتشغيل التلقائي. يستثني تعليق Spring @Autowired وسيتوقع واحدة الوسيط “مطلوبة” وهي قيمة منطقية مع قيمة افتراضية TRUE. يمكننا تحديد أن تكون “false” بحيث لا يقوم إطار الربيع برمي أي استثناء إذا لم يتم العثور على حبوب مناسبة للتشغيل التلقائي.
الربيع@Autowired التعليق – ملف تكوين الفاصل
ملف تكوين حبة الربيع هو الجزء الرئيسي في أي تطبيق ربيع، دعونا نرى كيف يبدو ملف تكوين حبة الربيع ثم سنتناول كل جزء منه.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-4.0.xsd"
default-autowire="byName" default-autowire-candidates="*" >
<bean name="employee" class="com.journaldev.spring.autowiring.model.Employee">
<property name="name" value="Pankaj"></property>
</bean>
<bean name="employee1" class="com.journaldev.spring.autowiring.model.Employee" autowire-candidate="false">
<property name="name" value="Dummy Name"></property>
</bean>
<!-- autowiring byName, bean name should be same as the property name -->
<bean name="employeeServiceByName" class="com.journaldev.spring.autowiring.service.EmployeeService" autowire="byName" />
<!-- autowiring byType, there should be only one bean definition for the mapping -->
<bean name="employeeServiceByType" class="com.journaldev.spring.autowiring.service.EmployeeService" autowire="byType" />
<!-- autowiring by constructor -->
<bean name="employeeServiceConstructor" class="com.journaldev.spring.autowiring.service.EmployeeService" autowire="constructor" />
<!-- Enable Annotation based configuration -->
<context:annotation-config />
<!-- using @Autowiring annotation in below beans, byType and constructor -->
<bean name="employeeAutowiredByTypeService" class="com.journaldev.spring.autowiring.service.EmployeeAutowiredByTypeService" />
<bean name="employeeAutowiredByConstructorService" class="com.journaldev.spring.autowiring.service.EmployeeAutowiredByConstructorService" />
</beans>
النقاط المهمة حول ملف تكوين حبة الربيع هي:
- beans العنصر
default-autowire
يُستخدم لتعريف طريقة التضمين التلقائي الافتراضية. هنا أنا أعرف طريقة التضمين التلقائي الافتراضية لتكون حسب الاسم. - beans العنصر
default-autowire-candidates
يُستخدم لتوفير نمط أسماء الفاصل التي يمكن استخدامها للتضمين التلقائي. لبساطة، أنا أسمح باعتبار جميع تعاريف الفاصل مؤهلة للتضمين التلقائي، ومع ذلك إذا كنا نستطيع تحديد بعض الأنماط للتضمين التلقائي. على سبيل المثال، إذا أردنا فقط تعريفات فاصل DAO للتضمين التلقائي، يمكننا تحديدها كـdefault-autowire-candidates="*DAO"
. autowire-candidate="false"
يُستخدم في تعريف الفاصل لجعله غير مؤهل للتضمين التلقائي. إنه مفيد عندما يكون لدينا تعاريف فاصل متعددة لنوع واحد ونريد أن لا يتم تضمين بعضها تلقائيًا. على سبيل المثال، في تكوينات فاصل الربيع أعلاه، لن يتم استخدام الفاصل “employee1” للتضمين التلقائي.- يعتبر سمة الـ autowire بواسطة الاسم، بواسطة النوع والبناء مفهومًا بذاته، لا يوجد الكثير للشرح هنا.
context:annotation-config
يُستخدم لتمكين دعم التكوين القائم على التعليقات. لاحظ أن الفئات employeeAutowiredByTypeService و employeeAutowiredByConstructorService ليست لديها سمات autowire.
Spring @Autowired التعليق – برنامج الاختبار
الآن بعد أن تكونت تطبيقاتنا بـ Spring مع جميع أنواع التوصيل التلقائي، دعونا نكتب برنامج اختبار بسيط لنرى ما إذا كان يعمل كما هو متوقع أم لا.
package com.journaldev.spring.autowiring.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.journaldev.spring.autowiring.service.EmployeeAutowiredByConstructorService;
import com.journaldev.spring.autowiring.service.EmployeeAutowiredByTypeService;
import com.journaldev.spring.autowiring.service.EmployeeService;
public class SpringMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
EmployeeService serviceByName = ctx.getBean("employeeServiceByName", EmployeeService.class);
System.out.println("Autowiring byName. Employee Name="+serviceByName.getEmployee().getName());
EmployeeService serviceByType = ctx.getBean("employeeServiceByType", EmployeeService.class);
System.out.println("Autowiring byType. Employee Name="+serviceByType.getEmployee().getName());
EmployeeService serviceByConstructor = ctx.getBean("employeeServiceConstructor", EmployeeService.class);
System.out.println("Autowiring by Constructor. Employee Name="+serviceByConstructor.getEmployee().getName());
// طباعة هاشكود للتحقق من أن جميع الكائنات هي من أنواع مختلفة
System.out.println(serviceByName.hashCode()+"::"+serviceByType.hashCode()+"::"+serviceByConstructor.hashCode());
// اختبار تعليقات @Autowired
EmployeeAutowiredByTypeService autowiredByTypeService = ctx.getBean("employeeAutowiredByTypeService",EmployeeAutowiredByTypeService.class);
System.out.println("@Autowired byType. Employee Name="+autowiredByTypeService.getEmployee().getName());
EmployeeAutowiredByConstructorService autowiredByConstructorService = ctx.getBean("employeeAutowiredByConstructorService",EmployeeAutowiredByConstructorService.class);
System.out.println("@Autowired by Constructor. Employee Name="+autowiredByConstructorService.getEmployee().getName());
ctx.close();
}
}
البرنامج بسيط، نقوم فقط بإنشاء سياق تطبيق Spring واستخدامه للحصول على فئات مختلفة وطباعة اسم الموظف. عند تشغيل التطبيق أعلاه، نحصل على الإخراج التالي.
Mar 31, 2014 10:41:58 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@3fa99295: startup date [Mon Mar 31 22:41:58 PDT 2014]; root of context hierarchy
Mar 31, 2014 10:41:58 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring.xml]
Default Constructor used
Default Constructor used
Autowiring by constructor used
Autowiring byName. Employee Name=Pankaj
Autowiring byType. Employee Name=Pankaj
Autowiring by Constructor. Employee Name=Pankaj
21594592::15571401::1863015320
@Autowired byType. Employee Name=Pankaj
@Autowired by Constructor. Employee Name=Pankaj
Mar 31, 2014 10:41:58 PM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@3fa99295: startup date [Mon Mar 31 22:41:58 PDT 2014]; root of context hierarchy
كما يمكنك أن ترى أنه للتوصيل التلقائي بالاسم وبالنوع، يُستخدم المنشئ الافتراضي بدون وسائط لتهيئة الكائن. بالنسبة للتوصيل التلقائي بواسطة المنشئ، يُستخدم المنشئ القائم على الوسائط. من رمز التجزئة لجميع المتغيرات، لقد أكدنا أن جميع كائنات الربيع مختلفة ولا تشير إلى نفس الكائن. بما أننا أزلنا “employee1” من قائمة الكائنات المؤهلة للتوصيل التلقائي، لم تكن هناك أي حيرة في تعيين الكائن. إذا قمنا بإزالة autowire-candidate="false"
من تعريف “employee1″، سنحصل على رسالة الخطأ التالية عند تنفيذ الطريقة الرئيسية المذكورة أعلاه.
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'employeeServiceByType' defined in class path resource [spring.xml]: Unsatisfied dependency expressed through bean property 'employee': : No qualifying bean of type [com.journaldev.spring.autowiring.model.Employee] is defined: expected single matching bean but found 2: employee,employee1; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.journaldev.spring.autowiring.model.Employee] is defined: expected single matching bean but found 2: employee,employee1
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1278)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1170)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.journaldev.spring.autowiring.main.SpringMain.main(SpringMain.java:12)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.journaldev.spring.autowiring.model.Employee] is defined: expected single matching bean but found 2: employee,employee1
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:967)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:855)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1263)
... 13 more
هذا كل شيء بخصوص توجيه @Autowired في الربيع وميزة التوصيل التلقائي في الربيع، يرجى تنزيل مشروع المثال من الرابط أدناه وتحليله لمعرفة المزيد.
Source:
https://www.digitalocean.com/community/tutorials/spring-autowired-annotation