17.2. Maven编程

本书的绝大部分都在讲述使用Maven,在这本关于Maven的书中,你还没看到太多关于定制Maven的样例代码。事实上,到目前为止这样的代码还没有。这原是设计的目的,99%的Maven用户将从来不需要编写自定义插件来定制Maven;有大量的可配置的插件可用,除非你有特别的单独需求,你没有理由自己去编写一个新的插件。而在那一小部分编写自定义插件的人中,也只有更少的人需要去查看Maven的源码以自定义Maven核心组件。如果你确实需要自定义Maven的行为,那么你可以编写一个插件。修改核心Maven代码与修改操作系统的TCP/IP堆栈一样,远远超出了大部分开发人员的范围,这对于大部分Maven用户来说过于抽象。

另一方面,如果你想开始编写自定义插件,你就需要学习一些Maven的内部原理:它如何管理软件组件?什么是一个插件?我如何能够自定义生命周期?本节将解答其中的一些问题,并介绍一些Maven设计核心的概念。学习如何编写Maven插件同时也是学习定制Maven本身一种很好的方式。如果你想了解如何开始探究Maven背后的代码,那么你已经找到了正确的出发点。

17.2.1. 什么是反转控制?

Maven的心脏是一个名为Plexus的反转控制(IoC)框架。它做什么呢?这是一个用来管理及关联组件的系统。虽然有一篇Martin Fowler编写的关于Ioc的权威论文,但这个概念和术语在过去的一些年中已经被大量的重载,因此找出一个关于此概念的良好定义已经变得非常困难,很多定义都是自我指认的(或者对于上述论文的简单引用)。这里我们将通过一个比喻来简要介绍反转控制和依赖注入,而不是简单的援引维基百科。

假设你有一系列的组件需要装配在一起。当你考虑组件的时候,将其想象成立体声音响组件而非软件组件。想象一下有一些音响组件接通了一个Playstation 3和一个机顶盒,后者又需要连接一个苹果电视盒以及一个50英寸的平板液晶电视。你从电子产品商店将所有这些东西带回家,并购买了一些电缆准备用来连接这些电器。你将所有组件拆开,将其放到正确的位置,然后开始连接同轴电缆,数字输入设备,立体声控制设备,以及网线等等。从你的家庭娱乐中心后退一步,然后打开电视机,你已经完成了依赖注入,你刚才正处在一个反转控制容器中。

那么,你到底需要做什么?你的Playstation 3和一个Java Bean都提供接口。Playstation 3有两个输入:电源和网络,以及一个电视输出。你的Java Bean有三个属性:power,network,和tvOutput。当你打开Playstation 3盒子的时候,它并不会提供关于连接所有不同种类电视的详细图片和指令,当你查看你的Java Bean的时候,它也只是提供了一组属性,而不是创建和管理整个系统组件的显式的方法。在一个如Plexus的IoC容器中,你负责通过简单的提供输入输出接口来声明组件之间的关系。你不需要初始化对象,Plexus会帮你完成;你的应用程序的代码不用去管理组件的状态,Plexus负责。虽然这听起来非常俗套,不过这里还是要说,当你启动Maven的时候,实际上是启动Plexus来管理一个带有很多相互关联组件的系统,就像你的家庭影音系统一样。

那么,使用Ioc容器的优点是什么呢?购买离散的音响组件的优点是什么?如果一个组件坏了,你可以放一个Playstation 3的替代品,而不用花20,000美元去重新购买整个系统。如果你对电视机不满意,你可以在不影响CD播放器的情况下将电视换掉。对你来说最重要的是,你的音响组件现在花费更低,但功能更强,且更稳定,因为制造商现在根据一组通用的输入输出来制造组件,他们能够更加的关注组件本身。反转控制和依赖注入提倡分解以及标准的形成。软件产业喜欢自己给新的想法命名,但依赖注入和反转控制实际上只是对于分解及可交换体系的重新命名。如果你真的想要好好了解DI和IoC,你可以学习一下Model T,Cotton Gin,以及19世纪末期形成的一个铁路系统标准。