Maven: The Complete Reference
Most of this book has dealt with using Maven, and for a book on Maven, you haven’t seen too many code examples dealing with Maven customization. In fact, you haven’t yet seen any. This is by design, 99 out of 100 Maven users will never need to write a custom plugin to customize Maven; there is an abundance of configurable plugins, and unless your project has particularly unique requirements, you will have to work to find a reason to write a new plugin. An even smaller percentage of people who end up writing custom plugins will ever need to crack open the source code for Maven and customize a core Maven component. If you really need to customize the behavior of Maven, then you would write a plugin. Modifying the core Maven code is as far out of scope for most developers as modifying the TCP/IP stack on an operating system, it is that abstract for most Maven users.
On the other hand, if you are going to start writing a custom plugin, you are going to have to learn a bit about the internals of Maven: How does it manage software components? What is a Plugin? How can I customize the lifecycle? This section answers some of those questions, and it introduces a few concepts at the core of Maven’s design. Learning how to write a custom Maven plugin is the gateway to customizing Maven itself. If you were wondering how to start understanding the code behind Maven, you’ve found the proper starting line.
At the heart of Maven is an Inversion of Control (IoC) container named Plexus. What does it do? It is a system for managing and relating components. While there is a canonical essay about IoC written by Martin Fowler, the concept and term have been so heavily overloaded in the past few years it is tough to find a good definition of the concept that isn’t a self-reference (or just a lazy reference to the aforementioned essay). Instead of resorting to a Wikipedia quote, we’ll summarize Inversion of Control and Dependency Injection with an analogy.
Assume that you have a series of components which need to be wired together. When you think about components, think stereo components not software components. Imagine several stereo components hooked up to a Playstation 3 and a Tivo that have to interface with both an Apple TV box and a 50-inch flat panel LCD TV. You bring everything home from the electronics store and you purchase a series of cables that you are going to use to connect everything to everything else. You unpack all of these components, put them in the right place, and then get to the job of hooking up fifty thousand coaxial cables and stereo jacks to fifty thousand digital inputs and network cables. Step back from your home entertainment center and turn on the TV, you’ve just performed dependency injection, and you’ve just been an inversion of control container.
So what did that have to do with anything? Your Playstation 3 and a
Java Bean both provide an interface. The Playstation 3 has two inputs:
power and network, and one output to the TV. Your JavaBean has three
tvOutput. When you open the box
of your Playstation 3, it didn’t provide you with detailed pictures
and instructions for how to connect it to every different kind of TV
that might be in every different kind of house. When you look at your
Java Bean, it just provides a set of properties, not an explicit
recipe for creating and managing an entire system of components. In an
IoC container like Plexus, you are responsible for declaring the
relationships between a set of components which simply provide an
interface of inputs and outputs. You don’t instantiate objects, Plexus
does; your application’s code isn’t responsible for managing the state
of components, Plexus is. Even though it sounds very cheesy, when you
start up Maven, it is starting Plexus and managing a system of related
components just like your stereo system.
What are the advantages of using an IoC container? What is the advantage of buying discrete stereo components? If one component breaks, you can drop in a replacement for your Playstation 3 without having to spend $20,000 on the entire system. If you are unhappy with your TV, you can swap it out without affecting your CD player. Most important to you, your stereo components cost less and are more capable and reliable because manufacturers can build to a set of known inputs and outputs and focus on building individual components. Inversion of Control containers and Dependency Injection encourage Disaggregation and the emergence of standards. The software industry likes to imagine itself as the font of all new ideas, but dependency injection and inversion of control are really just new words for the concepts of Disaggregation and interchangeable machinery. If you really want to know about DI and IoC, learn about the Model T, the Cotton Gin, and the emergence of a railroad standard in the late 19th century.
The most important feature of an IoC container implemented in Java is a mechanism called dependency injection. The basic idea of IoC is that the control of creating and managing objects is removed from the code itself and placed into the hands of an IoC framework. Using dependency injection in an application that has been programmed to interfaces, you can create components which are not bound to specific implementations of these interfaces. Instead, you program to interfaces and then configure Plexus to connect the appropriate implementation to the appropriate component. While your code deals with interfaces, you can capture the dependencies between classes and components in an XML file that defines components, implementation classes, and the relationships between your components. In other words, you can write isolated components, then you can wire them together using an XML file that defines how the components are wired together. In the case of Plexus, system components are defined with an XML document that is found in META-INF/plexus/components.xml.
In a Java IoC container, there are several methods for injecting dependencies values into a component object: constructor, setter, or field injections. Although Plexus is capable of all three dependency injection techniques, Maven only uses two types: field and setter injection.
- Constructor Injection
Constructor injection is populating an object’s values through its
constructor when an instance of the object is created. For example,
if you had an object of type
Personwhich had a constructor
Person(String name, Job job), you could pass in values for both
jobvia this constructor.
- Setter Injection
Setter injection is using the setter method of a property on a Java
bean to populate object dependencies. For example, if you were
working with a
Personobject with the properties
job, an IoC container which uses setter injection, would create an instance of
Personusing a no-arg constructor. Once it had an instance of
Person, it would proceed to call the
- Field Injection
Both Constructor and Setter injection rely on a call to a public
method. Using Field injection, an IoC container populates a
component’s dependencies by setting an object’s fields
directly. For example, if you were working with a
Personobject that had two fields
job, your IoC container would populate these dependencies by setting these fields directly (i.e.
person.name = "Thomas"; person.job = job;)
Spring does happen to be the most popular IoC container at the moment, and there’s a good argument to be made that it has affected the Java "ecosystem" for the better forcing companies like Sun Microsystems to yield more control to the open source community and helping to open up standards by providing a pluggable, component-oriented "bus". But, Spring isn’t the only IoC container in open source. There are many IoC containers (like PicoContainer).
Years and years ago, when Maven was created, Spring wasn’t a mature option. The initial team of committers on Maven were more familiar with Plexus because they invented it, so they decided to use it as an IoC container. While it might not be as popular as the Spring Framework, it is no less capable. And, the fact that it was created by the same person who created Maven makes it a perfect fit. After reading this chapter you’ve have an idea of how Plexus works. If you already use an IoC container you’ll notice similarities and differences between Plexus and the container you currently use.
Just because Maven is based on Plexus doesn’t mean that the Maven community is "anti-Spring" (we’ve included a whole chapter with a Spring example in this book, portions of the Spring project are moving to Maven as a build platform). The question, "Why didn’t you use Spring?" comes up often enough it did make sense to address it here. We know it, Spring is a rock star, we don’t deny it, and it is on our continuing to-do list to introduce people to (and document) Plexus: choice in the software industry is always a good thing.
A Maven Plugin is a Maven artifact which contains a plugin descriptor
and one or more Mojos. A Mojo can be thought of as a goal in Maven,
and every goal corresponds to a Mojo. The
corresponds to the
CompilerMojo class in the Maven Compiler Plugin,
jar:jar goal corresponds to the
JarMojo class in the Maven
Jar Plugin. When you write your own plugin, you are simply grouping
together a set of related Mojos (or goals) in a single plugin
Mojo? What is a Mojo? The word mojo is defined as "a magic charm or spell", "an amulet, often in a small flannel bag containing one or more magic items", and "personal magnetism; charm". Maven uses the term Mojo because it is a play on the word Pojo (Plain-old Java Object).
A Mojo is much more than just a goal in Maven, it is a component managed by Plexus that can include references to other Plexus components.
 "mojo." The American Heritage® Dictionary of the English Language, Fourth Edition. Houghton Mifflin Company, 2004. Answers.com 02 Mar. 2008