JavaRush /مدونة جافا /Random-AR /رحلة قصيرة إلى حقن التبعية أو "ما هو CDI أيضًا؟"
Viacheslav
مستوى

رحلة قصيرة إلى حقن التبعية أو "ما هو CDI أيضًا؟"

نشرت في المجموعة
الأساس الذي تم بناء الأطر الأكثر شيوعًا عليه الآن هو حقن التبعية. أقترح النظر في ما تقوله مواصفات CDI حول هذا الأمر، وما هي القدرات الأساسية التي لدينا وكيف يمكننا استخدامها.
رحلة قصيرة إلى حقن التبعية أو

مقدمة

أود أن أخصص هذه المراجعة القصيرة لشيء مثل CDI. ما هذا؟ يرمز CDI إلى السياقات وحقن التبعية. هذه هي مواصفات Java EE التي تصف حقن التبعية والسياقات. للحصول على معلومات، يمكنك إلقاء نظرة على الموقع http://cdi-spec.org . نظرًا لأن CDI عبارة عن مواصفات (وصف لكيفية عملها، ومجموعة من الواجهات)، فسنحتاج أيضًا إلى تطبيق لاستخدامها. أحد هذه التطبيقات هو Weld - http://weld.cdi-spec.org/ لإدارة التبعيات وإنشاء مشروع، سنستخدم Maven - https://maven.apache.org إذن، لقد قمنا بتثبيت Maven، والآن نحن سوف نفهم ذلك عمليا، حتى لا نفهم الملخص. للقيام بذلك، سنقوم بإنشاء مشروع باستخدام Maven. لنفتح سطر الأوامر (في Windows، يمكنك استخدام Win+R لفتح نافذة "Run" وتنفيذ cmd) ونطلب من Maven القيام بكل شيء من أجلنا. لهذا، لدى Maven مفهوم يسمى النموذج الأصلي: Maven Archetype .
رحلة قصيرة إلى حقن التبعية أو
بعد ذلك، بالنسبة للأسئلة " اختر رقمًا أو قم بتطبيق عامل التصفية " و" اختر org.apache.maven.archetypes:maven-archetype-quickstart version "، ما عليك سوى الضغط على Enter. بعد ذلك، أدخل معرفات المشروع، ما يسمى GAV (راجع دليل اتفاقية التسمية ).
رحلة قصيرة إلى حقن التبعية أو
بعد الإنشاء الناجح للمشروع، سنرى النقش "BUILD SUCCESS". الآن يمكننا فتح مشروعنا في IDE المفضل لدينا.

إضافة CDI إلى المشروع

في المقدمة، رأينا أن CDI لديها موقع ويب مثير للاهتمام - http://www.cdi-spec.org/ . يوجد قسم التحميل والذي يحتوي على جدول يحتوي على البيانات التي نحتاجها:
رحلة قصيرة إلى حقن التبعية أو
هنا يمكننا أن نرى كيف يصف Maven حقيقة أننا نستخدم CDI API في المشروع. API هي واجهة برمجة التطبيقات، أي بعض واجهات البرمجة. نحن نعمل مع الواجهة دون القلق بشأن ماذا وكيف يعمل خلف هذه الواجهة. واجهة برمجة التطبيقات عبارة عن أرشيف جرة سنبدأ في استخدامه في مشروعنا، أي أن مشروعنا يبدأ في الاعتماد على هذه الجرة. ولذلك، فإن CDI API لمشروعنا هو تبعية. في Maven، يتم وصف المشروع في ملفات POM.xml ( POM - Project Object Model ). يتم وصف التبعيات في كتلة التبعيات، والتي نحتاج إلى إضافة إدخال جديد إليها:
<dependency>
	<groupId>javax.enterprise</groupId>
	<artifactId>cdi-api</artifactId>
	<version>2.0</version>
</dependency>
وكما لاحظت، فإننا لا نحدد النطاق بالقيمة المقدمة. لم يوجد مثل هذا الاختلاف؟ يعني هذا النطاق أن شخصًا ما سيزودنا بالتبعية. عند تشغيل تطبيق ما على خادم Java EE، فهذا يعني أن الخادم سيزود التطبيق بجميع تقنيات JEE الضرورية. ومن أجل تبسيط هذه المراجعة، سنعمل في بيئة Java SE، وبالتالي لن يزودنا أحد بهذه التبعية. يمكنك قراءة المزيد عن نطاق التبعية هنا: " نطاق التبعية ". حسنًا، لدينا الآن القدرة على العمل مع الواجهات. ولكننا نحتاج أيضا إلى التنفيذ. كما نتذكر، سوف نستخدم اللحام. ومن المثير للاهتمام أنه يتم إعطاء تبعيات مختلفة في كل مكان. لكننا سنتبع الوثائق. لذلك، دعونا نقرأ " 18.4.5. إعداد Classpath " ونفعل كما يلي:
<dependency>
	<groupId>org.jboss.weld.se</groupId>
	<artifactId>weld-se-core</artifactId>
	<version>3.0.5.Final</version>
