מדריך לפרויקט מכונת מדינת אביב

1. הקדמה

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

2. תלות של Maven

כדי להתחיל, עלינו להוסיף את התלות העיקרית ב- Maven:

 org.springframework.statemachine spring-statemachine-core 1.2.3.RELEASE 

הגרסה האחרונה של תלות זו נמצאת כאן.

3. תצורת מכונת המדינה

עכשיו, נתחיל בהגדרת מכונת מדינה פשוטה:

המחלקה הציבורית @Configuration @EnableStateMachine SimpleStateMachineConfiguration מרחיב את StateMachineConfigurerAdapter {@Override confid public void (StateMachineStateConfigurer states) זורק Exception {states .withStates (). Initial ("SI") .end ("SF") .States (Hash. ("S1", "S2", "S3"))); } @ קביעת תצורה ריקה ציבורית של @Override (מעברי StateMachineTransitionConfigurer) זורק Exception {transitions.withExternal (). Source ("SI"). Target ("S1"). Event ("E1"). ו- () .withExternal (). Source (( "S1"). יעד ("S2"). אירוע ("E2") ו- () .withExternal () .source ("S2"). יעד ("SF"). אירוע ("סוף"); }}

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

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

כעת עלינו להתחיל בהקשר האביב ולקבל התייחסות למכונת המצב המוגדרת על ידי התצורה שלנו:

@ StateMachine פרטית אוטומטית stateMachine;

ברגע שיש לנו את מכונת המדינה, צריך להפעיל אותה:

stateMachine.start ();

כעת, כאשר המכונה שלנו נמצאת במצב ההתחלתי, אנו יכולים לשלוח אירועים וכך להפעיל מעברים:

stateMachine.sendEvent ("E1");

אנחנו תמיד יכולים לבדוק את המצב הנוכחי של מכונת המדינה:

stateMachine.getState ();

4. פעולות

בואו נוסיף כמה פעולות שיש לבצע סביב מעברי מדינה. ראשית, אנו מגדירים את הפעולה שלנו כפול שעועית באותו קובץ תצורה:

@Bean הפעולה הציבורית initAction () {להחזיר ctx -> System.out.println (ctx.getTarget (). GetId ()); }

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

