Google Guice依赖注入示例教程

时间:2020-02-23 14:41:21  来源:igfitidea点击:

Google Guice是在应用程序中自动进行依赖项注入的框架。
如果您直接在这里遇到过,我建议您查看"依赖注入示例",在该示例中我们了解了传统对象创建方法的问题以及依赖注入的实现好处。

在上一教程中,我们学习了如何在应用程序中手动实现依赖项注入。
但是,当应用程序中的类数量增加时,最好寻找一些框架来自动完成此任务。

Google Guice是主要的框架之一,其主要工作是提供依赖关系注入的自动实现。
我们将与上一篇文章中的相同示例一起工作,并学习如何使用Google Guice自动执行依赖项注入的实现过程。

Google Guice依赖项在Maven Central上可用,因此对于Maven项目,您可以为其添加以下依赖项。

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

如果您有简单的Java应用程序,则可以从Google Code上的Google Guice主页下载jar文件。
请注意,在这种情况下,您还需要在类路径中具有传递依赖项,否则您将获得运行时异常。

对于我的示例,我有一个Maven项目,其项目结构如下图所示。

让我们逐一查看每个组件。

服务等级

package com.theitroad.di.services;

public interface MessageService {

	boolean sendMessage(String msg, String receipient);
}

MessageService接口提供服务的基本合同。

package com.theitroad.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包中的注释。

假设我们有另一种服务实现来发送Facebook消息。

package com.theitroad.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支持"基于setter"和"基于构造函数"的依赖注入。
我们使用该服务的应用程序类如下所示。

package com.theitroad.di.consumer;

import javax.inject.Inject;

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

public class MyApplication {

	private MessageService service;
	
//	constructor based injector
//	@Inject
//	public MyApplication(MessageService svc){
//		this.service=svc;
//	}
	
	//setter method injector
	@Inject
	public void setService(MessageService svc){
		this.service=svc;
	}
	
	public boolean sendMessage(String msg, String rec){
		//some business logic here
		return service.sendMessage(msg, rec);
	}
}

请注意,我已经注释了基于构造函数的注入的代码,当您的应用程序也提供不需要服务类对象的其他功能时,这将非常方便。

还要注意@Injector批注,Google Guice将使用它来注入服务实现类。
如果您不熟悉注释,请查看Java注释教程。

绑定服务实现

显然,谷歌guice不知道要使用哪种服务,我们必须通过扩展AbstractModule抽象类并对其进行配置来提供对configure()方法的实现。

package com.theitroad.di.injector;

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

public class AppInjector extends AbstractModule {

	@Override
	protected void configure() {
		//bind the service to implementation class
		//bind(MessageService.class).to(EmailService.class);
		
		//bind MessageService to Facebook Message implementation
		bind(MessageService.class).to(FacebookService.class);
		
	}

}

如您所见,我们可以将任何实现绑定到服务类。
例如,如果要更改为EmailService,则只需更改绑定。

客户申请

我们的设置已经准备就绪,让我们看看如何通过简单的Java类使用它。

package com.theitroad.di.test;

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

import com.theitroad.di.consumer.MyApplication;
import com.theitroad.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 hyman", "[email protected]");
	}

}

实现非常容易理解。
我们需要使用Guice类createInjector()方法创建" Injector"对象,并其中传递我们的注射器类实现对象。
然后,我们使用注入器初始化我们的消费者类。
如果我们在类上运行,它将产生以下输出。

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

如果我们在AppInjector类中将绑定更改为EmailService,则它将产生以下输出。

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

JUnit测试用例

由于我们要测试MyApplication类,因此不需要创建实际的服务实现。
我们可以有一个简单的Mock服务实现类,如下所示。

package com.theitroad.di.services;

public class MockMessageService implements MessageService{

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

}

我的JUnit 4测试类如下所示。

package com.theitroad.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.theitroad.di.consumer.MyApplication;
import com.theitroad.di.services.MessageService;
import com.theitroad.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 hyman", "[email protected]"));;
	}

}

注意,我通过使用AbstractModule的匿名类实现将MockMessageService类与MessageService绑定。
这是通过在测试方法之前运行的setUp()方法完成的。