</dependency>
من المهم أن تدعم إصدارات السطر الثالث من Weld CDI 2.0. لذلك، يمكننا الاعتماد على API لهذا الإصدار. الآن نحن على استعداد لكتابة التعليمات البرمجية.
رحلة قصيرة إلى حقن التبعية أو

تهيئة حاوية CDI

CDI هي آلية. يجب على شخص ما التحكم في هذه الآلية. كما قرأنا بالفعل أعلاه، مثل هذا المدير هو حاوية. لذلك، نحن بحاجة إلى إنشائه، فهو نفسه لن يظهر في بيئة SE. دعنا نضيف ما يلي إلى طريقتنا الرئيسية:
public static void main(String[] args) {
	SeContainerInitializer initializer = SeContainerInitializer.newInstance();
	initializer.addPackages(App.class.getPackage());
	SeContainer container = initializer.initialize();
}
لقد أنشأنا حاوية CDI يدويًا لأن... نحن نعمل في بيئة SE. في المشاريع القتالية النموذجية، يتم تشغيل الكود على خادم يوفر تقنيات مختلفة للكود. وبناء على ذلك، إذا كان الخادم يوفر CDI، فهذا يعني أن الخادم لديه بالفعل حاوية CDI ولن نحتاج إلى إضافة أي شيء. ولكن لأغراض هذا البرنامج التعليمي، سنأخذ بيئة SE. بالإضافة إلى ذلك، الحاوية موجودة هنا بشكل واضح ومفهوم. لماذا نحتاج إلى حاوية؟ تحتوي الحاوية الموجودة بالداخل على حبوب (حبوب CDI).
رحلة قصيرة إلى حقن التبعية أو

حبوب سي دي آي

لذلك، الفول. ما هو صندوق CDI؟ هذه فئة Java تتبع بعض القواعد. تم وصف هذه القواعد في المواصفات في الفصل " 2.2. ما هي أنواع الفاصوليا؟ ". لنقم بإضافة حبة CDI إلى نفس الحزمة مثل فئة التطبيق:
public class Logger {
    public void print(String message) {
        System.out.println(message);
    }
}
الآن يمكننا أن نسمي هذه الحبة من mainطريقتنا:
Logger logger = container.select(Logger.class).get();
logger.print("Hello, World!");
كما ترون، لم نقم بإنشاء الحبة باستخدام الكلمة الأساسية الجديدة. لقد سألنا حاوية CDI: "حاوية CDI. أحتاج حقًا إلى مثيل لفئة المسجل، أعطني إياه من فضلك." تسمى هذه الطريقة " البحث عن التبعيات "، أي البحث عن التبعيات. الآن لنقم بإنشاء فئة جديدة:
public class DateSource {
    public String getDate() {
        return new Date().toString();
    }
}
فئة بدائية تقوم بإرجاع تمثيل نصي للتاريخ. دعونا الآن نضيف إخراج التاريخ إلى الرسالة:
public class Logger {
    @Inject
    private DateSource dateSource;

    public void print(String message) {
        System.out.println(dateSource.getDate() + " : " + message);
    }
}
لقد ظهر تعليق توضيحي مثير للاهتمام @Inject. كما هو مذكور في الفصل " 4.1. نقاط الحقن " في وثائق اللحام cdi، باستخدام هذا التعليق التوضيحي، نحدد نقطة الحقن. في اللغة الروسية، يمكن قراءة هذا على أنه "نقاط التنفيذ". يتم استخدامها بواسطة حاوية CDI لحقن التبعيات عند إنشاء مثيل للفاصوليا. كما ترون، نحن لا نقوم بتعيين أي قيم لحقل مصدر التاريخ. والسبب في ذلك هو حقيقة أن حاوية CDI تسمح داخل حبوب CDI (فقط تلك الحبوب التي تم إنشاؤها بنفسها، أي التي تديرها) باستخدام " حقن التبعية ". هذه طريقة أخرى لعكس التحكم ، وهي طريقة يتم فيها التحكم في التبعية بواسطة شخص آخر بدلاً من قيامنا بإنشاء الكائنات بشكل صريح. يمكن إجراء حقن التبعية من خلال طريقة أو مُنشئ أو حقل. لمزيد من التفاصيل، راجع فصل مواصفات CDI " 5.5. حقن التبعية ". يسمى الإجراء الخاص بتحديد ما يجب تنفيذه بالتحليل الآمن للنوع، وهو ما نحتاج إلى التحدث عنه.
رحلة قصيرة إلى حقن التبعية أو

