前两篇博客分别学习了maven环境搭建,手动创建maven工程,配置eclipse下的maven环境,今天学习maven的依赖关系。
我们现在已经知道使用maven来管理项目,我们可以方便的分模块来开发,这里我创建一个用户管理系统,并且分模块的来开发,并且配置依赖关系,来深入理解maven的依赖关系。
创建maven工程
这里我首先创建一个核心模块,打开eclipse->new->maven project
这里选择”maven-archetype-quickstart”
这里需要填写工程中pom.xml文件需要的基本内容:
groupId
artifactId
package
完成之后,maven会自动帮我们创建好目录已经pom.xml文件。
依赖的查询
在工程中总是要用到其他的一些包,在maven中所有的依赖都是通过坐标来表示的,也就是我们前面提到的(groupId,artifactId,version)通过这三个坐标描述的值,就可以确定一个唯一的依赖。
仓库查询的网站
http://mvnrepository.com/
这里我们需要用到hibernate的core模块,进入该网站搜索hibernate,选择hibernate-core,这里我选择4.1.0
如图,将上边的依赖复制到我们的pom.xml中的dependencies标签中,就可以添加hibernate4.0的核心包以及其依赖的所有包。如下图:
添加实体类和映射文件
创建Users.java
在”src/main/java”中创建实体类:Users.java
package com.test.user.user_core;
public class Users {
private int uid;
private String uname;
private double uage;
public Users(){}
public Users(String uname, double uage) {
this.uname = uname;
this.uage = uage;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public double getUage() {
return uage;
}
public void setUage(double uage) {
this.uage = uage;
}
}
创建Users.hbm.xml
在maven中所有的资源都是存放在”src/main/resources”文件夹中的,所以我们在该文件夹中新创建一个com.test.user.user_core包,并将Users.hbm.xml放到该包下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.test.user.user_core.Users">
<id name="uid">
<generator class="increment"/>
</id>
<property name="uname"/>
<property name="uage"/>
</class>
</hibernate-mapping>
创建hibernate.cfg.xml
同样hibernate.cfg.xml也属于资源文件,因此我们同样将其放到”src/main/resources”目录下。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.bytecode.use_reflection_optimizer">false</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<mapping resource="com/test/user/user_core/Users.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>
记得要在hibernate.cfg.xml中配置该映射文件:
<mapping resource="com/test/user/user_core/Userinfo.hbm.xml"/>
注意,这里使用到了mysql,所以需要添加mysql的依赖
创建实体类对应的表
到目前为止所有的实体类和映射文件都已经写好了,现在需要生成实体类对应的表,运行下面这段代码:
Configuration cfg = new Configuration().configure();
SchemaExport exp = new SchemaExport(cfg);
exp.create(true, true);
编写测试类
在maven中所有的测试类代码都是存放在”src/test/java”文件夹中的,我们在该文件夹中新建UserTest.java,这里我只测试一个添加的方法。
package com.test.user.user_core;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class UserTest {
@Test
public void testAdd() {
Configuration cfg = new Configuration().configure();
SessionFactory factory = cfg.buildSessionFactory();
Session session = factory.openSession();
try {
session.beginTransaction();
Users u = new Users("444",13);
session.save(u);
session.getTransaction().commit();
} catch (HibernateException e) {
e.printStackTrace();
session.getTransaction().rollback();
}
session.close();
}
}
使用maven编译测试
到现在为止,测试方法已经写好了,我们可以测试添加user的方法了。
1.右键pom.xml文件
2.run as
3.maven build
此时会出现如下界面:
注意,此时运行可能会出现如下错误:
-Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME environment variable and mvn script match.
解决办法
可以设一个环境变量M2_HOME指向你的maven安装目录
M2_HOME=D:\Apps\apache-maven-3.3.1
然后在Window->Preference->Java->Installed JREs->Edit
在Default VM arguments中设置
-Dmaven.multiModuleProjectDirectory=$M2_HOME
还可能会有如下错误
Unknown system variable ‘language’
解决办法
这是因为我使用的依赖mysql的jar文件是mysql-connector-java-5.1.36.jar,这个版本太高了,改用mysql-connector-java-5.1.24.jar版本即可
此时运行”Maven build”,已经成功将数据插入到数据库了。
完整的工程结构如下图:
打包工程
运行clean install命令打包该工程,需要注意的是,运行该命令的时候,maven会自动运行clean test package install这几个命令
此时会在target目录下生成user-core-0.0.1-SNAPSHOT.jar的包,并且会打包到本地仓库中:
依赖的传递性
接下来在创建一个”user-dao”工程来说明”依赖的传递性”
在该工程中,引入user-core的依赖
<dependency>
<groupId>com.test.user</groupId>
<artifactId>user-core</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
可以看到,user-dao并没有添加hibernate和mysql的依赖,却自动拥有这些jar文件,这是因为user-dao依赖于user-core,而user-core模块又依赖于hibernate和mysql,这就是依赖的传递性。
注意:依赖传递性的范围默认是基于scope是”compile”的,如果是其他的则默认是不会传递的
依赖的范围
依赖的范围分为以下几点:
1.test:只会在测试返回有效,在编译和打包时候,都不会使用该依赖
2.compile:在编译范围有效,在编译和打包时候,都会使用
3.provided:在编译和测试的过程有效,在最后生成war包时候,不会加入。
4.runtime:在运行的时候依赖,在编译的时候不依赖。
默认的依赖范围是compile
依赖传递性的冲突问题
试想如果出现如下现象:
user-core工程依赖于hibernate4.1版本
user-dao 工程依赖于hibernate5.1版本
那么此时,当user-service工程依赖既依赖于”user-core”又依赖于”user-dao”这两个工程,那么根据依赖的传递性,此时”user-service”到底依赖于hibernate4.1版本还是hibernate5.1版本呢??
分两种情况
当依赖的路径长度相同的时候
a->b1.0
c->b1.1
d->a,c
可以看到此时对于d来说依赖于a和c,依赖的路径长度是相同的,那么此时在d的pom.xml依赖当中,那么依赖先写,就优先依赖那个版本。
比如在d的pom.xml中是这样写的
<dependencies>
<dependency>
<groupId>c</groupId>
...
</dependency>
<dependency>
<groupId>a</groupId>
...
</dependency>
</dependencies>
可以看到此时c的依赖关系是在a的依赖关系之前的,那么此时d会首先依赖c的依赖,也就是b1.0版本。
当依赖的路径长度不同的时候
- a->b1.0
- c->b1.2
- d->a,c (a的依赖在c的前面,所以此时d依赖于b1.0)
- f->d,c
可以看到此时f->c->b1.2有两级路径 ,而f->d->a->b1.0有三级路径,此时,虽然在pom.xml文件当中,d的依赖在c的依赖前面配置,但是优先会选择路径较短的依赖,所以此时f依赖的是b1.2版本。
自定义依赖关系
对于上面提到的两种默认的依赖传递策略,如果我们想要更改也是可以的,比如对于
a->b1.0
c->b1.1
d->a,c
<dependencies>
<dependency>
<groupId>c</groupId>
...
</dependency>
<dependency>
<groupId>a</groupId>
...
</dependency>
</dependencies>
这样的依赖,可以看到此时”d默认是依赖于b1.1”,那么,如果需要让”d依赖于b1.0”,只需要做如下配置即可。
<dependencies>
<dependency>
<groupId>c</groupId>
...
<exclusions>
<exclusion>
<groupId>b1.1的groupId</groupId>
<artifactId>b1.1的artifactId</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>a</groupId>
...
</dependency>
</dependencies>