ההבדל בין BeanFactory לבין ApplicationContext

1. סקירה כללית

מסגרת האביב מגיעה עם שני מכולות IOC - BeanFactory ו ApplicationContext. ה BeanFactory היא הגרסה הבסיסית ביותר של מכולות IOC, ו- ApplicationContext מרחיב את התכונות של BeanFactory.

במדריך מהיר זה נבין את ההבדלים המשמעותיים בין שני מיכלי ה- IOC הללו עם דוגמאות מעשיות.

2. טעינה עצלה לעומת העמסה נלהבת

BeanFactory טוען שעועית לפי דרישה, בעוד ApplicationContext טוען את כל השעועית בעת ההפעלה. לכן, BeanFactory הוא קל משקל לעומת ApplicationContext. בואו נבין את זה עם דוגמא.

2.1. טוען עצלן עם BeanFactory

נניח שיש לנו שיעור שעועית יחיד סטוּדֶנט בשיטה אחת:

תלמיד בכיתה ציבורית {בוליאני סטטי ציבורי isBeanInstantiated = false; public void postConstruct () {setBeanInstantiated (true); } // קובעי סטנדרטים וגטרים}

נגדיר את postConstruct () שיטה כמו שיטת init בשלנו BeanFactory קובץ תצורה, ioc-container-difference-example.xml:

עכשיו, בואו נכתוב מקרה מבחן שיוצר a BeanFactory כדי לבדוק אם הוא טוען את סטוּדֶנט אפונה:

@Test הציבור בטל כאשר BFInitialized_thenStudentNotInitialized () {Resource res = new ClassPathResource ("ioc-container-difference-example.xml"); מפעל BeanFactory = XmlBeanFactory חדש (res); assertFalse (Student.isBeanInstantiated ()); }

פה, ה סטוּדֶנט האובייקט אינו מאותחל. במילים אחרות, רק ה BeanFactory מאותחל. השעועית שהוגדרה אצלנו BeanFactory יוטען רק כאשר אנו קוראים במפורש ל- getBean () שיטה.

בואו נבדוק את האתחול של שלנו סטוּדֶנט שעועית במקום שאנחנו קוראים לו באופן ידני getBean () שיטה:

@ מבחן ציבורי בטל כאשר BFInitialized_thenStudentInitialized () {Resource res = new ClassPathResource ("ioc-container-difference-example.xml"); מפעל BeanFactory = XmlBeanFactory חדש (res); סטודנט סטודנט = (סטודנט) factory.getBean ("סטודנט"); assertTrue (Student.isBeanInstantiated ()); }

הנה ה סטוּדֶנט עומס שעועית בהצלחה. מכאן, ש BeanFactory טוען את השעועית רק כאשר היא נדרשת.

2.2. טוען להוט עם ApplicationContext

עכשיו, בואו נשתמש ApplicationContext במקום BeanFactory.

נגדיר רק ApplicationContext, והיא תטען את כל השעועית באופן מיידי באמצעות אסטרטגיית טעינה להוטה:

@ מבחן ציבורי בטל כאשר AppContInitialized_thenStudentInitialized () {ApplicationContext context = new ClassPathXmlApplicationContext ("ioc-container-difference-example.xml"); assertTrue (Student.isBeanInstantiated ()); }

הנה ה סטוּדֶנט האובייקט נוצר למרות שלא קראנו getBean () שיטה.

ApplicationContext נחשב למיכל IOC כבד מכיוון שאסטרטגיית הטעינה הלהוטה שלו טוענת את כל השעועית בעת ההפעלה. BeanFactory קל משוואה בהשוואה ויכול להיות שימושי במערכות מוגבלות זיכרון. על כל פנים, נראה בסעיפים הבאים מדוע ApplicationContext עדיף ברוב מקרי השימוש.

3. תכונות יישום ארגוני

ApplicationContext משפר BeanFactory בסגנון יותר ממוקד מסגרת ומספק מספר תכונות שמתאימות ליישומים ארגוניים.

למשל, זה מספק הודעות (i18n או בינלאומי) פונקציונליות, פרסום אירוע פונקציונליות, הזרקת תלות מבוססת ביאור, ו שילוב קל עם תכונות AOP של Spring.

מלבד זאת, ה ApplicationContext תומך כמעט בכל סוגי טווחי השעועית, אך ה- BeanFactory תומך רק בשני טווחים - קְלָף בּוֹדֵד ו אב טיפוס. לכן, תמיד עדיף להשתמש בו ApplicationContext כאשר בונים יישומים ארגוניים מורכבים.

4. רישום אוטומטי של BeanFactoryPostProcessor ו מעבד BeanPost

ה ApplicationContext נרשם אוטומטית BeanFactoryPostProcessor ו מעבד BeanPost בעת ההפעלה. מצד שני, ה BeanFactory אינו רושם ממשקים אלה באופן אוטומטי.

4.1. רישום ב BeanFactory

כדי להבין, בואו נכתוב שתי כיתות.

ראשית, יש לנו את CustomBeanFactoryPostProcessor בכיתה, המיישמת את BeanFactoryPostProcessor:

מחלקה ציבורית CustomBeanFactoryPostProcessor מיישמת BeanFactoryPostProcessor {בוליאני סטטי פרטי isBeanFactoryPostProcessorRegistered = false; @ Override public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) {setBeanFactoryPostProcessorRegistered (true); } // קובעי סטנדרטים וגטרים}

הנה, ביטלנו את postProcessBeanFactory () שיטה לבדוק את רישומה.

שנית, יש לנו שיעור אחר, CustomBeanPostProcessor, אשר מיישמת מעבד BeanPost:

מחלקה ציבורית CustomBeanPostProcessor מיישמת BeanPostProcessor {בוליאני סטטי פרטי isBeanPostProcessorRegistered = false; @Override אובייקט ציבורי postProcessBeforeInitialization (שעועית אובייקט, שם מחרוזת) {setBeanPostProcessorRegistered (true); שעועית להחזיר; } // קובעי סטנדרטים וגטרים}

הנה, ביטלנו את postProcessBeforeInitialization () שיטה לבדוק את רישומה.

כמו כן, הגדרנו את שני הכיתות שלנו ioc-container-difference-example.xml קובץ תצורה:

בואו נראה מקרה מבחן כדי לבדוק אם שתי המחלקות הללו נרשמות אוטומטית במהלך ההפעלה:

@ מבחן ציבורי בטל כאשר BFInitialized_thenBFPProcessorAndBPProcessorNotRegAutomatically () {Resource res = new ClassPathResource ("ioc-container-difference-example.xml"); ConfigurableListableBeanFactory מפעל = XmlBeanFactory חדש (res); assertFalse (CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered ()); assertFalse (CustomBeanPostProcessor.isBeanPostProcessorRegistered ()); }

כפי שאנו רואים מהבדיקה שלנו, רישום אוטומטי לא קרה.

עכשיו, בואו נראה מקרה מבחן שמוסיף אותם ידנית ב- BeanFactory:

@ מבחן ציבורי בטל כאשר BPFPProcessorAndBPProcessorRegisteredManually_thenReturnTrue () {Resource res = new ClassPathResource ("ioc-container-difference-example.xml"); ConfigurableListableBeanFactory מפעל = XmlBeanFactory חדש (res); CustomBeanFactoryPostProcessor beanFactoryPostProcessor = חדש CustomBeanFactoryPostProcessor (); beanFactoryPostProcessor.postProcessBeanFactory (מפעל); assertTrue (CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered ()); CustomBeanPostProcessor beanPostProcessor = CustomBeanPostProcessor חדש (); factory.addBeanPostProcessor (beanPostProcessor); סטודנט סטודנט = (סטודנט) factory.getBean ("סטודנט"); assertTrue (CustomBeanPostProcessor.isBeanPostProcessorRegistered ()); }

הנה, השתמשנו ב- postProcessBeanFactory () שיטה לרישום CustomBeanFactoryPostProcessor וה addBeanPostProcessor () שיטה לרישום CustomBeanPostProcessor. שניהם נרשמים בהצלחה במקרה זה.

4.2. רישום ב ApplicationContext

כפי שציינו קודם, ApplicationContext רושם את שתי השיעורים באופן אוטומטי מבלי לכתוב קוד נוסף.

בואו נאמת התנהגות זו במבחן יחידה:

@Test ציבורי בטל כאשרAppContInitialized_thenBFPostProcessorAndBPostProcessorRegisteredAutomatically () {ApplicationContext context = new ClassPathXmlApplicationContext ("ioc-container-difference-example.xml"); assertTrue (CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered ()); assertTrue (CustomBeanPostProcessor.isBeanPostProcessorRegistered ()); }

כמו שאנו יכולים לראות, ההרשמה האוטומטית של שני השיעורים מוצלחת במקרה הזה.

לָכֵן, תמיד מומלץ להשתמש ApplicationContext כי אביב 2.0 (ומעלה) משתמש בכבדות מעבד BeanPost.

ראוי גם לציין זאת אם אתה משתמש במישור BeanFactory, ואז תכונות כמו עסקאות ו- AOP לא ייכנסו לתוקף (לפחות לא בלי לכתוב שורות קוד נוספות). זה עלול להוביל לבלבול מכיוון ששום דבר לא ייראה לא בסדר בתצורה.

5. מסקנה

במאמר זה ראינו את ההבדלים העיקריים בין ApplicationContext ו BeanFactory עם דוגמאות מעשיות.

ה ApplicationContext מגיע עם תכונות מתקדמות, כולל כמה המיועדות ליישומים ארגוניים, בעוד ש- BeanFactory מגיע עם תכונות בסיסיות בלבד. לכן, בדרך כלל מומלץ להשתמש ב- ApplicationContext, ו עלינו להשתמש BeanFactory רק כאשר צריכת הזיכרון קריטית.

כמו תמיד, הקוד של המאמר זמין באתר GitHub.