הגדרת תצורה ריקה ציבורית של @Override (מעברי StateMachineTransitionConfigurer) זורקת Exception {transitions.withExternal () transitions.withExternal () .source ("SI"). Target ("S1"). Event ("E1"). Action (initAction ())

פעולה זו תבוצע בעת המעבר מ סִי ל S1 באמצעות אירוע E1 מתרחשת. ניתן לצרף פעולות למדינות עצמן:

@Bean Action Action executeAction () {return ctx -> System.out.println ("Do" + ctx.getTarget (). GetId ()); } מציין .withStates () .state ("S3", executeAction (), errorAction ());

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

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

@Bean פעולה פעולה errorAction () {להחזיר ctx -> System.out.println ("שגיאה" + ctx.getSource (). GetId () + ctx.getException ()); }

אפשר גם לרשום פעולות בודדות עבור כְּנִיסָה, לַעֲשׂוֹת ו יְצִיאָה מעברי מדינה:

@Bean Action actionAction () {return ctx -> System.out.println ("Entry" + ctx.getTarget (). GetId ()); } @Bean Action action executeAction () {return ctx -> System.out.println ("Do" + ctx.getTarget (). GetId ()); } @Bean פעולה ציבורית exitAction () {להחזיר ctx -> System.out.println ("יציאה" + ctx.getSource (). GetId () + "->" + ctx.getTarget (). GetId ()); }
מציין .withStates () .stateEntry ("S3", entryAction ()) .stateDo ("S3", executeAction ()) .stateExit ("S3", exitAction ());

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

5. מאזינים גלובליים

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

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

עלינו להגדיר מאזין על ידי הרחבה StateMachineListenerAdapter:

class class StateMachineListener מרחיב את StateMachineListenerAdapter {@ Override public void stateChanged (State from, State to) {System.out.printf ("עבר מ-% s ל-% s% n", מ- == null? "none": from.getId ( ), to.getId ()); }}

כאן רק הגדרנו stateChanged אם כי רבים אחרים אפילו ווים זמינים.

6. מדינה מורחבת

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

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

@Bean Action Action executeAction () {return ctx -> {int approvals = (int) ctx.getExtendedState (). GetVariables () .getOrDefault ("approvalCount", 0); אישורים ++; ctx.getExtendedState (). getVariables () .put ("approvalCount", אישורים); }; }

7. שומרים

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

@Bean המשמר הציבורי simpleGuard () {return ctx -> (int) ctx.getExtendedState () .getVariables () .getOrDefault ("approvalCount", 0)> 0; }

ההבדל הניכר כאן הוא ששומר מחזיר א נָכוֹן אוֹ שֶׁקֶר אשר יידע את מכונת המדינה האם יש לאפשר את המעבר להתרחש.

קיימת גם תמיכה בביטויי SPeL כשומרים. ניתן היה לכתוב את הדוגמה לעיל גם כ:

.guardExpression ("extendedState.variables.approvalCount> 0")

8. מכונת מדינה מבונה

StateMachineBuilder ניתן להשתמש כדי ליצור מכונת מדינה ללא שימוש בהערות אביב או יצירת הקשר אביב:

StateMachineBuilder.Builder builder = StateMachineBuilder.builder (); builder.configureStates (). withStates () .initial ("SI") .state ("S1"). end ("SF"); builder.configureTransitions () .withExternal () .source ("SI"). target ("S1"). event ("E1"). and (). withExternal (). source ("S1"). target ("SF "). אירוע (" E2 "); מכונת StateMachine = builder.build ();

9. מדינות היררכיות

ניתן להגדיר מצבים היררכיים באמצעות מספר רב של מצבים withStates () בשיתוף עם הוֹרֶה():

מציין .withStates () .initial ("SI") .state ("SI"). end ("SF"). ו- () .withStates (). parent ("SI") .initial ("SUB1"). state ("SUB2") .end ("SUBEND");

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

stateMachine.getState (). getIds () ["SI", "SUB1"]

10. צמתים (אפשרויות)

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

ראשית, עלינו לסמן מדינה צומת (בחירה) בהגדרת המצב:

מציין .withStates () .junction ("SJ")

ואז במעברים אנו מגדירים אפשרויות ראשונות / אחרונות / אחרונות המתאימות למבנה אם-אז-אחר:

.withJunction () .source ("SJ"). first ("high", highGuard ()) .then ("medium", mediumGuard ()). last ("low")

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

@Bean המשמר הציבורי mediumGuard () {return ctx -> false; } @Bean המשמר הציבורי highGuard () {return ctx -> false; }

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

בדוגמה שלעיל, הוראת מכונת המדינה לעבור ל- SJ תביא לכך שהמצב בפועל יהפוך נָמוּך כששני השומרים פשוט חוזרים כוזבים.

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

11. מזלג

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

ראשית, עלינו לייעד צומת כצומת מזלג וליצור אזורים היררכיים שלתוכם מכונת המדינה תבצע את הפיצול:

מציין .withStates () .initial ("SI") .fork ("SFork"). ו- () .withStates (). parent ("SFork"). initial ("Sub1-1") .end ("Sub1-2 "). ו- () .withStates (). parent (" SFork "). initial (" Sub2-1 ") .end (" Sub2-2 ");

ואז הגדיר מעבר מזלג:

.withFork () .source ("SFork") .target ("Sub1-1") .target ("Sub2-1");

12. הצטרפו

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

כמו במזלגות, עלינו לייעד צומת צירוף בהגדרת המצב:

קובע .withStates () .join ("SJoin")

ואז במעברים אנו מגדירים אילו מדינות צריכות להשלים כדי לאפשר את מצב ההצטרפות שלנו:

מעברים .withJoin () .source ("Sub1-2") .source ("Sub2-2") .target ("SJoin");

זהו זה! עם תצורה זו, כאשר שניהם משנה 1-2 ו Sub2-2 יושגו, מכונת המדינה תעבור ל הצטרף

13. Enums במקום מיתרים

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

ראשית, עלינו להגדיר את כל המצבים והאירועים האפשריים במערכת שלנו:

enum ציבור ApplicationReviewStates {PEER_REVIEW, PRINCIPAL_REVIEW, APPROVED, REJECTED} public enum ApplicationReviewEvents {APPROVE, REJECT}

עלינו להעביר את האנומות שלנו כפרמטרים גנריים כאשר אנו מרחיבים את התצורה:

מחלקה ציבורית SimpleEnumStateMachineConfiguration מרחיב את StateMachineConfigurerAdapter 

לאחר הגדרתנו, אנו יכולים להשתמש בקביעות האנום במקום במיתרים. לדוגמא להגדרת מעבר:

transitions.withExternal () .source (ApplicationReviewStates.PEER_REVIEW) .target (ApplicationReviewStates.PRINCIPAL_REVIEW). event (ApplicationReviewEvents.APPROVE)

14. מסקנה

מאמר זה בחן כמה מהתכונות של מכונת מדינת אביב.

כמו תמיד, אתה יכול למצוא את קוד המקור לדוגמה ב- GitHub.


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