1. 简介
本文将深入探讨 Google Guice 的核心概念,并演示如何使用 Guice 完成基础的依赖注入(DI)任务。我们还会对比 Guice 与成熟 DI 框架(如 Spring 和 CDI)的实现差异。
⚠️ 本文假设读者已掌握依赖注入模式的基础知识。
2. 环境配置
在 Maven 项目中使用 Google Guice,需在 pom.xml
中添加以下依赖:
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>7.0.0</version>
</dependency>
此外,Guice 还提供扩展包和第三方模块,用于增强框架能力(主要是集成主流 Java 框架)。
3. Guice 基础依赖注入
3.1 示例应用
我们设计一个支持客服系统三种通信方式的场景:邮件、短信和即时消息。先看核心类:
public class Communication {
@Inject
private Logger logger;
@Inject
private Communicator communicator;
public Communication(Boolean keepRecords) {
if (keepRecords) {
System.out.println("Message logging enabled");
}
}
public boolean sendMessage(String message) {
return communicator.sendMessage(message);
}
}
Communication
是通信基础单元,通过 Communicator
实现消息传输。Guice 的入口是 Injector
:
public static void main(String[] args){
Injector injector = Guice.createInjector(new BasicModule());
Communication comms = injector.getInstance(Communication.class);
}
这里引入了 Guice 的核心概念:Module(示例中的 BasicModule
)。Module 是绑定的基本定义单元(类似 Spring 的 wiring)。
✅ Guice 采用代码优先的依赖注入方式,开箱即用无需大量 XML 配置。
✅ 只要类有无参构造函数,Guice 会通过即时绑定(just-in-time binding) 隐式注入依赖树(Guice 创世即有此特性,Spring 4.3 才支持)。
3.2 基础绑定
绑定(Binding)是 Guice 的核心机制,用于定义依赖注入规则。绑定在 AbstractModule
实现类中定义:
public class BasicModule extends AbstractModule {
@Override
protected void configure() {
bind(Communicator.class).to(DefaultCommunicatorImpl.class);
}
}
此模块指定:所有 Communicator
变量都将注入 DefaultCommunicatorImpl
实例。
3.3 命名绑定
命名绑定(Named Binding)是绑定的变种,看以下变量声明:
@Inject @Named("DefaultCommunicator")
Communicator communicator;
对应的绑定定义:
@Override
protected void configure() {
bind(Communicator.class)
.annotatedWith(Names.named("DefaultCommunicator"))
.to(DefaultCommunicatorImpl.class);
}
此绑定将为 @Named("DefaultCommunicator")
注解的变量提供 Communicator
实例。
⚠️ @Inject
和 @Named
注解虽借自 Jakarta EE 的 CDI,但实际位于 com.google.inject.*
包。使用 IDE 时需注意导入正确包。
提示:Guice 也支持 javax.inject.Inject
和 javax.inject.Named
等标准注解。
3.4 构造函数绑定
通过构造函数绑定(Constructor Binding)可注入无默认构造函数的依赖:
public class BasicModule extends AbstractModule {
@Override
protected void configure() {
bind(Boolean.class).toInstance(true);
bind(Communication.class).toConstructor(
Communication.class.getConstructor(Boolean.TYPE));
}
上述代码通过 boolean
参数的构造函数注入 Communication
实例。我们通过无目标绑定(untargeted binding) 为构造函数提供 true
参数。
此外,实例绑定(Instance Binding) 是另一种构造函数绑定方式:
public class BasicModule extends AbstractModule {
@Override
protected void configure() {
bind(Communication.class)
.toInstance(new Communication(true));
}
}
此绑定直接提供 Communication
实例。但需注意:
❌ 类的依赖树不会自动装配
❌ 仅适用于无复杂初始化或依赖注入的场景
4. 依赖注入类型
Guice 支持标准 DI 模式下的所有注入类型。在 Communicator
类中,我们需要注入不同类型的 CommunicationMode
。
4.1 字段注入
@Inject @Named("SMSComms")
CommunicationMode smsComms;
可选的 @Named
注解作为限定符,实现基于名称的定向注入。
4.2 方法注入
使用 setter 方法实现注入:
@Inject
public void setEmailCommunicator(@Named("EmailComms") CommunicationMode emailComms) {
this.emailComms = emailComms;
}
4.3 构造函数注入
通过构造函数注入依赖:
@Inject
public Communication(@Named("IMComms") CommunicationMode imComms) {
this.imComms= imComms;
}
4.4 隐式注入
Guice 会隐式注入通用组件,如 Injector
和 java.util.Logger
。示例中虽使用 logger,但无需显式绑定。
5. Guice 作用域
Guice 支持主流 DI 框架的作用域机制,默认每次注入都创建新实例。
5.1 单例
注入单例:
bind(Communicator.class).annotatedWith(Names.named("AnotherCommunicator"))
.to(Communicator.class).in(Scopes.SINGLETON);
in(Scopes.SINGLETON)
指定所有 @Named("AnotherCommunicator")
注解的 Communicator
字段将获得单例实例(默认懒加载)。
5.2 饿汉单例
注入饿汉单例:
bind(Communicator.class).annotatedWith(Names.named("AnotherCommunicator"))
.to(Communicator.class)
.asEagerSingleton();
asEagerSingleton()
定义单例为饿汉式实例化。
除这两种作用域外,Guice 还支持自定义作用域,以及 Jakarta EE 提供的 Web 专用注解 @RequestScoped
和 @SessionScoped
(Guice 未提供这些注解的替代版本)。
6. Guice 面向切面编程
Guice 遵循 AOPAlliance 规范实现 AOP。我们通过四步实现日志拦截器,用于跟踪消息发送:
步骤 1 – 实现 AOPAlliance 的 MethodInterceptor
public class MessageLogger implements MethodInterceptor {
@Inject
Logger logger;
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object[] objectArray = invocation.getArguments();
for (Object object : objectArray) {
logger.info("Sending message: " + object.toString());
}
return invocation.proceed();
}
}
步骤 2 – 定义普通 Java 注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MessageSentLoggable {
}
步骤 3 – 定义匹配器绑定
匹配器(Matcher)指定 AOP 注解的应用目标。此处限定注解应用于 CommunicationMode
的实现类:
public class AOPModule extends AbstractModule {
@Override
protected void configure() {
bindInterceptor(
Matchers.any(),
Matchers.annotatedWith(MessageSentLoggable.class),
new MessageLogger()
);
}
}
此匹配器将 MessageLogger
拦截器应用于所有方法带 MessageSentLoggable
注解的类。
步骤 4 – 应用注解并加载模块
@Override
@MessageSentLoggable
public boolean sendMessage(String message) {
logger.info("SMS message sent");
return true;
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(new BasicModule(), new AOPModule());
Communication comms = injector.getInstance(Communication.class);
}
7. 总结
通过分析 Guice 基础功能,可见其设计灵感源于 Spring。Guice 支持 JSR-330,定位为专注注入的 DI 框架(而 Spring 提供完整编程生态,不仅是 DI),面向需要 DI 灵活性的开发者。
Guice 高度可扩展,允许开发者编写可移植插件,实现框架的灵活创新应用。此外,Guice 已深度集成主流框架和平台,如 Servlets、JSF、JPA 和 OSGi 等。