דוגמה לשימוש בהזנה של Guice Dependency Injection של Google

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

<dependency>
	<groupId>com.google.inject</groupId>
	<artifactId>guice</artifactId>
	<version>3.0</version>
</dependency>

אם יש לך אפליקציה פשוטה ב-Java, אז ניתן להוריד את קובץ ה-JAR מ-דף הבית של גוגל גויס בקוד של גוגל. שים לב שבמקרה זה תצטרך גם להכליל את התלות המשתנות שלו ב-Classpath אחרת יש לך עיתון בזמן הריצה. עבור הדוגמה שלי, יש לי פרויקט Maven שמבנה הפרויקט שלו נראה כמו בתמונה למטה. בואו נסתכל על כל אחד מהרכיבים בנפרד.

סוגי שירות

package com.journaldev.di.services;

public interface MessageService {

	boolean sendMessage(String msg, String receipient);
}

MessageService מספק את הקריאה הבסיסית לשירותים.

package com.journaldev.di.services;

import javax.inject.Singleton;

//import com.google.inject.Singleton;

@Singleton
public class EmailService implements MessageService {

	public boolean sendMessage(String msg, String receipient) {
		//some fancy code to send email
		System.out.println("Email Message sent to "+receipient+" with message="+msg);
		return true;
	}

}

EmailService הוא אחד מהמימושים של MessageService. שימו לב שהמחלקה סומנה עם הערת @Singleton. מאחר ואובייקטי השירות ייווצרו דרך מחלקות האינג'קטור, ניתנה הערה זו כדי להודיע להם שסוגי השירות צריכים להיות אובייקטים יחידים. Google Guice 3.0 הוסיף תמיכה ב-JSR-330 ואנו יכולים להשתמש בהערות מהחבילות com.google.inject או javax.inject. נניח שיש לנו גם מימוש נוסף של שירות לשליחת הודעות בפייסבוק.

package com.journaldev.di.services;

import javax.inject.Singleton;

//import com.google.inject.Singleton;

@Singleton
public class FacebookService implements MessageService {

	public boolean sendMessage(String msg, String receipient) {
		//some complex code to send Facebook message
		System.out.println("Message sent to Facebook user "+receipient+" with message="+msg);
		return true;
	}

}

מחלקת צרכן

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

package com.journaldev.di.consumer;

import javax.inject.Inject;

//import com.google.inject.Inject;
import com.journaldev.di.services.MessageService;

public class MyApplication {

	private MessageService service;
	
// בסיס הכנסת בנאי
// @Inject
// public MyApplication(MessageService svc){
//		this.service=svc;
//	}
	
	// בנאי על ידי שימוש בקבוע
	@Inject
	public void setService(MessageService svc){
		this.service=svc;
	}
	
	public boolean sendMessage(String msg, String rec){
		// עסקאות עסקיות כאן
		return service.sendMessage(msg, rec);
	}
}

שים לב שהערך אותו ציינתי עבור הכנסת בנאי מבוטל, זה מועיל כאשר היישום שלך מספק גם תכונות אחרות שאינן דורשות אובייקט של מחלקת השירות. גם שים לב להערה @Injector זה ישמש את Google Guice להזרקת מחלקת היישום של השירות. אם אינך מודע להערות, תבדוק את המדריך להערות ה-Java java annotations tutorial.

קישור למימוש שירות

ברור כי Google Guice לא יודע לאיזו שירות להשתמש, עלינו להגדיר אותו על ידי הרחבת AbstractModule כיתה מופשטת ולספק מימוש לשיטה configure().

package com.journaldev.di.injector;

import com.google.inject.AbstractModule;
import com.journaldev.di.services.EmailService;
import com.journaldev.di.services.FacebookService;
import com.journaldev.di.services.MessageService;

public class AppInjector extends AbstractModule {

	@Override
	protected void configure() {
		// חייב את השירות למימוש הכיתה
		//bind(MessageService.class).to(EmailService.class);
		
		// חביר את MessageService למימוש ההודעה בפייסבוק
		bind(MessageService.class).to(FacebookService.class);
		
	}

}

כפי שאתה רואה, אנו יכולים לקשור כל מימוש למחלקת שירות. לדוגמה, אם נרצה לשנות ל-EmailService, יהיה עלינו רק לשנות את הקישורים.

יישום לקוח

ההגדרה שלנו מוכנה, בואו נראה איך להשתמש בה עם כיתה פשוטה ב-Java.

package com.journaldev.di.test;

import com.google.inject.Guice;
import com.google.inject.Injector;

import com.journaldev.di.consumer.MyApplication;
import com.journaldev.di.injector.AppInjector;

public class ClientApplication {

	public static void main(String[] args) {
		Injector injector = Guice.createInjector(new AppInjector());		
		
		MyApplication app = injector.getInstance(MyApplication.class);
		
		app.sendMessage("Hi Pankaj", "[email protected]");
	}

}

המימוש קל להבנה. אנו צריכים ליצור אובייקט Injector באמצעות המתודה createInjector() של מחלקת Guice, שבה נעביר אובייקט המימוש של מחלקת ה-Injector שלנו. לאחר מכן, אנו משתמשים ב-Injector כדי לאתחל את מחלקת הצרכן שלנו. אם נפעיל את הכיתה לעיל, היא תפיק פלט הבא.

Message sent to Facebook user [email protected] with message=Hi Pankaj

אם נשנה את הקישורים ל-EmailService במחלקת AppInjector, זה יפיק את הפלט הבא.

Email Message sent to [email protected] with message=Hi Pankaj

מבחני יחידה JUnit

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

package com.journaldev.di.services;

public class MockMessageService implements MessageService{

	public boolean sendMessage(String msg, String receipient) {
		return true;
	}

}

המחלקה שלי לבדיקות JUnit 4 נראית כך.

package com.journaldev.di.test;


import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.journaldev.di.consumer.MyApplication;
import com.journaldev.di.services.MessageService;
import com.journaldev.di.services.MockMessageService;

public class MyApplicationTest {

	private Injector injector;
	
	@Before
	public void setUp() throws Exception {
		injector = Guice.createInjector(new AbstractModule() {
			
			@Override
			protected void configure() {
				bind(MessageService.class).to(MockMessageService.class);
			}
		});
	}

	@After
	public void tearDown() throws Exception {
		injector = null;
	}

	@Test
	public void test() {
		MyApplication appTest = injector.getInstance(MyApplication.class);
		Assert.assertEquals(true, appTest.sendMessage("Hi Pankaj", "[email protected]"));;
	}

}

שים לב שאני קושר את מחלקת MockMessageService למחלקת MessageService על ידי ביצוע יישום של מחלקה אנונימית של AbstractModule. זה נעשה בשיטה setUp() שרצה לפני שיטות הבדיקה.

הורד את פרויקט Google Guice

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

Source:
https://www.digitalocean.com/community/tutorials/google-guice-dependency-injection-example-tutorial