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