Google Guice是一个轻量级依赖注入框架,和Spring类似。下面结合一些示例来讲解其使用方式。
首先引入maven依赖:
com.google.inject
guice
4.1.0
示例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 {
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容器,添加扩展库依赖
com.google.inject.extensions
guice-multibindings
4.1.0
注入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 printers = Multibinder.newSetBinder(binder(), IHelloPrinter.class);
printers.addBinding().to(SimpleHelloPrinter.class);
printers.addBinding().to(ComplexHelloPrinter.class);
}
}
public class Sample {
@Inject
private Set 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 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 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