הזרקת שעועית אב טיפוס למופע של סינגלטון באביב

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

במאמר מהיר זה נציג גישות שונות של הזרקת שעועית אב-טיפוס למופע יחיד. נדון במקרי השימוש וביתרונות / חסרונות של כל תרחיש.

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

כדי ללמוד עוד על היקפי שעועית, כתיבה זו היא מקום טוב להתחיל בו.

2. בעיה בהזרקת שעועית

כדי לתאר את הבעיה, בואו להגדיר את השעועית הבאה:

@Configuration מחלקה ציבורית AppConfig {@Bean @Scope (ConfigurableBeanFactory.SCOPE_PROTOTYPE) PrototypeBean prototypeBean () {להחזיר PrototypeBean חדש (); } @Bean ציבורי SingletonBean singletonBean () {להחזיר SingletonBean חדש (); }}

שימו לב שלשעועית הראשונה יש היקף אב-טיפוס, השנייה היא יחידנית.

עכשיו, בואו נזריק את השעועית המצופה באב-טיפוס לסינגל - ואז נחשוף אם באמצעות ה- getPrototypeBean () שיטה:

מעמד ציבורי SingletonBean {// .. @ PrototypeButowired פרטי PrototypeBean; ציבורי SingletonBean () {logger.info ("מופע Singleton נוצר"); } PrototypeBean ציבורי getPrototypeBean () {logger.info (String.valueOf (LocalTime.now ())); החזר prototypeBean; }}

ואז, בואו נטען את ה- ApplicationContext וקבל את שעועית הסינגלטון פעמיים:

ראשי ריק סטטי ציבורי (String [] args) זורק InterruptedException {AnnotationConfigApplicationContext context = AnnotationConfigApplicationContext חדש (AppConfig.class); SingletonBean firstSingleton = context.getBean (SingletonBean.class); PrototypeBean firstPrototype = firstSingleton.getPrototypeBean (); // קבל מופע שעועית של סינגלטון פעם נוספת SingletonBean secondSingleton = context.getBean (SingletonBean.class); PrototypeBean secondPrototype = secondSingleton.getPrototypeBean (); isTrue (firstPrototype.equals (secondPrototype), "יש להחזיר את אותו מופע"); }

הנה הפלט מהקונסולה:

שעועית סינגלטון יצרה אב טיפוס שעועית יצרה 11: 06: 57.894 // צריכה ליצור מופע שעועית אב טיפוס אחר כאן 11: 06: 58.895

שתי השעועית אותתו רק פעם אחת, בעת הפעלת הקשר היישום.

3. הזרקה ApplicationContext

אנחנו יכולים גם להזריק את ApplicationContext ישירות לשעועית.

כדי להשיג זאת, השתמש ב- @Autowire הערה או יישום ApplicationContextAware מִמְשָׁק:

מחלקה ציבורית SingletonAppContextBean מיישם את ApplicationContextAware {private ApplicationContext applicationContext; PrototypeBean ציבורי getPrototypeBean () {return applicationContext.getBean (PrototypeBean.class); } @Override public void setApplicationContext (ApplicationContext applicationContext) זורק BeansException {this.applicationContext = applicationContext; }}

בכל פעם שה- getPrototypeBean () שיטה נקראת, מופע חדש של PrototypeBean יוחזר מה- ApplicationContext.

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

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

4. הזרקת שיטה

דרך נוספת לפתור את הבעיה היא הזרקת שיטה עם ה- @הבט מעלה ביאור:

@Component class class SingletonLookupBean {@ Lookup public PrototypeBean getPrototypeBean () {return null; }}

האביב יעקוף את getPrototypeBean () שיטת הערה עם @הבט מעלה. לאחר מכן הוא רושם את השעועית להקשר היישום. בכל פעם שאנו מבקשים את getPrototypeBean () שיטה, זה מחזיר חדש PrototypeBean למשל.

הוא ישתמש ב- CGLIB כדי ליצור את קוד הביץ ' אחראי להביא את PrototypeBean מהקשר היישום.

5. javax.inject ממשק API

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

הנה שעועית הסינגלטון:

סוג ציבורי SingletonProviderBean {@ ספק פרטי מאושר myPrototypeBeanProvider; PrototypeBean public getPrototypeInstance () {return myPrototypeBeanProvider.get (); }}

אנו משתמשים ספקמִמְשָׁק להזריק את שעועית האב טיפוס. לכל אחד getPrototypeInstance () שיחת שיטה, myPrototypeBeanProvider.זet () השיטה מחזירה מופע חדש של PrototypeBean.

6. פרוקסי סקופ

כברירת מחדל, Spring מחזיק בהתייחסות לאובייקט האמיתי לביצוע ההזרקה. כאן, אנו יוצרים אובייקט פרוקסי כדי לחבר את האובייקט האמיתי עם התלוי.

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

כדי להגדיר זאת, אנו משנים את ה- Appconfig בכיתה להוסיף חדש @תְחוּם ביאור:

@Scope (value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)

כברירת מחדל, Spring משתמש בספריית CGLIB כדי לסווג ישירות את האובייקטים. כדי למנוע שימוש ב- CGLIB, אנו יכולים להגדיר את מצב ה- proxy באמצעות ScopedProxyMode.ממשקים, להשתמש במקום זאת ב- proxy הדינמי של JDK.

7. ObjectFactory מִמְשָׁק

Spring מספק את ממשק ObjectFactory כדי לייצר אובייקטים מהסוג הנתון לפי דרישה:

מעמד ציבורי SingletonObjectFactoryBean {@Autowired פרטי ObjectFactory אב טיפוס BeanObjectFactory; PrototypeBean public getPrototypeInstance () {return prototypeBeanObjectFactory.getObject (); }}

בואו נסתכל על getPrototypeInstance () שיטה; getObject () מחזיר מופע חדש לגמרי של PrototypeBean לכל בקשה. כאן, יש לנו שליטה רבה יותר על אתחול האב-טיפוס.

וגם ה ObjectFactory הוא חלק מהמסגרת; המשמעות היא הימנעות מהתקנה נוספת על מנת להשתמש באפשרות זו.

8. צור שעועית בזמן ריצה באמצעות java.util.Function

אפשרות נוספת היא ליצור מופעי שעועית אב-טיפוס בזמן ריצה, מה שמאפשר לנו גם להוסיף פרמטרים למופעים.

כדי לראות דוגמה לכך, בואו להוסיף שדה שם ל PrototypeBean מעמד:

Class public PrototypeBean {שם מחרוזת פרטי; PrototypeBean ציבורי (שם מחרוזת) {this.name = שם; logger.info ("מופע אב טיפוס" + שם + "נוצר"); } // ...}

לאחר מכן, נזריק מפעל שעועית לפולי הסינגלטון שלנו על ידי שימוש ב- java.util.Function מִמְשָׁק:

כיתה ציבורית SingletonFunctionBean {@ פונקציה פרטית אוטומטית beanFactory; PrototypeBean ציבורי getPrototypeInstance (שם מחרוזת) {PrototypeBean שעועית = beanFactory.apply (שם); שעועית להחזיר; }}

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

@Configuration מחלקה ציבורית AppConfig {@Bean Function Function beanFactory () {return name -> prototypeBeanWithParam (name); } @Bean @Scope (value = "prototype") PrototypeBean prototypeBeanWithParam (שם מחרוזת) {להחזיר PrototypeBean חדש (שם); } @Bean ציבורי SingletonFunctionBean singletonFunctionBean () {להחזיר SingletonFunctionBean חדש (); } // ...}

9. בדיקות

בואו נכתוב כעת מבחן JUnit פשוט לשימוש איתו ObjectFactory מִמְשָׁק:

@Test הציבור בטל givenPrototypeInjection_WhenObjectFactory_ThenNewInstanceReturn () {AbstractApplicationContext context = AnnotationConfigApplicationContext חדש (AppConfig.class); SingletonObjectFactoryBean firstContext = context.getBean (SingletonObjectFactoryBean.class); SingletonObjectFactoryBean secondContext = context.getBean (SingletonObjectFactoryBean.class); PrototypeBean firstInstance = firstContext.getPrototypeInstance (); PrototypeBean secondInstance = secondContext.getPrototypeInstance (); assertTrue ("מופע חדש צפוי", FirstInstance! = secondInstance); }

לאחר השקת הבדיקה בהצלחה, אנו יכולים לראות זאת בכל פעם getPrototypeInstance () שיטה שנקראת, נוצר מופע שעועית חדש של אב-טיפוס.

10. מסקנה

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

כמו תמיד, ניתן למצוא את הקוד המלא עבור הדרכה זו בפרויקט GitHub.