تحليل الاسم أو تحليل Typesafe

عادةً، يتم استخدام الواجهة كنوع الكائن المطلوب تنفيذه، وتحدد حاوية CDI نفسها التنفيذ الذي سيتم اختياره. وهذا مفيد لعدة أسباب سنناقشها. لذلك لدينا واجهة المسجل:
public interface Logger {
    void print(String message);
}
ويقول أنه إذا كان لدينا بعض المسجل، فيمكننا إرسال رسالة إليه وسوف يكمل مهمته - السجل. كيف وأين لن يكون ذا أهمية في هذه الحالة. لنقم الآن بإنشاء تطبيق للمسجل:
public class SystemOutLogger implements Logger {
    @Inject
    private DateSource dateSource;

    public void print(String message) {
        System.out.println(message);
    }
}
كما ترون، هذا هو المسجل الذي يكتب إلى System.out. رائع. الآن، ستعمل طريقتنا الرئيسية كما كانت من قبل. Logger logger = container.select(Logger.class).get(); سيظل المُسجل يستقبل هذا الخط. والجميل هو أننا نحتاج فقط إلى معرفة الواجهة، وحاوية CDI تفكر بالفعل في التنفيذ بالنسبة لنا. لنفترض أن لدينا تطبيقًا ثانيًا من المفترض أن يرسل السجل إلى مكان ما إلى وحدة تخزين بعيدة:
public class NetworkLogger implements Logger {
    @Override
    public void print(String message) {
        System.out.println("Send log message to remote log system");
    }
}
إذا قمنا الآن بتشغيل الكود الخاص بنا دون تغييرات، فسوف نحصل على خطأ، لأنه ترى حاوية CDI تطبيقين للواجهة ولا يمكنها الاختيار بينهما: org.jboss.weld.exceptions.AmbiguousResolutionException: WELD-001335: Ambiguous dependencies for type Logger ماذا تفعل؟ هناك العديد من الاختلافات المتاحة. أبسطها هو التعليق التوضيحي @Vetoed لفاصوليا CDI بحيث لا ترى حاوية CDI هذه الفئة على أنها حبة CDI. ولكن هناك نهج أكثر إثارة للاهتمام. يمكن وضع علامة على حبة CDI على أنها "بديلة" باستخدام التعليق التوضيحي @Alternativeالموضح في الفصل " 4.7. البدائل " من وثائق Weld CDI. ماذا يعني ذلك؟ وهذا يعني أنه ما لم نقول صراحة لاستخدامه، فلن يتم اختياره. هذه نسخة بديلة من الفول. لنضع علامة على حبة NetworkLogger على أنها @Alternative ويمكننا أن نرى أنه تم تنفيذ التعليمات البرمجية مرة أخرى واستخدامها بواسطة SystemOutLogger. لتمكين البديل، يجب أن يكون لدينا ملف Beans.xml . قد يطرح السؤال: " Beans.xml، أين أضعك؟ " لذلك، دعونا نضع الملف بشكل صحيح:
رحلة قصيرة إلى حقن التبعية أو
بمجرد حصولنا على هذا الملف، سيتم تسمية القطعة الأثرية التي تحتوي على الكود الخاص بنا بـ " Explicit Bean archive ". الآن لدينا تكوينان منفصلان: البرنامج وXML. المشكلة هي أنهم سوف يقومون بتحميل نفس البيانات. على سبيل المثال، سيتم تحميل تعريف حبة DataSource مرتين وسيتعطل برنامجنا عند تنفيذه، لأن ستعتبرهما حاوية CDI حبتين منفصلتين (على الرغم من أنهما في الواقع من نفس الفئة التي تعلمتها حاوية CDI مرتين). لتجنب ذلك هناك خياران:
  • أزل السطر initializer.addPackages(App.class.getPackage())وأضف إشارة إلى البديل لملف xml:
