Guice
新公司不是使用 spring,而是使用 Guice 来进行依赖注入的,对我来说还是新东西,又可以学习了
Guice 官网: https://github.com/google/guice
概述
Put simply, Guice alleviates the need for factories and the use of new in your Java code. Think of Guice’s @Inject as the new new. You will still need to write factories in some cases, but your code will not depend directly on them. Your code will be easier to change, unit test and reuse in other contexts.
以上是 git 主页对于 guice 的介绍第一段,其实重点就是一句话: Think of Guice’s @Inject as the new new.
相对于 spring 来说,最大的优势就在于轻量级,guice 它只做依赖注入,是一个纯粹的依赖注入框架
关于 spring 的 IoC 实现和 DI 方法,可以查看:
https://www.baeldung.com/inversion-control-and-dependency-injection-in-spring
而且 Spring 从2.5 开始提供了基于注解的自动装配机制来简化依赖注入。
@Autowired
:基于 类型 的自动装配注入@Resource
:基于 名称 的自动装配注入
话说回来,那 Guice 的依赖注入是什么样的?
先实践一下吧
使用
添加依赖
1. maven直接添加
在 maven 的 pom.xml中添加依赖
1 | <dependency> |
2. 作为 Guice 的 extension 添加
公司使用的是 jooby 框架,jooby 还有另一种第三方方式引入 guice.
参考文档可以查看 jooby 官网: https://jooby.io/#dependency-injection-guice
1 | <dependency> |
当然现在使用第一种方式先添加
简单使用
这里假设我们有这样一个场景,我们设计一个 class 来支持服务业务中的三种通信方式: Email, SMS, IM
先定义一个接口,接口有一个实现类
1 | public interface Communicator { |
1 | public class DefaultCommunicatorImpl implements Communicator { |
这样我们的 communication 类可以写成
1 | public class Communication { |
写一个 main 方法
1 | public class Test { |
这个 main 方法就是找到一个 Communication 的类的实例
但是上面的 BasicModule 又是什么呢?
The Module is the basic unit of definition of bindings
定义依赖绑定的基本单元
Guice has adopted a code-first approach for dependency injection and management so you won’t be dealing with a lot of XML out-of-the-box.
Guice binding
Binding is to Guice as wiring is to Spring. With bindings, you define how Guice is going to inject dependencies into a class.
也就是说定义 guice 怎么去注入依赖进入一个类
在本例中,BasicModule 如下
1 | public class BasicModule extends AbstractModule { |
这个表明了DefaultCommunicatorImpl的实例 Instance 将被注入于 Communicator 变量被发现的地方
这个表明了, Guice 是通过代码来注入并管理依赖的,而不是和 spring 一样是使用 xml 的
另一种方式: 命名绑定 named binding
1 |
|
为此,我们有以下绑定:
1 |
|
基于注解的绑定: 使用@Provides
1 | public class BasicModule extends AbstractModule { |
Singleton
注入一个单例
1 | bind(Communicator.class).annotatedWith(Names.named("AnotherCommunicator")) |
这个表示任何Communicator如果被*@Named(“AnotherCommunicator”)* 标注的话,都将会得到一个scope单例的注入.
这个注入是lazily initiated 延时加载的
TIP
问题
如果我们有另一个实现类比如AnotherCommunicatorImpl
注入肯定不能直接@Inject
这样怎么办?
解决方法
使用@Named注解提供为属性赋值的功能
首先在注入绑定的时候使用
1 |
|
然后在定义绑定的时候使用
1 |
|
查找实例
injector.getInstance(XXX.class);
的过程:
先根据指定的类来 new Key()
,Key
包括类信息 XXX.class
和注解信息,XXX.class
的 hashcode
和注解的 hashcode
决定了 Key
的 hashcode
,getProvider
时是根据 Key
的 hashcode
来判断是否是同一个Key
,然后取到 Provider
,由 Provider
提供最终的示例。
参考资料: