小小白祈祷中...

今天我们来聊聊jar包。作为Java程序员,日常工作就是打自己的jar包和学别人的jar包。

什么是jar包?

jar包 Java Archive File,顾名思义,它与 Java 息息相关的,是 Java 的一种文档格式,同时也是一种与平台无关的文件格式,可将多个文件合成一个jar文件。

大伙会觉得它与zip包非常类似,确实,确切地说,它就是 zip 包jar zip 唯一的区别就只是在 jar 文件的META-INF目录下多包含了一个 MANIFEST.MF 文件作为jar里面的"详情单",这个文件里包含了该Jar包的版本、创建人和类搜索路径Class-Path等信息,当然如果是可执行Jar包(包含main()方法),还会包含Main-Class属性,表明main()方法入口。其中较为重要的Class-PathMain-Class

此外,由于jar包主要是对.class文件进行打包,而java编译生成的.class文件是跨平台的,这就意味着jar包也是跨平台的,这是jar包的优势。

小伙伴们在平时编写代码的时候,可以把自己代码中的通用部分分离出来,积累一些通用的工具类,将其逐渐模块化,最后打成jar包供自己在别的项目或者模块中使用。同时可以不断完善jar包里面的内容,将其做得更加容易理解和使用。

因此,将自己写好的通用工具类或者框架分离出来,打成jar包供自己或他人调用,不仅能够提升自己的编程水准,同时也能扩宽整个Java生态圈,这也是Java如此受欢迎的原因之一。

如何打jar包?

现在,我们来试着打包我们自己写好的java源文件。

记得最早接触的一个第三方jar包,是 mysql-connector-java-8.0.24.jar,即Java中著名的jdbc驱动包

虽然这个驱动包使用起来非常方便,但是仍然有许多重复的代码需要我们去编写,所以一些主流的Java框架会对其进行再次封装,比如SpringBoot框架中,我们只需要填入数据库地址,用户名,密码等基本信息即可访问我们的数据库,下面,我们就尝试着对这个驱动包进行二次封装,并把它打包成jar包,以下是我们的目标:

  • 向用户开放一个主构造方法:ConnectMysql(String url, String username, String password)用于连接mysql数据库。
  • 用户只需调用 insert(), delete(), update(), select() 四个方法即可实现对于数据库的 增 删 改 查 四个操作。

二次封装

