מבוא לאביב עם עכה

1. הקדמה

במאמר זה אנו נתמקד בשילוב Akka עם Spring Framework - כדי לאפשר הזרקה של שירותים מבוססי אביב אל שחקני Akka.

לפני קריאת מאמר זה, מומלץ להכיר את היסודות של עכה.

2. הזרקת תלות בעכה

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

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

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

למרבה המזל, Akka מספק מנגנון, כלומר הרחבות Akka, שהופך את השימוש במסגרות הזרקת תלות חיצוניות למשימה די קלה.

3. תלות Maven

כדי להדגים את השימוש בעקה בפרויקט האביב שלנו, נצטרך תלות מינימלית באביב - אביב-הקשר הספריה, וגם אקא-שחקן סִפְרִיָה. ניתן לחלץ את גרסאות הספרייה אל החלק של פום:

 4.3.1.RELEASE 2.4.8 org.springframework spring-context $ {spring.version} com.typesafe.akka akka-actor_2.11 $ {akka.version} 

הקפד לבדוק את הגרסאות העדכניות ביותר של Maven Central אביב-הקשר ו אקא-שחקן תלות.

ושימו לב איך, כי אקא-שחקן לתלות יש _2.11 postfix על שמו, מה שמסמן שגרסה זו של Akka framework נבנתה כנגד גרסת Scala 2.11. הגרסה המתאימה של ספריית Scala תיכלל באופן מעברי בבניין שלך.

4. הזרקת שעועית אביבית לשחקני עכה

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

4.1. הגדרת שחקן ושירות

כדי להדגים הזרקת שירות לשחקן, ניצור שיעור פשוט GreetingActor מוגדר כשחקן לא קלד (הרחבת העקות UntypedActor כיתת בסיס). השיטה העיקרית של כל שחקן Akka היא על קבל שיטה המקבלת הודעה ומעבדת אותה על פי הגיון מוגדר כלשהו.

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

בוא נראה:

@Component @Scope (ConfigurableBeanFactory.SCOPE_PROTOTYPE) בכיתה ציבורית GreetingActor מרחיב את UntypedActor {private GreetingService greetingService; // constructor @ Override public void onReceive (הודעת אובייקט) זורק Throwable {if (message instance of Greet) {שם מחרוזת = ((Greet) הודעה) .getName (); getSender (). tell (greetingService.greet (שם), getSelf ()); } אחר {לא מטופל (הודעה); }} מחלקה סטטית ציבורית ברכה {פרטי מחרוזת שם; // קונסטרוקטורים / גטרים סטנדרטיים}}

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

שימו לב גם להערות האביב @רְכִיב ו @תְחוּם - אלה מגדירים את הכיתה כשעועית מנוהלת באביב עם אב טיפוס תְחוּם.

ההיקף חשוב מאוד מכיוון שכל בקשת אחזור שעועית אמורה לגרום למופע שנוצר לאחרונה, מכיוון שהתנהגות זו תואמת את מחזור חיי השחקן של עכה. אם אתה מיישם את השעועית הזו עם היקף אחר כלשהו, ​​ככל הנראה המקרה האופייני של הפעלה מחדש של שחקנים בעכה יתפקד בצורה לא נכונה.

לבסוף, שימו לב שלא היינו צריכים במפורש @Autowire ה GreetingService למשל - זה אפשרי בגלל התכונה החדשה של אביב 4.3 שנקראת הזרקת קונסטרוקטור מרומז.

ההטמעה של GreeterService הוא די פשוט, שים לב שהגדרנו אותו כשעועית מנוהלת באביב על ידי הוספת ה- @רְכִיב ביאור אליו (עם ברירת מחדל קְלָף בּוֹדֵד תְחוּם):

@ מחלקה ציבורית ברכיב GreetingService {ברכת מחרוזת ציבורית (שם מחרוזת) {החזרה "שלום" + שם; }}

4.2. הוספת תמיכה באביב באמצעות הרחבת Akka

הדרך הקלה ביותר לשלב את האביב עם עכה היא באמצעות הרחבה של עכו.

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

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

מחלקה ציבורית SpringExtension מורחבת AbstractExtensionId {גמר סטטי ציבורי ציבורי SpringExtension SPRING_EXTENSION_PROVIDER = SpringExtension חדש (); @Override ציבורי SpringExt createExtension (מערכת ExtendedActorSystem) {להחזיר SpringExt חדש (); } מחלקה סטטית ציבורית SpringExt מיישמת את הרחבה {private volatile ApplicationContext applicationContext; אתחול הריק הציבורי (ApplicationContext applicationContext) {this.applicationContext = applicationContext; } אביזרי Props ציבוריים (מחרוזת actorBeanName) {החזר Props.create (SpringActorProducer.class, applicationContext, actorBeanName); }}}

ראשוןSpringExtension מיישם סינגל createExtension שיטה מה- AbstractExtensionId מחלקה - המהווה יצירה של מופע הרחבה, SpringExt לְהִתְנַגֵד.

ה SpringExtension בכיתה יש גם שדה סטטי SPRING_EXTENSION_PROVIDER אשר מחזיקה התייחסות למופע היחיד שלה. לרוב הגיוני להוסיף קונסטרוקטור פרטי שיצהיר זאת במפורש SpringExtention אמור להיות שיעור יחיד, אבל נשמיט אותו לשם הבהירות.

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

במקרה שלנו, אנחנו נצטרך את לְאַתחֵל שיטה לשמירה על מעיין ApplicationContext מופע - שיטה זו תיקרא רק פעם אחת בכל אתחול ההרחבה.

כמו כן אנו נדרוש את אביזרים שיטה ליצירת אביזרים לְהִתְנַגֵד. אביזרים מופע הוא שרטוט של שחקן, ובמקרה שלנו אביזרים. ליצור השיטה מקבלת א SpringActorProducer טיעוני כיתה ובנאי עבור כיתה זו. אלה הטיעונים שאיתם ייקרא הבנאי של הכיתה הזו.

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

השלישי וחתיכת הפאזל האחרונה היא SpringActorProducer מעמד. זה מיישם את עכו IndirectActorProducer ממשק המאפשר לעקוף את תהליך המיידי לשחקן על ידי יישום ה- ליצר ו שחקן קלאס שיטות.

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

מחלקה ציבורית SpringActorProducer מיישם IndirectActorProducer {פרטי ApplicationContext applicationContext; פרטי מחרוזת beanActorName; ציבורי SpringActorProducer (ApplicationContext applicationContext, String beanActorName) {this.applicationContext = applicationContext; this.beanActorName = beanActorName; } @Override שחקן ציבורי מייצר () {return (שחקן) applicationContext.getBean (beanActorName); } @Override ציבור שחקנים בכיתה ClassClass () {return (Class) applicationContext .getType (beanActorName); }}

4.3. לשים את הכל ביחד

הדבר היחיד שנותר לעשות הוא ליצור מחלקת תצורה של אביב (מסומנת ב @תְצוּרָה הערה) שתגיד לאביב לסרוק את החבילה הנוכחית יחד עם כל החבילות המקוננות (זה מובטח על ידי @ComponentScan ביאור) וליצור מיכל אביב.

אנחנו רק צריכים להוסיף שעועית נוספת אחת - ה- מערכת שחקנים למשל - ואתחל את הרחבת האביב בנושא זה מערכת שחקנים:

@Configuration @ComponentScan מחלקה ציבורית AppConfiguration {@Autowired פרטי ApplicationContext applicationContext; @Bean ActorSystem ציבורית actorSystem () {ActorSystem system = ActorSystem.create ("akka-spring-demo"); SPRING_EXTENSION_PROVIDER.get (system) .initialize (applicationContext); מערכת החזרה; }}

4.4. אחזור שחקנים קווית-אביבית

כדי לבדוק שהכל עובד כראוי, אנו עשויים להזריק את מערכת שחקנים למשל בקוד שלנו (או איזה קוד יישום המנוהל על ידי Spring או מבחן מבוסס Spring), צור אביזרים אובייקט לשחקן המשתמש בסיומת שלנו, אחזר הפניה לשחקן באמצעות אביזרים התנגד ונסה לברך מישהו:

מברך ActorRef = system.actorOf (SPRING_EXTENSION_PROVIDER.get (system) .props ("greetingActor"), "greeter"); משך FiniteDuration = FiniteDuration.create (1, TimeUnit.SECONDS); פסק זמן לפסק זמן = פסק זמן.durationToTimeout (משך זמן); תוצאה עתידית = שאל (מברך, ברכה חדשה ("ג'ון"), פסק זמן); Assert.assertEquals ("שלום, ג'ון", Await.result (תוצאה, משך זמן));

כאן אנו משתמשים בטיפוסי akka.pattern.Patterns.ask דפוס המחזיר סקאלה עתיד למשל. לאחר השלמת החישוב, ה- עתיד נפתרת בערך שהחזרנו בו GreetingActor.onMessasge שיטה.

אנו עשויים לחכות לתוצאה על ידי יישום ה- Scala Await.result שיטה ל עתיד, או, עדיף, לבנות את היישום כולו עם דפוסים אסינכרוניים.

5. מסקנה

במאמר זה הראינו כיצד ניתן לשלב את Spring Framework עם Akka ו- שעועית אוטומטית בשחקנים.

קוד המקור של המאמר זמין ב- GitHub.


$config[zx-auto] not found$config[zx-overlay] not found