Google Guice依赖注入框架使用

Google Guice是一个轻量级依赖注入框架,和Spring类似。下面结合一些示例来讲解其使用方式。

首先引入maven依赖:

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

示例1:

package com.jingchenyong.boundless.guice.example2;

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

@Singleton
class HelloPrinter {
	public void print() {
		System.out.println("Hello, World!");
	}
}

@Singleton
public class Sample {

	@Inject
	private HelloPrinter printer;

	public void hello() {
		printer.print();
	}

	public static void main(String[] args) {
		Injector injector = Guice.createInjector();
		Sample sample1 = injector.getInstance(Sample.class);
		sample1.hello();
	}
}

Guice最常用的两个注解就是@Singleton和@Inject,前者表示构建的对象是单例的,后者表示被标注的字段将使用Guice自动注入。示例1中使用Guice创建了一个注射器injector,Guice会自动装配依赖树,然后通过getInstance()方法获取指定的类实例并运行。

如果不使用Singleton标注类,那么每次获取实例时,Guice会重新构造一个,增加性能损耗。如下示例2所示,在Sample类上取消了Singleton注解,那么每次injector.getInstance(Sample.class)调用获取的都是不同的实例(对象堆地址不同)。

示例2:

package com.jingchenyong.boundless.guice.example2;

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

@Singleton
class HelloPrinter {
	public void print() {
		System.out.println("Hello, World!");
	}
}

public class Sample {

	@Inject
	private HelloPrinter printer;

	public void hello() {
		printer.print();
	}

	public static void main(String[] args) {
		Injector injector = Guice.createInjector();
		Sample sample1 = injector.getInstance(Sample.class);
		System.out.println(sample1);
		Sample sample2 = injector.getInstance(Sample.class);
		System.out.println(sample2);
	}
}
// 运行结果:
com.jingchenyong.boundless.guice.example2.Sample@74650e52
com.jingchenyong.boundless.guice.example2.Sample@15d0c81b

当一个接口有多个实现时,可以通过@ImplementedBy注解指定接口的具体实现类(不太优雅)。

示例3:

package com.jingchenyong.boundless.guice.example3;

import com.google.inject.Guice;
import com.google.inject.ImplementedBy;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;

@ImplementedBy(ComplexHelloPrinter.class)
interface IHelloPrinter {
	void print();
}

@Singleton
class SimpleHelloPrinter implements IHelloPrinter {

	@Override
	public void print() {
		System.out.println("Hello, Simple World");
	}
}

@Singleton
class ComplexHelloPrinter implements IHelloPrinter {

	@Override
	public void print() {
		System.out.println("Hello, Complex World");
	}

}

@Singleton
public class Sample {

	@Inject
	private IHelloPrinter printer;

	public void hello() {
		printer.print();
	}

	public static void main(String[] args) {
		Injector injector = Guice.createInjector();
		Sample sample = injector.getInstance(Sample.class);
		sample.hello();
	}
}

// 运行结果
Hello, Complex World

为了解决在接口类上添加@ImplementedBy注解不优雅的方式,可以使用Guice Module定义装配规则,它相当于Spring的XML文件,只不过它的装配规则都是使用代码定义的。如下示例4所示:

示例4:

package com.jingchenyong.boundless.guice.example4;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;

interface IHelloPrinter {
	void print();
}

@Singleton
class SimpleHelloPrinter implements IHelloPrinter {

	@Override
	public void print() {
		System.out.println("Hello, Simple World");
	}
}

@Singleton
class ComplexHelloPrinter implements IHelloPrinter {

	@Override
	public void print() {
		System.out.println("Hello, Complex World");
	}
}

class SampleModule extends AbstractModule {

	@Override
	protected void configure() {
		bind(IHelloPrinter.class).to(SimpleHelloPrinter.class);
	}

}

public class Sample {
	@Inject
	private IHelloPrinter printer;

	public void hello() {
		printer.print();
	}