首先对jdbc驱动包做二次封装,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package com.sixibiheye.mysql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class ConnectMysql {
private String url;
private String user;
private String password;
private Statement statement;

public ConnectMysql(String url, String user, String password) {
this.url = "jdbc:mysql://" + url + "?useUnicode=true&characterEncoding=utf8";
this.user = user;
this.password = password;
this.init();
}

private void init() {
try {
String driver = "com.mysql.jdbc.Driver";
Class.forName(driver);
Connection con = DriverManager.getConnection(this.url, this.user, this.password);
if (!con.isClosed()) {
System.out.println("数据库连接成功!");
}

this.statement = con.createStatement();
} catch (ClassNotFoundException var3) {
System.out.println("对不起,无法找到驱动!");
var3.printStackTrace();
} catch (Exception var4) {
var4.printStackTrace();
}

}

public ResultSet select(String sql) {
try {
return this.statement.executeQuery(sql);
} catch (SQLException var3) {
System.out.println("查询异常......");
var3.printStackTrace();
return null;
}
}

public int insert(String sql) {
try {
int number = this.statement.executeUpdate(sql);
System.out.println("插入成功!受影响的行数:" + number);
return number;
} catch (SQLException var3) {
var3.printStackTrace();
return 0;
}
}

public int update(String sql) {
try {
int number = this.statement.executeUpdate(sql);
System.out.println("更新成功!受影响的行数:" + number);
return number;
} catch (SQLException var3) {
var3.printStackTrace();
return 0;
}
}

public int delete(String sql) {
try {
int number = this.statement.executeUpdate(sql);
System.out.println("删除成功!受影响的行数:" + number);
return number;
} catch (SQLException var3) {
var3.printStackTrace();
return 0;
}
}

记住 ConnectMysql 这个类放在了 com.sixibiheye.mysql 包里,现在,我们尝试着将其打包成jar包。同样的,我们不借助任何第三方工具,采用最原生的java命令来打jar包。下面的教程假设小伙伴们已经配置好了java的基础环境。(Mac用户与Windows用户均可用)

制作jar包清单材料

首先,我们来看看,打包成一个jar包需要哪些东西:

img

我们新建一个MakeJar文件夹(文件夹名任意),在这个文件夹中,添加三个材料:

  • 编译后的.class文件(如果有多个.class文件且处于不同的包里,注意放到对应的包里)
  • MANIFEST.MF清单文件(待会解释)
  • jar包所依赖的jar包(此例中由于使用到了jdbc驱动包,故需要将其添加进去,此外,java自带的jar包无需添加进去,如java.sql.*

第一,三个材料大家容易理解,这里主要介绍一下MANIFEST.MF清单文件, 清单文件用来指明我们打jar包的一些基本信息,最重要的是主区(Main Section)的四个属性:

  • Manifest-Version

​ 版本号,如1.0

  • Create-By

​ 创建者,一般格式:jdk版本(开发者或公司) ,如 1.6.0_35(sum Microsystems Inc.),可以省略。

  • Main-Class

可执行jar包(即包含main方法)的入口类名,如果我们编写的多个类含有多个main方法,此属性可指定调用jar包的入口类的main方法。如果编写的 ConnectMysql 类中无main()方法,则Main-Class属性可以省略。值得注意的是,属性值一定要包含类所在的包名,如:

Main-Class: com.sixibiheye.mysql.ConnectMysql

  • Class-Path

    JVM搜索依赖的jar包的路径,三种情况:

  • 如果依赖的jar包就在当前路径,直接使用jar包名即可;

  • 如果依赖的jar包不在当前路径,使用全局路径;

  • 如果依赖的jar包在当前路径的子路径中,使用相对路径。

如果有多个依赖的jar包,包与包之间用一个空格隔开即可。此处,我们所依赖的jar包就在当前路径,所以直接写jar包名即可。

当然清单文件中还可以添加一些其他内容,感兴趣的小伙伴们可以去查阅有关资料。

此例中,我们的MANIFEST.MF清单文件长这样:

img

注意:属性与属性值之间有一个空格;最后一定要留出一空行,否则最后一行读取不到。

jar

接下来,我们开始打包,Java提供了 jar命令 用于打jar包。

打开我们的cmd(控制台),将当前路径切换至MakeJar,接着输入如下命令:

jar -cvfm mysql-connector-java.jar MANIFEST.MF -C ./ .

命令中,mysql-connector-java.jar为生成的jar包的名称,MANIFEST.MF 表示使用指定此清单文件用于生成jar包,“ ./ ”和后面的“ . ”之间有一空格,控制参数c,v,f,m的含义分别是:

  • -c:即create,创建一个jar
  • -v:即view,生成详细的报告并输出至标准设备
  • -f:即force,指定生成的jar包的名称
  • -m:即manifest.mf清单文件,指定一个清单文件

末尾 “ -C ” 参数的含义是, 转到相应的目录下执行jar命令,即相当于cd到那个目录,然后不带“ -C ” 参数执行jar命令。

图示如下:

img

如果输出类似上述信息,则表示打包成功。

MakeJar文件夹中,我们可以看到生成的 **mysql-connector-java.jar **:

img

一个简单的jar包就生成完毕了。

jar包测试

我们来测试一下这个jar包好不好使,在上述目录中,编写一个Test.java类,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.sixibiheye.mysql;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
* @author sixibiheye
* @date 2021/11/3
* @apiNote 自定义jar包的测试类
*/

public class Test {
public static void main(String[] args) throws SQLException {
ConnectMysql connector = new ConnectMysql("localhost:3306/sixibiheye","everyone","123456");
String sql = "select username,sex from user;";
//ResultSet类,用来存放获取的结果集!!
ResultSet rs = connector.select(sql);
System.out.println("-----------------");
System.out.println("执行结果如下所示:");
System.out.println("-----------------");
System.out.println("姓名" + "\t" + "性别");
System.out.println("-----------------");

String name = null;
String sex = null;
while(rs.next()){
//获取stuname这列数据
name = rs.getString("username");
//获取stuid这列数据
sex = rs.getString("sex");

//输出结果
System.out.println(name + "\t" + sex);
}
rs.close();

}
}

进入MakeJar文件夹中,在命令行输入如下命令:

img控制参数 “ -cp ” (即ClassPath)告诉JVM源文件编译运行时所依赖的jar包的路径,路径的写法与之前清单文件中的Class-Path类似。

可以看到,我们成功地获得了想要的数据。使用封装好的jar包连接数据库并获得数据的代码量要少得多。这再一次体现出封装的优越性。