【曹工杂谈】Maven IOC容器的下半场:Google Guice
Maven容器的下半场:Guice
前言
在前面的文章里,Maven底层容器Plexus Container的前世今生,一代芳华终落幕,我们提到,在Plexus Container退任后,取而代之的底层容器是Guice。
Guice的应用也还比较广泛,以下轮子中(仅部分)都有它活跃的身影:
- google内部
- scalatest
- TestNG
- Caffeine Cache
- Spring Security Config
- elastic search
- jenkins
这很多轮子,都是直接用的Guice,那是因为没什么历史包袱;但Maven不一样,maven之前用自己的IOC轮子,有自己独特的定义组件的方式(比如Spring通过@Component注解来定义);但是Guice作为一个独立的IOC框架,那肯定是不认识Maven中的组件的。
因此,这中间肯定需要兼容啊,Maven的组件,还是用的Plexus IOC容器那套方式去定义,但是他们开发了一个中间层,把那些组件解析后,存放到了Guice容器中。
这里说,把组件解析后,存放到了Guice容器中,这个也不是特别准确,更准确的说法是,放到了基于Guice进行了一层封装的一个容器中,这个容器叫做:sisu,由eclipse在维护这个开源项目(https://www.eclipse.org/sisu/)。
可能你就疑惑了,就一个破IOC,搞得多有技术含量一样,还一层套一层。。这个我们就先不管了,这期我先讲Guice,然后大家就懂了,为啥Sisu要要封装一层了。总结一下,依赖路径是:
最底层的是google Guice --》 sisu(eclipse)--》 sisu-plexus兼容层--》plexus --》maven。
好了,开始正文。
Guice是什么
根据wiki的描述,Guice就是依赖注入框架,由google开源。主要特点就是:支持以java注解的方式配置组件及依赖。最早的版本应该是在2007年,我还找到一篇当年的报道 https://developers.googleblog.com/2007/03/,
当时还是2007年,而2004年的时候,支持注解的JDK1.5才放出来,与此同时,Spring早期版本主要也还是以xml配置为主,Guice在那时就支持全注解配置,以当时的眼光来看,很前沿了。
接下来,我们就来仔细了解下Guice的用法。
核心理念
在开始讲之前,我说下我对IOC框架的理解先。很多时候,可以简单地说,IOC容器是一个map,一个放东西的地方,就像一个中药房,每个格子里会放一种药材,而每个格子上,有一个标签,来说明里面放的是什么药材。
既然是放东西的地方,核心就是两个部分,怎么放,放的时候,可能就要考虑到后续怎么找的问题。比如,如果你打算只支持根据物品的类型来找,那你要考虑到:如果这个类型的物品有多个,要怎么办?怎么区分这多个物品?
如果你打算解决这个问题,那你可能就会想:那我放的时候,再给这些物品取个名字吧,免得多个相同类型的物品,分不清。
甚至呢,你可能会考虑,物品的权限隔离,比如,物品上再加个存放人的字段,以后取得时候,就只能:自己取自己的,不能取别人的。
反正,最终还是看需求,一般来说,像我们spring这种,按类型就差不多了,一个类型多个实现的时候,再根据名字区分一下就ok。
而Guice呢,我这边会重点讲解:怎么存。至于取,可能还分成两种,依赖注入和直接从容器中取。但是依赖注入的底层实现,也是:发现我依赖的某个东西没有,就去容器里取。
所以,取东西,我们只需要关注:直接从容器中怎么获取就行;我这边就不会特别关注依赖注入的问题。
Guice中,存东西的多种方式
概览
存东西,在Guice的文档里,名词叫做Binding,中文就是绑定吧。
https://github.com/google/guice/wiki/Bindings
绑定是什么意思,就是我最终可能需要从容器中获取ClassA类型的对象。既然要取,那还得先存,存的时候,我就要建立绑定:ClassA --》该Class类型对象的获取方式。
其实还是很简单的。下边就跟着我的代码例子,我们来看看。
以下全部的代码,都在:
https://gitee.com/ckl111/maven-3.8.1-source-learn/tree/master/my-test-modules/official-guice-demo
1. linkedbinding-绑定接口到实现类
先来一个接口和实现:
public interface HelloInterface {
void hello();
}
public class HelloInterfaceImpl implements HelloInterface {
@Override
public void hello() {
System.out.println("hello world");
}
}
再来看看,怎么放到容器,和简单的从容器中取出来的方法:
大家看我代码截图,放东西的时候,就是要指定这个接口,对应的实现类。
取东西的时候,再去根据接口取就行了。
2.BindingAnnotations 一个类型有多个实现类的时候的绑定方式
接口和多个实现类:
interface HelloInterface {
void hello();
}
class HelloInterfaceImpl implements HelloInterface {
@Override
public void hello() {
System.out.println("hello world");
}
}
class HelloInterfaceImpl2 implements HelloInterface {
@Override
public void hello() {
System.out.println("hello world");
}
}
如果我们还是按前面的办法去取,框架就晕圈了,多个实现类,我给你哪一个呢?麻烦再明确一下吧,ok吗
Guice有个注解,叫Named,可以加在各种地方,注解本身,支持设置名称。
这里意思就是说,你接口不是多个实现吗,那我们这样:接口+注解,才算是唯一的key,这样ok了吧。
因此,现在就变成了这样:接口+注解1 --》 实现类1;接口 + 注解2 --》 实现类2.
那我怎么取呢?简单啊,怎么存,怎么取,存的时候,用的接口+注解,取的时候,也需要这样。
既然,可以用官方的Named注解,那其实自己的注解也一样可以用。
3. InstanceBindings 接口直接绑定一个单例对象
如果同一个类型,要绑定到多个实例的情况,同前面的处理方式一样。
4. 绑定到工厂方法:授人以鱼不如授人以渔
前面都是些直来直去的办法,这次不一样,我只告诉你,这个东西的获得方法。
5. 不用接口了,直接绑定一个实现类
前面都是根据一个接口类,去取接口对应的实现之类的。这次不一样,直接就是一个实现类了。
public class UtilService {
}
像上面这个情况,那肯定是直接调用这个类的构造函数了。
6. 接口绑定到一个构造函数:ToConstructorBindings
哎,我是越来越无语了,Guice的骚操作真是多啊。
7. 内置的不用绑就能用的
主要有:Logger、Injector本身(就是相当于可以帮你注入容器自身)
8. 能不能不绑定直接用
用惯了spring的我们,现在已经是不需要这么绑来绑去了。我们看看Guice的支持怎么样
不绑定的话,可以这样:
@ImplementedBy(TestInterfaceImpl.class)
interface TestInterface {
}
这就相当于,你要自己指定一下,你的实现类是谁,或者你的provider是谁。但是官方不建议用这种隐式绑定,不知道为啥,还出了个选项,专门禁用隐式绑定。
9. 一个接口多个实现类,一次性全获取回来
这个场景,就是一次性把多实现类一把取回来,放到一个集合里给你。
这个场景我没写代码,大家自己看一下文档,也简单。
10. 注入的方式
前面说了很多怎么手动从容器里面取,当然了,要自动注入的话,也是支持:构造器注入、field注入等等方式。
如以下为构造器注入:
其他支持的特性
其他的,比如循环依赖、aop也是大体支持的,只是这个容器在安卓端用,会有问题,因为aop好像不太支持,所以给安卓端还专供了一个去掉aop的版本。
循环依赖之类的,具体实现还没怎么看过。
另外,guice默认生成的是多例(类比spring的prototype,而不是singleton),但是本身也是支持singleton的,我前面的代码例子有。
最大槽点
可以看出,Guice是很轻量,轻量的意思是,功能没Spring那么全,所以,我们还需要去显式地:配置每个接口,要怎么获取它的对象(方法也是五花八门,哈哈哈,如前面展示的)。
当然,配置ok后,我们获取某对象的时候,它会帮我们去完成自动注入的东西。
但是,它也不支持类路径扫描啊,比如给个包名,自动去扫描这个包下面的组件,反正官方不支持,说是有第三方插件,还没试过。
总结
在各种轮子里,用来管理自己的代码间的相互依赖,用Guice确实足够了,用在业务代码,就还是有点累。
因为,主要是:各种依赖要自己配,只是集中在一个地方配置而已,没有像spring那样,约定通过接口找对象时,默认就是找实现类,然后反射生成对象。
这一点来说,确实是:约定优于配置,就像Maven为啥打败了ant,也是这个道理。
另外的问题就是,不支持spring的那种component-scan。
基于这两个问题呢,方法肯定是有的,所以,Maven也足够聪明,没有直接基于Guice,而是选择了基于Guice封装后的Sisu,而Sisu就可以解决我们说的问题,支持类路径扫描之类的。
我们看看sisu怎么介绍自己:
就是比Guice多了些看起来还很不错的、Spring早已有了的特性吧。回头我们肯定要再介绍sisu的。
再见,以上。
【曹工杂谈】Maven IOC容器的下半场:Google Guice的更多相关文章
- 【曹工杂谈】Maven源码调试工程搭建
Maven源码调试工程搭建 思路 我们前面的文章<[曹工杂谈]Maven和Tomcat能有啥联系呢,都穿打补丁的衣服吗>分析了Maven大体的执行阶段,主要包括三个阶段: 启动类阶段,负责 ...
- 【曹工杂谈】Mysql-Connector-Java时区问题的一点理解--写入数据库的时间总是晚13小时问题
背景 去年写了一篇"[曹工杂谈]Mysql客户端上,时间为啥和本地差了整整13个小时,就离谱",结果最近还真就用上了. 不是我用上,是组内一位同事,他也是这样:有个服务往数据库in ...
- 【曹工杂谈】Maven IOC 容器-- Guice内部有什么
Google Guice容器内部有什么 前言 Maven系列,好几天没写了,主要是这几天被Google Guice卡住了,本来是可以随便带过Guice,讲讲guice的用法就够了(这个已经讲了,在前面 ...
- 【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕
Maven底层容器Plexus Container的前世今生,一代芳华终落幕 前言 说实话,我非常地纠结,大家平时只是用Maven,对于内部的实现其实也不关心,我现在非要拉着大家给大家讲.这就有个问题 ...
- 曹工杂谈--使用mybatis的同学,进来看看怎么在日志打印完整sql吧,在数据库可执行那种
前言 今天新年第一天,给大家拜个年,祝大家新的一年里,技术突突突,头发长长长! 咱们搞技术的,比较直接,那就开始吧.我给大家看看我demo工程的效果(代码下边会给大家的): 技术栈是mybatis/m ...
- 曹工杂谈:Spring boot应用,自己动手用Netty替换底层Tomcat容器
前言 问:标题说的什么意思? 答:简单说,一个spring boot应用(我这里,版本升到2.1.7.Release了,没什么问题),默认使用了tomcat作为底层容器来接收和处理连接. 我这里,在依 ...
- 【曹工杂谈】详解Maven插件调试方法
前言 今年的更新频率简直是降至冰点了,一方面平时加班相对多一些了,下班只想玩手机:另一方面,好像进了大厂后,学习动力也很低了,总之就,很懒散,博客的话,今年都才只更新了不到5篇. 现在慢慢有一点状态, ...
- 【曹工杂谈】Maven和Tomcat能有啥联系呢,都穿打补丁的衣服吗
Maven和Tomcat能有啥联系呢,都穿打补丁的衣服吗 前奏 我们上篇文章,跟大家说了下,怎么调试maven插件的代码,注意,是插件的代码.插件,是要让主框架来执行的,主框架是谁呢,就是maven ...
- 【曹工杂谈】说说Maven框架和插件的契约
说说Maven框架和插件的契约 前言 Maven框架就像现在公司内的各种平台方,规定一些契约,然后想办法拉动业务方,一起在这个平台上去做生态共建.Maven也是这样,其实它就是一个插件执行的框架,Ma ...
随机推荐
- 一张图带你搞懂Javascript原型链关系
在某天,我听了一个老师的公开课,一张图搞懂了原型链. 老师花两天时间理解.整理的,他讲了两个小时我们当时就听懂了. 今天我把他整理出来,分享给大家.也让我自己巩固加深一下. 就是这张图: 为了更好的图 ...
- squid异常停止的排查步骤
今天重启squid的时候发现,squid启动后,status 一会就stop了 whoami@blackman:~/script/AutoProxy-master/main/server$ sudo ...
- AuthorizationFailed""The client '***' with object id '***' does not have authorization to perform action 'or the scope is invalid. If access was recently granted, please refresh your credentials
Warning SyncLoadBalancerFailed 4m9s (x11 over 29m) service-controller Error syncing load balanc ...
- Netty入门(二):Channel
前言 Netty系列索引: 1.Netty入门(一):ByteBuf 2.Netty入门(二):Channel 在Netty框架中,Channel是其中之一的核心概念,是Netty网络通信的主体,由它 ...
- Java Fork/Join
Fork/Join框架 Fork/Join 以递归方式将可以并行的任务拆分成更小的任务,然后将每个子任务的结果合并起来生成整体结果. 这个过程其实就是分治算法的并行版本,图解如下: 如何使用 我们要使 ...
- 阿里面试官:Android中binder机制的实现原理及过程?
Binder 是 Android 系统中非常重要的组成部分.Android 系统中的许多功能建立在 Binder 机制之上.在这篇文章中,我们会对 Android 中的 Binder 在系统架构中的作 ...
- 最全总结 | 聊聊 Python 数据处理全家桶(PgSQL篇)
1. 前言 大家好,我是安果! Python 数据处理全家桶,截止到现在,一共写过 6 篇文章,有兴趣的小伙伴可以去了解一下! 最全总结 | 聊聊 Python 数据处理全家桶(Mysql 篇) 最全 ...
- 雪花算法ID在前端丢失精度解决方案
首先说一下背景,目前笔者的工作是物联网方面的,设备有对应的智慧运营平台,平台开发中建表的主键用的是Mybatis plus默认的雪花算法来生成的,也就是分布式系统比较常用的雪花ID,技术栈就是常用的S ...
- MySQL-04-SQL简单介绍
SQL介绍 SQL 结构化查询语言 5.7 以后符合SQL92严格模式 通过sql_mode参数来控制 常用SQL分类 DDL:数据定义语言 DCL:数据控制语言 DML:数据操作语言 DQL:数据的 ...
- GO语言的基本语法之变量,常量,条件语句,循环语句
GO语言的基本语法之变量,常量,条件语句,循环语句 作为慕课网得笔记自己看 定义变量: 使用var关键字 var a, b, C bool var s1, s2 string = "hell ...