النموذج الأولي IOC الربيع
النقطة الأساسية والنقطة الأساسية لإطار الربيع هي بلا شك IOC. نظرًا لأن التكنولوجيا الأساسية التي توفرها حاويات Spring ، فقد أكملت IOC بنجاح انعكاس التبعيات: من الإدارة النشطة للفئة الرئيسية على التبعيات إلى السيطرة العالمية على التبعيات عن طريق حاويات الربيع.
ما هي فوائد القيام بذلك؟
بطبيعة الحال ، فإن ما يسمى بـ "فك الارتباط" ، والذي يمكن أن يجعل العلاقة بين وحدات البرنامج أكثر استقلالية. يحتاج Spring فقط إلى التحكم في التبعيات بين هذه الوحدات وإنشاء هذه الوحدات وإدارتها وصيانتها بناءً على هذه التبعيات أثناء بدء تشغيل الحاوية وعملية التهيئة. إذا كنت بحاجة إلى تغيير التبعيات بين الوحدات ، فأنت لا تحتاج حتى إلى تغيير رمز البرنامج. تحتاج فقط إلى تعديل التبعيات المتغيرة. سوف يعيد Spring تأسيس هذه التبعيات الجديدة في عملية بدء وتهيئة الحاوية مرة أخرى. في هذه العملية ، من الضروري ملاحظة أن الكود نفسه لا يحتاج إلى تعكس إعلان حالة التبعية المحددة للوحدة ولكن يحتاج فقط إلى تحديد واجهة الوحدة النمطية المطلوبة. لذلك ، هذه فكرة نموذجية موجهة نحو الواجهة. في الوقت نفسه ، من الأفضل التعبير عن التبعيات في شكل ملفات التكوين أو التعليقات التوضيحية. ستقوم فئات معالجة الربيع ذات الصلة بتجميع الوحدات النمطية بناءً على ملفات التكوين الخارجية هذه ، أو مسح التعليق التوضيحي للاتصال بمعالج التعليقات التوضيحية الداخلية لتجميع الوحدات النمطية لإكمال عملية اللجنة الأولمبية الدولية.
الغرض من IOC هو حقن التبعية تسمى DI. من خلال تقنية IOC ، ستساعدنا الحاوية النهائية في إكمال حقن التبعية بين الوحدات النمطية.
بالإضافة إلى ذلك ، فإن النقطة الأخيرة هي أنه في عملية الربيع IOC ، يجب أن نكون دائمًا واضحين بشأن الخط الرئيسي أعلاه. بغض النظر عن مدى تعقيد بناء الجملة في الوقت الفعلي وهيكل الفئة ، فإن وظيفتها والغرض منها هي نفسها: إنها إكمال "التجميع" للوحدة من خلال الاعتماد على ملف التكوين الموصوف مثل "الرسم" التجميع. بناء الجملة المعقد هو مجرد وسيلة لإنجاز هذا الغرض.
ما يسمى النموذج الأولي IOC ، من أجل إظهار أبسط مخطط تخطيطي IOC ، قد نقوم أيضًا بعمل نموذج أولي بسيط تمامًا لتوضيح هذه العملية:
أولاً ، هناك العديد من الوحدات النمطية التي نحددها ، بما في ذلك الوحدة الرئيسية ووحدة التبعية المحددة في الواجهتين:
الفئة mainmodule {private reparmodulea modulea ؛ reparmoduleb الخاص بوحدة. public reparmodulea getModulea () {return modulea ؛ } public void setModulea (compmodulea modulea) {this.modulea = modulea ؛ } public reparmoduleb getModuleB () {return moduleb ؛ } public void setModuleB (reparModuleB moduleb) {this.moduleb = moduleb ؛ }} واجهة repplymodulea {public void funcfromdulea () ؛} واجهة reparmoduleb {public void funcfrommulb () ؛} class class reparmoduleaimpl تنفذ compmodulea {Override public funcfromdulea () {system.out.println (" }} class reparmodulebimpl تنفذ reparmoduleb {Override public void funcfrommulb () {system.out.println ("هذا هو func من الوحدة B") ؛ }}إذا لم نعتمد IOC ، لكننا نعتمد على الوحدة الرئيسية نفسها للتحكم في إنشاء الوحدة النمطية التابعة لها ، فسيكون الأمر هكذا:
الطبقة العامة SimpleiOcdemo {public static void main (string [] args) remrows ClassNotFoundException {mainModule mainModule = new MainModule () ؛ mainmodule.setModulea (new reparmoduleaimpl ()) ؛ mainmodule.setModuleB (new reparModuleBimpl ()) ؛ mainmodule.getModulea (). funcfrommodea () ؛ mainmodule.getModuleB (). funcfrommulb () ؛ }}هذا هو تعريفنا المبسط للنموذج الأولي للحاوية IOC. عند تهيئة الحاوية بعد بدء التشغيل ، ستقرأ ملف التكوين الذي كتبه المستخدم. هنا نأخذ ملف تكوين الخصائص البسيطة كمثال. فقط عندما يقوم المستخدم باستدعاء طريقة getBean ، سيتم تجميع الحبة المقابلة وتحميلها حقًا وفقًا لملف التكوين. يتم الحفاظ على الخريطة المستخدمة لحفظ الفاصوليا المجمعة داخل النموذج الأولي للحاوية التي حددناها. إذا كان هناك حبة تلبي المتطلبات ، فلن تحتاج إلى إنشاء مرة أخرى:
class simpleioccontainer {private properties properties = new properties () ؛ الخريطة الخاصة <string ، Object> modulemap = new HashMap <> () ؛ {try {properties.load (جديد fileInputStream (ملف جديد ("SimpleiOC.Properties"))) ؛ } catch (استثناء e) {E.PrintStackTrace () ؛ }} الكائن العام getBean (سلسلة modulename) يلقي classnotfoundException {object extleoBj ؛ if (modulemap.get (modulename)! = null) {system.out.println ("return Old Bean") ؛ إرجاع modulemap.get (Modulename) ؛ } system.out.println ("إنشاء فول جديد") ؛ String fullClassName = properties.getProperty (Modulename) ؛ if (fullClassName == null) رمي classnotfoundException () جديدة ؛ آخر {class <؟ يمتد الكائن> clazz = class.forname (fullClassName) ؛ حاول {eastyObj = clazz.newinstance () ؛ eChateObj = buildattachedModules (Modulename ، extorlyObj) ؛ modulemap.put (Modulename ، extorlyObj) ؛ إرجاع almateObj ؛ } catch (InstantiationException e) {e.printStackTrace () ؛ } catch (alfictAccessException e) {e.printStackTrace () ؛ }} الإرجاع null ؛ } كائن خاص buildattachedModules (سلسلة modulename ، Object extorlyObj) {set <string> propertiesKeys = properties.StringPropertyNames () ؛ Field [] fields = eChateObj.getClass (). getDeclaredFields () ؛ لـ (مفتاح السلسلة: propertieskeys) {if (key.contains (modulename) &&! key.equals (modulename)) {try {class <؟ يمتد الكائن> clazz = class.forname (properties.getProperty (properties.getProperty (key))) ؛ لـ (حقل الحقل: الحقول) {if (field.gettype (). isAsassignableFrom (clazz)) field.set (eChateObj ، clazz.newinstance ()) ؛ }} catch (استثناء e) {E.PrintStackTrace () ؛ }}} return extlyObj ؛ }}هذا هو ملف تكوين التبعية الذي كتبناه باستخدام ملف تكوين الخصائص. ملف التكوين هذا هو "رسم" وحدة التجميع الخاصة بنا. يتم تعريف بناء الجملة هنا تمامًا من قبلنا. في حاوية IOC في الربيع الحقيقي ، من أجل التعبير عن منطق التبعية الأكثر تعقيدًا ، سيتم استخدام ملف تكوين تنسيق XML أكثر تطوراً أو تكوين التعليق التوضيحي الأحدث ، وسيتم استخدام معالج التعليقات التوضيحية لإكمال تحليل الرسم:
mainModule = com.rocking.demo.mainmodulemainmodule.modulea = moduleAmainModule.ModuleB = modulebmodulea = com.rocking.demo.dependmoduleaimplmoduleb = com.rocking.demo.dependmodulebimpl
هذا هو رمز الاختبار. يمكن ملاحظة أنه يمكننا الحصول على وحدات تفي بالمتطلبات تمامًا من خلال حاوية IOC التي حددناها. في الوقت نفسه ، يمكننا أيضًا أن نجد أن الحاوية التي حددناها يمكنها الحفاظ على هذه الفاصوليا بالنسبة لنا. عندما يتم تجميع الفول وإنشائه ، لا يلزم إنشاءه مرة أخرى.
الطبقة العامة SimpleiOcdemo {public static void main (string [] args) remrows ClassNotFoundException {simpleioContainer Container = new SimpleIoCcontainer () ؛ reparmodulea modulea = (compmodulea) container.getBean ("modulea") ؛ modulea.funcfrommodea () ؛ reparmoduleb moduleb = (compmoduleb) container.getBean ("moduleb") ؛ moduleb.funcfrommbuleb () ؛ MainModule MainModule = (MainModule) Container.getBean ("MainModule") ؛ mainmodule.getModulea (). funcfrommodea () ؛ mainmodule.getModuleB (). funcfrommulb () ؛ Container.getBean ("MainModule") ؛ }}هذا هو النموذج الأولي للحاوية IOC التي قمت بإنشائها بناءً على الفكرة الأساسية لـ IOC. على الرغم من أن SPRING IOC لديها بناء جملة معقدة ، فإن المهام المكتملة في النهاية هي نفسها في قلبها ، ما يسمى "جميع التغييرات لن يتم فصلها عن جوهرها".
عملية محددة في الربيع IOC
في المرة الأخيرة ، تم عرض النموذج الأولي للتنفيذ العام لـ IOC. إذن ، كيفية تنفيذ عملية تحميل POJOs على وجه التحديد في إطار الربيع لهذه الحاوية استنادًا إلى تكوين معلومات التعريف البيانات الوصفية؟ هناك العديد من الأماكن في عملية عمل حاوية IOC بأكملها التي تم تصميمها لتكون مرنة تمامًا ، مما يوفر للمستخدمين مساحة كبيرة لإكمال مهامهم الخاصة ، بدلاً من مجرد إكمال العملية الميكانيكية للحاوية.
هذا هو مخطط العملية لعملية عمل حاوية IOC بأكملها:
1. مرحلة بدء تشغيل الحاوية (1) معلومات ملف تكوين التحميل (2) تحليل معلومات ملف التكوين (3) تجميع الفاصوليا
(4) بعد المعالجة أولاً ، يتم تحميل معلومات تلوي مثل ملفات التكوين أو التعليقات التوضيحية ومعلومات فئة Javabean في حاوية IOC. تقرأ الحاوية ملف تكوين XML-Format. ملف التكوين هذا هو التبعية التي أعلنها المستخدم والتجميع الذي يحتاج إلى عناية خاصة. إنه "رسم خارجي" مبكر لتجميع الفول. يمكن لمحرك التحليل في الحاوية تحليل المعلومات الوصفية للحرف في نموذج النص الذي نكتبه في التعريف الفاصولي الذي يمكن التعرف عليه داخل الحاوية ، والتي يمكن أن تفهم التعريف. يصبح بنية الطبقة مماثلة لآلية الانعكاس. يحصل هذا الفاصوليا التي تم الحصول عليها من خلال تحليل ملفات Javabeans وتكوينه على الهيكل الأساسي لتجميع جافابان يلبي المتطلبات. إذا كنت بحاجة إلى تعديل التعريف الفول بالإضافة إلى التعريف الفاصولي ، يتم تنفيذ هذه المعالجة بعد المعالجة. تتم معالجة ما بعد المعالجة بشكل عام من خلال معالج BeanFactoryPostProcessor في إطار الربيع.
ما زلنا نستخدم الأمثلة التي استخدمناها في المرة الأخيرة لتوضيح مبدأ التشغيل لهذا التعريف الفاصول: هناك ثلاثة حبوب ، وحدات MainModule الرئيسية للوحدة الرئيسية ووحدات التبعية CERMODMODULEA و compmoduleb. السابق يعتمد على الوحدة الأخيرة. في ملف التكوين ، نعلن عمومًا تبعيات مثل هذا:
<؟ XSI: schemalocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <edious mainmodule "> </swerperal> <property name = "moduleb"> <ref bean = "moduleb"/> </preperty> </bean> <bean id = "modulea"> </bean> <bean id = "moduleb"> </bean> </beans>
هذا هو برنامجنا الذي يوضح تجميع حاوية Beanfactory القياسية (أحد تطبيقات حاويات IOC الربيعية) إلى ملف التكوين أعلاه:
الفئة mainmodule {private reparmodulea modulea ؛ reparmoduleb الخاص بوحدة. public reparmodulea getModulea () {return modulea ؛ } public void setModulea (compmodulea modulea) {this.modulea = modulea ؛ } public reparmoduleb getModuleB () {return moduleb ؛ } public void setModuleB (reparModuleB moduleb) {this.moduleb = moduleb ؛ }} واجهة repplymodulea {public void funcfromdulea () ؛} واجهة reparmoduleb {public void funcfrommulb () ؛} class class reparmoduleaimpl تنفذ compmodulea {Override public funcfromdulea () {system.out.println (" }} class reparmodulebimpl تنفذ reparmoduleb {Override public void funcfrommulb () {system.out.println ("هذا هو func من الوحدة B") ؛ }} الفئة العامة simpleiocdemo {public static void main (string [] args) remsnotfoundException {defaultListableBeanFactory Beanfactory = new DefaultListableBeanFactory () ؛ XmlBeanDefinitionReader Reader = New XmlBeanDefinitionReader (BeanFactory) ؛ reader.loadBeanDefinitions ("beans.xml") ؛ mainmodule mainmodule = (mainmodule) beanfactory.getBean ("mainmodule") ؛ mainmodule.getModulea (). funcfrommodea () ؛ mainmodule.getModuleB (). funcfrommulb () ؛ }}هنا يتم تحميل ملف التكوين لدينا وجافابان وقراءته وتوحله. هنا يتم إخفاء عملية توليد الفاصوليا والاستخدام فيها. هذه هي العملية العامة التي تحدث بالفعل داخل اللجنة الأولمبية الدولية:
الطبقة العامة SimpleiOcdemo {public static void main (string [] args) يلقي classnotfoundException {defaultListableBeanfactory Beanfactory = جديد defaultListableBeanFactory () ؛ AbstractBeanDefinition MainModule = جديد RootBeanDefinition (mainmodule.class) ؛ AbstractBeanDefinition modulea = new RootBeanDefinition (reparmoduleaiMpl.Class) ؛ AbstractBeanDefinition moduleb = new RootBeanDefinition (reparmodulebimpl.class) ؛ beanfactory.registerBeanDefinition ("mainmodule" ، mainmodule) ؛ Beanfactory.registerBeanDefinition ("Modulea" ، Modulea) ؛ beanfactory.registerBeanDefinition ("moduleb" ، moduleb) ؛ propertyPropertyValues propertyValues = new MutablePropertyValues () ؛ PropertyValues.Add ("Modulea" ، Modulea) ؛ PropertyValues.Add ("moduleb" ، moduleb) ؛ MainModule.SetPropertyValues (PropertyValues) ؛ MainModule Module = (MainModule) beanfactory.getBean ("MainModule") ؛ module.getModulea (). funcfrommodea () ؛ module.getModuleB (). funcfrommulb () ؛ }}بعد تحميل وقراءة معلومات التعريف الخاصة بـ XML ، سيقوم محرك تحليل IOC بإنشاء الوحدة النمطية المذكورة فيه في تعريف الفاصوليا بناءً على نوعه الحقيقي. يمكن اعتبار هذا التعريف الفاصوليا عملية انعكاس أو وكيل. والغرض من ذلك هو توضيح حاوية IOC من بنية الفاصوليا لكائن المثيل المراد إنشاؤه في المستقبل ، ثم تسجيل هياكل الفاصوليا هذه في الفاصوليا ، ثم إضافة تبعيات الوحدة الرئيسية إلى خصائص الوحدة الرئيسية في شكل الفاصلة بالفعل على السحبة ". شكل. بعد ذلك ، ما عليك سوى الاتصال بالطريقة getBean لإنتاج الفاصوليا التي تلبي المتطلبات. هذه هي المرحلة التالية من العملية ، وسنتحدث عنها لاحقًا.
بعد تسجيل المعلومات حول "رسم" Beandefinition إلى Beanfactory ، لا يزال بإمكاننا إجراء تغييرات على التعريف الفاصوليات المسجل. هذا هو أحد الجوانب المرنة لتصميم الربيع للمستخدمين المذكورة سابقًا. هذا لا يعني أن جميع العمليات لا يمكن السيطرة عليها ، ولكنها تترك مجالًا كبيرًا للمستخدمين للعب في العديد من الأماكن. تتمثل الطريقة المحددة في استخدام Beanfactory Processor BeanfactoryPostProcessor للتدخل في معالجة Beanfactory لزيادة كتابة جزء Beandefinition الذي نحتاج إلى تعديله. تتوافق هذه العملية مع عملية "ما بعد المعالجة" في هذه العملية.
أخذ أحد المعالجات الشائعة: معالج تكوين العناصر النائبة السمة كمثال ، فهو لمعالجة الفاصوليا المسجلة بعد أن تم بناؤه ، بحيث يتم تعديل المحتويات في سمة التعريف المقابلة إلى المعلومات في ملف التكوين المحدد معالج التكوين:
defaultListableBeanfactory Beanfactory = جديد defaultListableBeanFactory () ؛ XmlBeanDefinitionReader Reader = جديد XmlBeanDefinTiveRearder (BeanFactory) ؛ reader.loadBeanDefinitions (classpathresource new ("beansml"))) propertyplaceholderConfigurer () ؛ configurer.setLocation (ClassPathResource جديد ("about.properties")) ؛ configurer.postProcessBeanfactory (BeanFactory) ؛سوف BeanfactoryPostProcessor المعالجة Beanfactory. والنتيجة هي تغيير بعض السمات المحددة في التعريف الفاصلة لبعض المعلومات في موقع BeanFactoryPostProcessor.
2. مرحلة تثبيت الفول
تحت إشراف "الرسومات الداخلية" المعالجة من التعريف الفاصولي ، يمكن للحاوية زيادة تحويل BeanDefiffnition إلى كائن مثيل منشط موجود في الذاكرة من خلال الانعكاس أو إنتاج CGLIB Bytecode ، ثم تجميع كائن التبعية المحدد عن طريق التعريف الفاصوليات في كائن مثيل تم إنشاؤه حديثًا من خلال حدوث حدوث في التهيئة. هنا ، يتم تعيين مرجع كائن التبعية فعليًا لسمات الكائنات التي يجب الاعتماد عليها.
ولكن تجدر الإشارة هنا إلى أن المثيل الذي تم إنشاؤه ليس مجرد مثيل بسيط لتعريف الفول ، ولكن مثيل BeanWrapper ملفوف بحلول الربيع. لماذا ينبغي استخدامها للف الفاصوليا في طريقة beanwrapper؟ لأن BeanWrapper يوفر واجهة للوصول إلى خصائص الفول بشكل موحد. بعد إنشاء إطار الفول الأساسي ، يجب ضبط الخصائص الموجودة فيه. تختلف طريقة Setter لكل فول ، لذلك ستكون معقدة للغاية إذا قمت بتعيينها مباشرة مع التفكير. لذلك ، يوفر Spring هذا الغلاف لتبسيط إعدادات الخصائص:
beanwrapper beanwrapper = new BeanWrapperImpl (class.forname ("com.rocking.demo.mainmodule")) ؛ beanwrapper.setPropertyValue ("modulea" ، class.forname ("com.Rocking.demo.depmoduleAimpl"). newInstance ()) ؛ class.forname ("com.rocking.demo.depmodulebimpl").تُظهر العملية أعلاه أنه في فصل الربيع ، يمكنك فهم بنية الحبة المثيل المغلفة في المستقبل من خلال الحصول على الحاوية العاكسة للفئة وصنع العبوة. استخدم طريقة إعداد الخصائص الموحدة SetPropertyValue لتعيين خصائص لمثيل هذه الحزمة. يتم الحصول على مثيل الفول النهائي الذي تم الحصول عليه من خلال getWrappedInstance ، ويمكنك أن تجد أن سماتها قد تم تعيينها بنجاح.
في هذا الوقت ، يكون مثيل Bean قابلاً للاستخدام تمامًا ، لكن Spring أعدت أيضًا استراتيجيات مرنة لنا في مرحلة التثبيت لإكمال تدخل المستخدم في هذه المرحلة. على غرار BeanfactoryPostProcessor Controcsister في مرحلة بدء تشغيل الحاويات ، خلال مرحلة التثبيت ، يوفر Spring معالج BeanpostProcessor للعمل على الحالات المجمعة لإكمال التغييرات المحتملة:
فيما يلي مثال لتوضيح أنك تحدد فئة تنفيذ BeanpostProcessor ، وتنفيذ الأساليب بعد المعالجة المعتادة والمعالجة بعد المعالجة لتحديد العمليات التي يتم إجراؤها بشكل منفصل بعد تجميع مثيل الفول وقبله. بعد أن يضيف Beanfactory هذا المعالج ، في كل مرة يتم تجميع طريقة getBean ، سيتم استدعاء الطريقتين في مثيل الفول الذي تم تجميعه وفقًا لـ "الرسم" (بما في ذلك الفاصوليا المعتمدة التي تم إنشاؤها أثناء عملية التجميع). يمكن لهذه الطرق تعديل هذه الحالات بين الفول.
فيما يلي مثال مثل هذا (MainModule وتبعياتها هي نفسها تلك الموجودة سابقًا في هذه المقالة):
فئة modulec {private string x ؛ السلسلة العامة getx () {return x ؛ } public void setx (String x) {this.x = x ؛ }} class modulepostprocessor تنفذ beanpostprocessor {Override الكائن العام postprocessafterinitialization (كائن كائن ، سلسلة السلسلة) يلقي beansexception {system.out.println (string) ؛ if (Object extryof modulec) {system.out.println (string) ؛ ((modulec) كائن) .setx ("بعد") ؛ } كائن الإرجاع ؛ } Override الكائن العام postprocessbeforeinitialization (كائن كائن ، سلسلة السلسلة) يلقي beansexception {if (Object extryof modulec) {((modulec) object) .setx ("قبل") ؛ } كائن الإرجاع ؛ }} الفئة العامة heatsimpleiockernal {public static void main (string [] args) remsnotfoundException ، beansexception ، instantiationException ، inchalcalAccessException {defaultListableBeanfactory beanfactory = new defaultBanbeanfactory () ؛ XmlBeanDefinitionReader Reader = New XmlBeanDefinitionReader (BeanFactory) ؛ reader.loadBeanDefinitions (classpathResource جديد ("beans.xml")) ؛ ModulePostProcessor postprocessor = New ModulePostProcessor () ؛ Beanfactory.AddBeanPostProcessor (postprocessor) ؛ MainModule Module = (MainModule) beanfactory.getBean ("MainModule") ؛ modulec modulec = (modulec) beanfactory.getBean ("modulec") ؛ system.out.println (modulec.getx ()) ؛ }}هذا هو ملف تكوين التبعية للفول:
<؟ XSI: schemalocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/spring http://www.springframework.org/schema/beans id = "mainmodule"> <property name = "modulea"> <ref bean = "modulea"/> </spleneration> <property name = "moduleb"> <ref bean = "moduleb"/> </propert id = "moduleb"> <property name = "infob"> <sualit> معلومات moduleb </value> </property> </bean> <bean id = "modulec"> </bean> </bans>
من النتيجة النهائية ، يمكننا أن نرى أنه في كل مرة سيتم استرداد مثيل getBean (بما في ذلك التبعية) التي تم الحصول عليها عن طريق استدعاء طريقة GetBean بواسطة BeanPostProcessor للمعالجة قبل وبعد المعالجة.
بالإضافة إلى معالجة الفاصوليا المجمعة المشابهة لبرنامج BeanPostProcessor أعلاه ، يمكن لـ Spring أيضًا تعيين وظائف رد الاتصال لعملية التهيئة والتدمير للفاصوليا من خلال تكوين الأساليب في البداية وتدمير الأساليب. يمكن أن توفر وظائف رد الاتصال هذه الفرصة بشكل مرن لتغيير مثيلات الفول.
إن عملية IOC الربيعية بأكملها هي في الواقع نفس النموذج الأولي لـ IOC التي كتبناها بأنفسنا ، باستثناء أن التصميم المعقد يسمح لعملية IOC بتزويد المستخدمين بمساحة أكثر مرونة وفعالية. بالإضافة إلى ذلك ، حققت IOC من Spring أيضًا تصميمًا رائعًا من حيث الأمان ، واستقرار الحاويات ، والبيانات الوصفية إلى كفاءة تحويل الفول ، مما يجعل أساس IOC ، حاوية زنبركية ، مستقرة.