<beans
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://xmlns.jcp.org/xml/ns/javaee
        http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd">
    <alternatives>
        <class>ru.javarush.NetworkLogger</class>
    </alternatives>
</beans>
  • أضف سمة bean-discovery-modeبالقيمة " لا شيء " إلى عنصر جذر الفاصوليا وحدد بديلاً برمجيًا:
initializer.addPackages(App.class.getPackage());
initializer.selectAlternatives(NetworkLogger.class);
وبالتالي، باستخدام بديل CDI، يمكن للحاوية تحديد الحبة التي سيتم تحديدها. ومن المثير للاهتمام، إذا كانت حاوية CDI تعرف عدة بدائل لنفس الواجهة، فيمكننا معرفة ذلك من خلال الإشارة إلى الأولوية باستخدام تعليق توضيحي @Priority(منذ CDI 1.1).
رحلة قصيرة إلى حقن التبعية أو

التصفيات

بشكل منفصل، يجدر مناقشة شيء مثل التصفيات. تتم الإشارة إلى المؤهل من خلال تعليق توضيحي أعلى الحبة ويحسن البحث عن الحبة. والآن مزيد من التفاصيل. ومن المثير للاهتمام أن أي حبة CDI في أي حال تحتوي على مؤهل واحد على الأقل - @Any. إذا لم نحدد أي مؤهل أعلى الحبة، ولكن بعد ذلك تضيف حاوية CDI نفسها @Anyمؤهلاً آخر إلى المؤهل - @Default. إذا قمنا بتحديد أي شيء (على سبيل المثال، حدد @Any بشكل صريح)، فلن تتم إضافة المؤهل @Default تلقائيًا. لكن جمال التصفيات هو أنه يمكنك إنشاء مؤهلاتك الخاصة. لا يختلف المؤهل تقريبًا عن التعليقات التوضيحية، لأنه في جوهرها، هذا مجرد تعليق توضيحي مكتوب بطريقة خاصة. على سبيل المثال، يمكنك إدخال Enum لنوع البروتوكول:
public enum ProtocolType {
    HTTP, HTTPS
}
بعد ذلك يمكننا إجراء مؤهل يأخذ هذا النوع في الاعتبار:
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface Protocol {
    ProtocolType value();
    @Nonbinding String comment() default "";
}
ومن الجدير بالذكر أن الحقول التي تم وضع علامة عليها @Nonbindingلا تؤثر على تحديد المؤهل. الآن أنت بحاجة إلى تحديد المؤهل. تمت الإشارة إليه أعلى نوع الحبة (بحيث يعرف CDI كيفية تعريفه) وفوق نقطة الحقن (مع التعليق التوضيحيInject، حتى تتمكن من فهم الحبة التي تبحث عنها للحقن في هذا المكان). على سبيل المثال، يمكننا إضافة فئة ما مع مؤهل. للتبسيط، في هذه المقالة سنقوم بذلك داخل NetworkLogger:
public interface Sender {
	void send(byte[] data);
}

@Protocol(ProtocolType.HTTP)
public static class HTTPSender implements Sender{
	public void send(byte[] data) {
		System.out.println("sended via HTTP");
	}
}

@Protocol(ProtocolType.HTTPS)
public static class HTTPSSender implements Sender{
	public void send(byte[] data) {
		System.out.println("sended via HTTPS");
	}
}
وبعد ذلك عندما نقوم بإجراء Inject، سنحدد مؤهلًا سيؤثر على الفئة التي سيتم استخدامها:
@Inject
@Protocol(ProtocolType.HTTPS)
private Sender sender;
عظيم، أليس كذلك؟) يبدو جميلا، ولكن السبب غير واضح. الآن تخيل ما يلي:
Protocol protocol = new Protocol() {
	@Override
	public Class<? extends Annotation> annotationType() {
		return Protocol.class;
	}
	@Override
	public ProtocolType value() {
		String value = "HTTP";
		return ProtocolType.valueOf(value);
	}
};
container.select(NetworkLogger.Sender.class, protocol).get().send(null);
بهذه الطريقة يمكننا تجاوز الحصول على القيمة بحيث يمكن حسابها ديناميكيًا. على سبيل المثال، يمكن أن تؤخذ من بعض الإعدادات. بعد ذلك يمكننا تغيير التنفيذ بسرعة، دون إعادة ترجمة أو إعادة تشغيل البرنامج/الخادم. يصبح الأمر أكثر إثارة للاهتمام، أليس كذلك؟ )
رحلة قصيرة إلى حقن التبعية أو