	public static void main(String[] args) {
		Injector injector = Guice.createInjector(new SampleModule());
		Sample sample = injector.getInstance(Sample.class);
		sample.hello();
	}
}

我们也可以使用@Named来指定依赖注入的实现(两种方式:字段注入和构造注入)

字段注入:

package com.jingchenyong.boundless.guice.example5;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

interface IHelloPrinter {
	void print();
}

@Singleton
class SimpleHelloPrinter implements IHelloPrinter {

	@Override
	public void print() {
		System.out.println("Hello, Simple World");
	}
}

@Singleton
class ComplexHelloPrinter implements IHelloPrinter {

	@Override
	public void print() {
		System.out.println("Hello, Complex World");
	}
}

class SampleModule extends AbstractModule {

	@Override
	protected void configure() {
		bind(IHelloPrinter.class).annotatedWith(Names.named("simple")).to(SimpleHelloPrinter.class);
		bind(IHelloPrinter.class).annotatedWith(Names.named("complex")).to(ComplexHelloPrinter.class);
	}

}

public class Sample {
	@Inject
	@Named("simple")
	private IHelloPrinter simplePrinter;
	
	@Inject
	@Named("complex")
	private IHelloPrinter complexPrinter;
	
	public void hello() {
		simplePrinter.print();
		complexPrinter.print();
	}
	public static void main(String[] args) {
		Injector injector = Guice.createInjector(new SampleModule());
		Sample sample = injector.getInstance(Sample.class);
		sample.hello();
	}
}

构造注入:

package com.jingchenyong.boundless.guice.example5;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

interface IHelloPrinter {
	void print();
}

@Singleton
class SimpleHelloPrinter implements IHelloPrinter {

	@Override
	public void print() {
		System.out.println("Hello, Simple World");
	}
}

@Singleton
class ComplexHelloPrinter implements IHelloPrinter {

	@Override
	public void print() {
		System.out.println("Hello, Complex World");
	}
}

class SampleModule extends AbstractModule {

	@Override
	protected void configure() {
		bind(IHelloPrinter.class).annotatedWith(Names.named("simple")).to(SimpleHelloPrinter.class);
		bind(IHelloPrinter.class).annotatedWith(Names.named("complex")).to(ComplexHelloPrinter.class);
	}

}

public class Sample {
	@Named("simple")
	private IHelloPrinter simplePrinter;
	
	@Named("complex")
	private IHelloPrinter complexPrinter;
	
	@Inject
	public Sample(@Named("simple") IHelloPrinter simplePrinter, @Named("complex") IHelloPrinter complexPrinter) {
		this.simplePrinter = simplePrinter;
		this.complexPrinter = complexPrinter;
	}
	
	public void hello() {
		simplePrinter.print();
		complexPrinter.print();
	}
	public static void main(String[] args) {
		Injector injector = Guice.createInjector(new SampleModule());
		Sample sample = injector.getInstance(Sample.class);
		sample.hello();
	}
}

有时候需要直接注入一个对象实例,而不是从依赖关系中解析。如果我们注入基本类型可以在SampleModule的configure()方法中添加如下语句:

bind(String.class).annotatedWith(Names.named("url")).toInstance("http://www.baidu.com");

那么在Sample中就可以添加如下语句进行自动装配:

@Named("url")
private String url;

当一个对象很复杂,无法使用简单的构造器来生成的时候,我们就可以使用使用实现Provider接口的类来生成复杂对象,然后在SampleModule的configure()方法中配置该复杂对象

(1)使用实现Provider接口的类来生成复杂对象

class LogParam {
	@Override
	public String toString() {
		return "我是test";
	}
}
// Log类为Sample类需要加载的复杂对象的抽象类(说它复杂因为包含了LogParam的实例)
abstract class Log {
	protected LogParam test;

	public abstract void setTest(LogParam test);

	public abstract LogParam getTest();
}

// Log的实现类
class MyLog extends Log {

	@Override
	public void setTest(LogParam test) {
		this.test = test;
	}

	@Override
	public LogParam getTest() {
		return this.test;
	}

}

class LogProvider implements Provider<Log> {

	private final LogParam test;
    // 这里会自动装配LogParam实例,也可在get方法中自定义构造该实例
	@Inject
	public LogProvider(LogParam test) {
		this.test = test;
	}

	@Override
	public Log get() {
		MyLog myLog = new MyLog();
		myLog.setTest(test);
		return myLog;
	}

}

(2)在SampleModule的configure()方法中配置该复杂对象

bind(Log.class).toProvider(LogProvider.class);

(3)Sample类中装配使用Log实现类

@Named("simple")
private IHelloPrinter simplePrinter;
	
@Named("complex")
private IHelloPrinter complexPrinter;
	
private Log log;
	
@Inject
public Sample(@Named("simple") IHelloPrinter simplePrinter, @Named("complex") IHelloPrinter complexPrinter, Log log) {
	this.simplePrinter = simplePrinter;
	this.complexPrinter = complexPrinter;
	this.log = log;
}

Guice还可以自动注入Set,Map容器,添加扩展库依赖

<dependency>
	<groupId>com.google.inject.extensions</groupId>
	<artifactId>guice-multibindings</artifactId>
	<version>4.1.0</version>
</dependency>

注入Set

package com.jingchenyong.boundless.guice.example6;

import java.util.Set;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import com.google.inject.multibindings.Multibinder;

interface IHelloPrinter {
	void print();
}

@Singleton
class SimpleHelloPrinter implements IHelloPrinter {

	@Override
	public void print() {
		System.out.println("Hello, Simple World");
	}
}

@Singleton
class ComplexHelloPrinter implements IHelloPrinter {

	@Override
	public void print() {
		System.out.println("Hello, Complex World");
	}
}

class SampleModule extends AbstractModule {

	@Override
	protected void configure() {
		Multibinder<IHelloPrinter> printers = Multibinder.newSetBinder(binder(), IHelloPrinter.class);
		printers.addBinding().to(SimpleHelloPrinter.class);
		printers.addBinding().to(ComplexHelloPrinter.class);
	}

}

public class Sample {

	@Inject
	private Set<IHelloPrinter> printers;

	public void hello() {
		for (IHelloPrinter printer : printers) {
			printer.print();
		}
	}

	public static void main(String[] args) {
		Injector injector = Guice.createInjector(new SampleModule());
		Sample sample = injector.getInstance(Sample.class);
		sample.hello();
	}
}
// 运行结果
Hello, Simple World
Hello, Complex World

注入Map

package com.jingchenyong.boundless.guice.example6;

import java.util.Map;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import com.google.inject.multibindings.MapBinder;

interface IHelloPrinter {
	void print();
}

@Singleton
class SimpleHelloPrinter implements IHelloPrinter {

	@Override
	public void print() {
		System.out.println("Hello, Simple World");
	}
}

@Singleton
class ComplexHelloPrinter implements IHelloPrinter {

	@Override
	public void print() {
		System.out.println("Hello, Complex World");
	}
}

class SampleModule extends AbstractModule {

	@Override
	protected void configure() {
		MapBinder<String, IHelloPrinter> printers = MapBinder.newMapBinder(binder(), String.class, IHelloPrinter.class);
		printers.addBinding("simple").to(SimpleHelloPrinter.class);
		printers.addBinding("complex").to(ComplexHelloPrinter.class);
	}

}

public class Sample {

	@Inject
	private Map<String, IHelloPrinter> printers;

	public void hello() {
		for (String name : printers.keySet()) {
			printers.get(name).print();
		}
	}

	public static void main(String[] args) {
		Injector injector = Guice.createInjector(new SampleModule());
		Sample sample = injector.getInstance(Sample.class);
		sample.hello();
	}
}
//运行结果
Hello, Simple World
Hello, Complex World

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章