Basic use of Maven
1️⃣ Write POM
So far, the Maven environment has been roughly understood and installed. Now, we start to create the simplest Hello World
project. If you are new to Maven, it is recommended to write and execute the code step by step according to the content of this article. You may encounter some concepts that are temporarily difficult to understand, but don’t worry, write down these difficult points, and I will go through them one by one in the follow-up articles answer.
Like Make
, , the core Makefile
of the Maven project is . Defines the basic information of the project, which is used to describe how the project is built, declare project dependencies, and so on. Now write the simplest one for the project .Ant
build.xml
pom.xml
POM (Project Object Model, 项目对象模型)
Hello World
pom.xml
First create a hello-world
folder named , open the folder, create a new pom.xml
file named , and enter its content, as shown below.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven,apache.org/POM/4.0.0"
xmins:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache,org/POM/4.0.0
http://maven.apache,org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xiaoshan.mvnbook</groupId>
<artifactId>hello-world</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Maven Hello World Project</name>
</project>
The first line of code is an XML header specifying the version and encoding of the xml document. Next is project
the element, project
which is pom.xml
the root element of all , and it also declares some POM-related namespaces and xsd
elements. Although these attributes are not required, using these attributes allows third-party tools (such as XML editors in the IDE) to help Let's quickly edit the POM.
The first child element under the root element modelVersion
specifies the version of the current POM model. For Maven 2 and Maven 3, it can only be 4.0.0.
The most important in this code are the three lines containing groupld
, artifactld
and version
. These three elements define the basic coordinates of a project. In the world of Maven, any jar
or pom
all war
are distinguished based on these basic coordinates.
groupld
Defines which group the project belongs to, and this group is often associated with the organization or company where the project is located. For example, if you create a project called myapp on googlecode, then groupld
it should be com. googlecode.myapp
, if your company is mycom, and there is a project called myapp, then groupld
it should be com.mycom.myapp
. artifactld
Defines the unique ID of the current Maven project in the group, which we define for this Hello World
project . And in the previous example of for , you might assign for different subprojects (modules) , such as , , etc. As the name suggests, specifies the current version of the project -- . SNAPSHOT means a snapshot, indicating that the project is still under development and is an unstable version. With the development of the project, it will be continuously updated, such as upgrading to , , , and so on. Later articles will introduce SNAPSHOT in detail and how to use Maven to manage the upgrade and release of project versions.artifactld
hello-world
groupId
com. googlecode.myapp
artifactId
myapp-util
myapp-domain
myapp-web
version
Hello World
1.0-SNAPSHOT
version
1.0
1.1-SNAPSHOT
1.1
2.0
The last name
element declares a more user-friendly project name, although it is not required, it is recommended to be declared for each POM name
to facilitate information exchange.
Without any actual Java code, we can define the POM of a Maven project, which reflects one of the great advantages of Maven, which can make the project object model independent of the actual code to the greatest extent, which we can call decoupling, or Orthogonality. This largely avoids the interaction of Java code and POM code. For example, when the project needs to upgrade the version, it only needs to modify the POM, without changing the Java code; after the POM is stable, the daily Java code development basically does not involve the modification of the POM.
2️⃣ Write business code
The business code of the project is different from the test code. The business code of the project will be packaged into the final component (such as jar), while the test code is only used when running the test and will not be packaged. By default, Maven assumes that the business code of the project is located in src/ main/java
the directory. We follow Maven's conventions, create this directory, and then create a file under this directory com/xiaoshan/mvnbook/helloworld/HelloWorld.java
. The contents are as follows:
package com.xiaoshan.mvnbook.helloworld;
public class HelloWorld{
public String sayHello(){
return "Hello Maven";
}
public static void main(String[] args){
System.out.print(new HelloWorld().sayHello());
}
}
This is a simple Java class with one sayHello()
method that returns a String. At the same time, this class also has a main
method to create an HelloWorld
instance, call sayHello()
the method, and output the result to the console.
There are two things to note about this Java code. First of all, in most cases, the main code of the project should be placed src/main/java/
in the directory (following the convention of Maven), without additional configuration, Maven will automatically search the directory to find the main code of the project. Second, the package name of the Java class is , which matches the and com.xiaoshan. mvnbook. helloworld
defined earlier in the POM . Generally speaking, the packages of Java classes in a project should be based on the project's sum , which is clearer and more logical, and it is also convenient to search for components or Java classes.groupId
artifactId
groupId
artifactId
After the code is written, use Maven to compile and run the command in the project root directory mvn clean compile
. will get the following output:
[INFO] Scanning for projects..
[INFO]
-----------------------------------------------------------------------
[INFO] Building Maven Hello World Project
[INFO] task-segment:[clean, compile]
[INFO]
-----------------------------------------------------------------------
[INFO] [clean:clean {
execution:default-clean}]
[INF0] Deleting directory D:\code\hello-world\target
[INF0] [resources:resources {
execution:default-resources}]
[INFO] skip non existing resourcepirectory D:\code\hello-world\src\main\resources
[INFO] [compiler:compile {
execution:default-compile}]
[INFO] Compiling 1 source file to D:\code\hello-world\target\classes
[INFO]
-----------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO]
-----------------------------------------------------------------------
[INFO] Total time:1 second
[INFO] Finished at: Fri oct 0902:08:09 CST 2009
[INFO] Final Memory:9M/16M
-----------------------------------------------------------------------
clean
The command tells Maven to clean up the output directory target/
, compile
and tells Maven to compile the main code of the project. From the output, we can see that Maven first executed clean:clean
the task and deleted targel/
the directory. By default, all the output of Maven builds are in target/
the directory; then execute reources:resources
the task (the project resource is not defined, skip it for now); finally execute compiler:compile
the task to compile the main code of the project to target/classes
the directory (the compiled class is com/xiaoshan/mvnbook/helloworld/HelloWorld.class
).
The mentioned above clean:clean, resources: resources 和 compiler:compile
corresponds to some Maven plug-ins and plug-in goals, for example, clean:clean
is the clean goal of the clean plug-in, and compiler:compile
is the compile goal of the compiler plug-in. The Maven plugin and how to write it will be described in detail later.
So far, Maven has performed the cleaning and compiling tasks of the project without any additional configuration. Next, write some unit test code and let Maven execute the automated tests.
3️⃣ Write test code
In order to keep the project structure clear, business code and test code should be located in separate directories. As mentioned above, the default main code directory in the Maven project is src/main/java
, and correspondingly, the default test code directory in the Maven project is src/test/java
. Therefore, this directory should be created before writing test cases.
In Java, JUnit, established by Kent Beck and Erich Gamma, is the de facto standard for unit testing. To use JUnit, you first need to Hello World
add a JUnit dependency to the project, and modify the POM of the project as follows:
<?xml version="1.0" encoding="UTP-8"?>
<project xmlns="http://maven.apache,org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xiaoshan.mvnbook</groupld>
<artifactId>helloworld</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Maven Hello World Project</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
A element is added to the code dependencies
, which can contain multiple dependency
elements to declare the dependencies of the project. A dependency was added here - groupId
yes junit
yes yes 4.7. As mentioned earlier , and are the most basic coordinates of any Maven project, and JUnit is no exception. With this statement, Maven can download it automatically . You may ask, where does Maven download this jar? Before Maven, you can go to the official website of JUnit to download the distribution package. With Maven, it will automatically access the central warehouse ( ) and download the required files . You can also visit the warehouse by yourself, open the path , and you can see and . The Maven warehouse and central warehouse will be introduced in detail later.artifactId
junit
version
groupId
artifactId
version
junit-4.7.jar
http://repol.maven.org/maven2/
junit/junil/4.7/
junit-4.7.pom
junil-4.7.jar
test
There is also an element whose value is in the above POM code scope
, scope
which is the dependency range. If the dependency range is test
, it means that the dependency is only valid for the test. import
In other words, there is no problem with the JUnit code in the test code , but if you use import JUnit code in the main code, it will cause compilation errors. If you do not declare a dependency scope, then the default value is compile
, which means that the dependency is valid for both the main code and the test code.
After configuring the test dependencies, you can write test classes. Looking back at the previous HelloWorld
class, now we need to test sayHello()
the method of this class to check whether its return value is " Hello Maven
". Create a file under src/test/java
the directory with the following contents:
package com.xiaoshan.mvnbook.helloworld;
import org.junit.Assert.assertEquals;
import org.junit.Test:
public class HelloWorldTest{
@Test
public void testSayHello(){
He1loWorld helloWorld = new HelloWorld();
String result = helloWorld.sayHello();
assertEquals("Hello Maven",result);
}
}
A typical unit test consists of three steps: ① prepare the test class and data; ② execute the behavior to be tested; ③ check the results. The above example first initializes an instance to be tested , then executes the method HelloWorld
of the instance and saves the result to a variable, and finally uses the class of the JUnit framework to check whether the result is " " that we expect. In JUnit3, it is agreed that all methods that need to execute tests start with . JUnit4 is used here, but this convention is still followed. In JUnit4, all test methods that need to be executed should be marked.sayHello()
result
Assert
HelloMaven
test
@Test
After the test case is written, Maven can be invoked to execute the test. run mvn clean test
:
[INFO] Scanning for projects.
[INFO]
-------------------------------------------------------------------
[INFO] Building Maven Hello World Project
[INFO] task-segment:[clean, test]
[INFO]
-------------------------------------------------------------------
[INFO] [elean:clean {
execution:default-clean}]
[INFO] Deleting directory D:\git-juven\mvnbook\code\hello-world\target
[INFO] [resources:resources {
execution:default-resources)]
Downloading:http://repo1.maven.org/maven2/junit/junit/4.7/junit-4.7.pom
1K downloaded (junit-4.7.pom)
[INFO] [compiler:compile {
execution: default-compile}]
[INFO] Compiling 1 source file to D:\code\hello-world\target\classes
[INF0] [resources:testResources {
execution:default-testResources}]
Downloading: http://repol,maven.org/maven2/junit/junit/4.7/unit-4.7.jar
226K downloaded (Junit-4.7.jar)
[INFO] [compiler:testCompile {
execution:default-testCompile}]
[INFO] Compiling 1 source file to D:\code\hello-world\target\test-classes
[INFO]
-------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO]
-------------------------------------------------------------------
[INFO] Compilation failure
D:\code\hello-world\src\test\java\com\xiaoshan\mvnbook\helloworld\He11oWorldTest.java;[8,5]-source 1.3 中不支持注释(请使用-source 5 或更高版本以启用注释) @Test
[INFO]
[INFO For more information, run Maven with the switch
Unfortunately, the build failed. Please analyze this output patiently. The command line input is mvn clean test
, and Maven actually executes more than these two tasks, as well as clean:clean
, resources:resources
, compiler:compile
, resources:testResources
and compiler:testCompile
. What needs to be understood for the time being is that before Maven executes the test (test), it will automatically execute the project's main resource processing, main code compilation, test resource processing, and test code compilation. This is a feature of the Maven life cycle. Subsequent chapters will explain the Maven life cycle in detail.
It can also be seen from the output: Maven has downloaded junit-4.7.pom
and junit-4.7.jar
these two files from the central warehouse to the local warehouse ( ~/. m2/repository
) for use by all Maven projects.
compiler:testCompile
The build failed when executing the task, and the Maven output suggested that we need to use source5 or higher to start the annotation, which is the JUnit4 @Test
annotation mentioned above. This is a problem Maven beginners often encounter. Due to historical reasons, one of Maven's core plug-ins, compiler
the plug-in, only supports compiling Java 1.3 by default, so the plug-in needs to be configured to support Java 5, as shown below:
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5c/target>
</configuration>
</plugin>
</plugins>
</build>
</project>
This POM omits other parts than plugin configuration. We don't care about the details of the plug-in configuration for now, just know that compiler
the plug-in supports Java5 compilation. Now execute again mvn clean test
, the output is as follows:
[INFO] [compiler:testCompile {
execution:default-testCompile}]
[INFO] Compiling 1 source file to D:\code\hello-world\target\test-classes
[INFO] [surefire:test {
execution:default-test}]
[INFO] Surefire report directory:D:\code\hello-world\target\surefire-reports
TESTS
Running com.xiaoshan.mvnbook.helloworld.He11oWorldTest
Tests run:1, Failures:0, Errors:0, Skipped:0,Time elapsed:0.055 sec
Results:
Tests run:1, Failures;0.Errors:0,Skipped:0
[INFO]
-------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO]
-------------------------------------------------------------------
We see that compiler:testCompile
the task is executed successfully. After the test code is compiled, a binary file is generated target/test-classes
under and then surefire:test
the task runs the test, surefire
which is the plug-in responsible for executing the test in Maven. Here it runs the test case HelloWorldTest
, and outputs the test report, showing that a total of How many tests, how many failed, how many went wrong, how many skipped. Clearly, our tests pass.
4️⃣ Package and run
After compiling and testing the project, the next important step is packaging ( package
). HelloWorld
The packaging type is not specified in the POM, and the default packaging type jar is used. Simply execute the command mvn clean package
to package, you can see the following output:
...
Tests run:1,Failures:0, Errors:0, Skipped:0
[INFO] [jar:jar {
execution: default-jar}]
[INFO] Building jar:D:\code\hello-worid\target\hello-wor1d-1.0-SNAPSHOT.Jar
[INPO]
-------------------------------------------------------------------
[INPO] BUILD SUCCESSFUL
...
Similarly, Maven will perform compilation, testing, etc. before packaging. Here we see jar:jar
that the task is responsible for packaging, in fact, the jar target of the jar plug-in packages the main code of the project into a hello-world-1.0-SNAP-SHOT.jar
file named . This file is also located target/
in the output directory. It is artifact-version.jar
named according to the rules. If necessary, you can also use finalName
to customize the name of the file. It will not be expanded here, and will be explained in detail later.
So far, we have obtained the output of the project. If necessary, we can copy this jar file to the Classpath of other projects to use the HelloWonld
class. However, how can other Maven projects directly reference this jar? An installation step is required, execute mvn clean install
:
...
[INFO] [jar:jar {
execution: default-jar}]
[INF0] Building jar:D:\code\hello-world\target\hello-world-1.0-SNAPSHOT.jar
[INFO] [install:install {
execution:default-instal1}]
[INFO] Installing D:\code\hello-world\target\hello-wor1d-1.0-SNAPSHOT.jar to c:\Users\xiaoshan\.m2\repository\com\xiaoshan\mvnbook\hello-world\1.0-SNAPSHOTN\hello-world-1.0-SNAPSHOT.jar
[INFO]
-------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
...
After packaging, the installation task was performed install:install
. From the output, you can see that the task has installed the jar output by the project into the Maven local warehouse, and you can open the corresponding folder to see the HelloWorld
pom and jar of the project. When we talked about the download of JUnit's POM and jar, we said that only after the components are downloaded to the local warehouse, can they be used by all Maven projects HelloWorld
. use it.
We have experienced the most important commands of Maven: mvn clean compile
, mvn clean test
, mvn clean package
, mvn clean install
. Executes test
before executes compile
, executes package
before executes test
, and similarly, install
before executes package
. These commands can be executed in any Maven project, and we already know what they are used for.
So far, the HelloWorld project has not been run. Don't forget that the HelloWorld class has a main
method. The jar generated by default packaging cannot be run directly, because the class information with the main method will not be added to it manifest
(open the file in the jar file META-INF/MANIFEST.MF
, you will not be able to see Main-Class
the - line). In order to generate an executable jar file, you need to use it maven-shade-plugin
. Configure the plug-in as follows:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource. ManifestResourceTransformer">
<mainClass>com.xiaoshan.mvnbook.helloworld.HelloWorld</mainclass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
plugin
The relative position of the element in the POM should be <project>
<build>
<plugins>
below. We configured mainClass
as com.xiaoshan.mvnbook.helloworld.HelloWorld
, the project will put this information in when packaging MANIFEST
. Execute now mvn clean install
, open the directory after the build is complete target/
, you can see hello-world-1.0-SNAPSHOT.jar
and original-hello-world-1.0-SNAPSHOT.jar
, the former is Main-Class
an executable jar with information, the latter is the original jar, open hello-world-1.0-SNAPSHOT.jar
, META-INF/ MANIFEST.MF
you can see that it contains such a line of information:
Main-Class:com.xiaoshan.mvnbook.helloworld.HelloWorld
Now, execute the jar file in the project root directory:
D:\code\hello-world>java-jartarget\hello-world-1.0-SNAPSHOT.jar
HelloMaven
The console output is HelloMaven, which is what we expect.
5️⃣ Use Archetype to generate project skeleton
There are some Maven conventions in the HelloWorld project: place in the root directory of the project pom.xml
, src/main/java
place the main code of the project in the directory, and src/test/java
place the test code of the project in the directory. The reason why these steps are shown step by step is to let you, who may be a Maven beginner, get the most practical feeling. We call these basic directory structures and pom.xml
file contents the skeleton of the project. When you create the project skeleton for the first time, you will be interested in understanding the ideas behind these default conventions. The second, third, You may still be satisfied with your proficiency, but the fourth or fifth time you do the same thing, you may be annoyed. To this end, Maven provides Archetype
to help us quickly outline the project skeleton.
Still taking HelloWorld as an example, we use maven archetype
to create the skeleton of the project, leaving the current Maven project directory.
In case of Maven3, simply run:
mvn archetype:generate
If it is Maven2, it is better to run the following command:
mvn org.apache.maven.plugins:maven-archetype-plugin:2.0-alpha-5:generate
A lot of information will let you use simpler mvn archetype:generate
commands directly, but this is not safe in Maven2, because the command does not specify the version of the Archetype plug-in, so Maven will automatically download the latest version. In turn, an unstable SNAPSHOT version may be obtained, causing the operation to fail. However in Maven3, even if the user doesn't specify a version, Maven will only resolve the latest stable version, so this is safe.
We are actually running the plug-in maven-archetype-plugin
, pay attention to the separation of the colon, its format is groupld:arifactld:version:goal
, orgapache.maven.plugins
it is the maven official plug-in groupId
, maven-archetype-plugin
it is the Archetype plug-in artifactId
, 2.0-alpha-5
it is the latest stable version of the plug-in, and generate
it is the plug-in target to be used.
Then you will see a long output, there are many available Archelypes to choose from, including the famous Appfuse
Archetype of the project, JPA
the Archetype of the project, etc. Each Archetype will have a number in front of it, and the command line will prompt a default number, the corresponding Archetype is, press maven-archetype-quickstart
Enter directly to select the Archelype, and then Maven will prompt you to enter the groupId
, artifactId
, version
and package name of the project to be created package
. Enter and confirm as follows:
Define value for groupId:: com.xiaoshan.mvnbook
Define value for artifactId::hello-world
Define value for version::1.0-SNAPSHOT
Define value for package:com.xiaoshan.mvnbook::com.xiaoshan.mvnbook.helloworld
Confirm properties configuration:
groupId: com.juvenxu.mvnbook
artifactId: hello-world
version: 1.0-SNAPSHOT
package: com.xiaoshan.mvnbook.helloworld
Y::Y
The Archetype plugin will create a project skeleton based on the information we provide. In the current directory, the Archetype plugin will create a subdirectory named hello-world
(we defined artifactId
), from which you can see the basic structure of the project: the basic one pom.xml
has been created, which contains the necessary information and a junit dependency; the main code directory src/main/java
It has been created, and there is a Java class in this directory com.xiaoshan.mvnbook.helloworld.App
. Note that the package name just defined is used here, and this class only has a simple output Hello World!
method main
; the test code directory src/test/java
has also been created, and contains a test case com.xiaoshan.mvnbook.helloworld.AppTest
.
Archetype can help us quickly build the skeleton of the project. In the previous example, we can develop the project based on the skeleton generated by Archetype HelloWorld
to save a lot of time.
In addition, here is just the simplest Archetype. If there are many projects with similar custom project structures and configuration files, you can develop your own Archetype once and for all, and then use the custom Archetype in these projects to quickly Generate project skeleton. Later I will elaborate on how to develop Maven Archetype.
《》