المنتجين

ميزة أخرى مفيدة لـ CDI هي المنتجين. هذه طرق خاصة (يتم تمييزها بتعليق توضيحي خاص) يتم استدعاؤها عندما تطلب بعض الحبوب حقن التبعية. مزيد من التفاصيل موضحة في الوثائق، في القسم " 2.2.3. طرق المنتج ". أبسط مثال:
@Produces
public Integer getRandomNumber() {
	return new Random().nextInt(100);
}
الآن، عند الحقن في حقول من النوع Integer، سيتم استدعاء هذه الطريقة والحصول على قيمة منها. هنا يجب أن نفهم على الفور أنه عندما نرى الكلمة الرئيسية جديدة، يجب أن نفهم على الفور أن هذه ليست حبة CDI. وهذا يعني أن مثيل الفئة Random لن يصبح حبة CDI لمجرد أنه مشتق من شيء يتحكم في حاوية CDI (في هذه الحالة، المنتج).
رحلة قصيرة إلى حقن التبعية أو

اعتراضية

المعترضات هي اعتراضات "تتدخل" في العمل. في CDI يتم ذلك بشكل واضح تمامًا. دعونا نرى كيف يمكننا القيام بالتسجيل باستخدام المترجمين الفوريين (أو المعترضين). أولاً، نحتاج إلى وصف الارتباط بالمعترض. مثل أشياء كثيرة، يتم ذلك باستخدام التعليقات التوضيحية:
@Inherited
@InterceptorBinding
@Target({TYPE, METHOD})
@Retention(RUNTIME)
public @interface ConsoleLog {
}
الشيء الرئيسي هنا هو أن هذا رابط للمعترض ( @InterceptorBinding)، والذي سيتم توريثه بواسطة الامتدادات ( @InterceptorBinding). الآن دعونا نكتب المعترض نفسه:
@Interceptor
@ConsoleLog
public class LogInterceptor {
    @AroundInvoke
    public Object log(InvocationContext ic) throws Exception {
        System.out.println("Invocation method: " + ic.getMethod().getName());
        return ic.proceed();
    }
}
يمكنك قراءة المزيد حول كيفية كتابة المعترضات في المثال من المواصفات: " 1.3.6. مثال المعترض ". حسنًا، كل ما علينا فعله هو تشغيل المُعترض. للقيام بذلك، حدد التعليق التوضيحي الملزم أعلى الطريقة التي يتم تنفيذها:
@ConsoleLog
public void print(String message) {
والآن تفاصيل أخرى مهمة جدًا. يتم تعطيل أدوات الاعتراض بشكل افتراضي ويجب تمكينها بنفس طريقة تمكين البدائل. على سبيل المثال، في ملف Beans.xml :
<interceptors>
	<class>ru.javarush.LogInterceptor</class>
</interceptors>
كما ترون، الأمر بسيط للغاية.
رحلة قصيرة إلى حقن التبعية أو

الأحداث والمراقبون

يوفر CDI أيضًا نموذجًا للأحداث والمراقبين. هنا كل شيء ليس واضحًا كما هو الحال مع المعترضات. لذلك، يمكن أن يكون الحدث في هذه الحالة أي فئة على الإطلاق، ولا حاجة إلى أي شيء خاص للوصف. على سبيل المثال:
public class LogEvent {
    Date date = new Date();
    public String getDate() {
        return date.toString();
    }
}
الآن يجب على شخص ما انتظار الحدث:
public class LogEventListener {
    public void logEvent(@Observes LogEvent event){
        System.out.println("Message Date: " + event.getDate());
    }
}
الشيء الرئيسي هنا هو تحديد التعليق التوضيحيObserves، الذي يشير إلى أن هذه ليست مجرد طريقة، ولكنها طريقة يجب استدعاؤها كنتيجة لملاحظة أحداث من نوع LogEvent. حسنًا، نحتاج الآن إلى شخص سيراقب:
public class LogObserver {
    @Inject
    private Event<LogEvent> event;
    public void observe(LogEvent logEvent) {
        event.fire(logEvent);
    }
}
لدينا طريقة واحدة تخبر الحاوية بحدوث حدث حدث لنوع الحدث LogEvent. الآن كل ما تبقى هو استخدام المراقب. على سبيل المثال، في NetworkLogger يمكننا إضافة جزء من مراقبنا:
@Inject
private LogObserver observer;
وفي طريقة الطباعة يمكننا إعلام المراقب بوجود حدث جديد:
public void print(String message) {
	observer.observe(new LogEvent());
من المهم معرفة أنه يمكن معالجة الأحداث في موضوع واحد أو في عدة موضوعات. للمعالجة غير المتزامنة، استخدم طريقة .fireAsync(بدلاً من .fire) وتعليقًا توضيحيًا @ObservesAsync(بدلاً من @Observes). على سبيل المثال، إذا تم تنفيذ جميع الأحداث في سلاسل رسائل مختلفة، فإذا قام مؤشر ترابط واحد بطرح استثناء، فسيتمكن الآخرون من القيام بعملهم لأحداث أخرى. يمكنك قراءة المزيد عن الأحداث في CDI، كالعادة، في المواصفات، في الفصل " 10. الأحداث ".
رحلة قصيرة إلى حقن التبعية أو

مصممو الديكور

كما رأينا أعلاه، يتم جمع أنماط التصميم المختلفة تحت جناح CDI. وهنا واحد آخر - مصمم ديكور. هذا شيء مثير للاهتمام للغاية. دعونا نلقي نظرة على هذا الصف:
@Decorator
public abstract class LoggerDecorator implements Logger {
    public final static String ANSI_GREEN = "\u001B[32m";
    public static final String ANSI_RESET = "\u001B[0m";

    @Inject
    @Delegate
    private Logger delegate;

    @Override
    public void print(String message) {
        delegate.print(ANSI_GREEN + message + ANSI_RESET);
    }
}
من خلال إعلانها كمصمم ديكور، نقول أنه عند استخدام أي تطبيق Logger، سيتم استخدام هذه "الوظيفة الإضافية"، التي تعرف التنفيذ الحقيقي، والتي يتم تخزينها في حقل المفوض (حيث يتم تمييزها بالتعليق التوضيحي @Delegate). لا يمكن ربط أدوات الديكور إلا بفاصوليا CDI، والتي في حد ذاتها ليست أداة اعتراضية ولا أداة تزيين. يمكن أيضًا رؤية مثال في المواصفات: " 1.3.7. مثال على الديكور ". يجب تشغيل الديكور، مثل المعترض. على سبيل المثال، في Beans.xml :
<decorators>
	<class>ru.javarush.LoggerDecorator</class>
</decorators>
لمزيد من التفاصيل، راجع مرجع اللحام: " الفصل العاشر. أدوات الديكور ".

دورة الحياة

الفاصوليا لها دورة حياتها الخاصة. يبدو شيء من هذا القبيل:
رحلة قصيرة إلى حقن التبعية أو
كما ترون من الصورة، لدينا ما يسمى عمليات الاسترجاعات لدورة الحياة. هذه هي التعليقات التوضيحية التي ستخبر حاوية CDI باستدعاء طرق معينة في مرحلة معينة من دورة حياة الحبة. على سبيل المثال:
@PostConstruct
public void init() {
	System.out.println("Inited");
}
سيتم استدعاء هذه الطريقة عندما يتم إنشاء مثيل لحبة CDI بواسطة حاوية. سيحدث الشيء نفسه معPreDestroy عندما يتم تدمير الحبة عندما لا تكون هناك حاجة إليها. ليس من قبيل الصدفة أن يحتوي اختصار CDI على الحرف C - السياق. تعتبر الفاصوليا الموجودة في CDI سياقية، مما يعني أن دورة حياتها تعتمد على السياق الذي توجد فيه داخل حاوية CDI. لفهم هذا بشكل أفضل، يجب عليك قراءة قسم المواصفات " 7. دورة حياة الحالات السياقية ". ومن الجدير أيضًا معرفة أن الحاوية نفسها لها دورة حياة، والتي يمكنك القراءة عنها في " أحداث دورة حياة الحاوية ".
رحلة قصيرة إلى حقن التبعية أو

المجموع

أعلاه نظرنا إلى قمة جبل الجليد المسمى CDI. يعد CDI جزءًا من مواصفات JEE ويستخدم في بيئة JavaEE. أولئك الذين يستخدمون Spring لا يستخدمون CDI، ولكن DI، أي أن هذه مواصفات مختلفة قليلاً. لكن بمعرفة وفهم ما ورد أعلاه، يمكنك بسهولة تغيير رأيك. مع الأخذ في الاعتبار أن Spring يدعم التعليقات التوضيحية من عالم CDI (نفس الحقن). مواد إضافية: # فياتشيسلاف
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION