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

 

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