Java组件化开发:jar包

news2024/12/21 21:54:25

我在java基础:原始数据类型,包的创建与导入-CSDN博客一文中记录了包的使用,此文就详细讲解一下IDEA中如何进行组件化开发。

介绍

现在的软件系统功能越来越复杂,规模也越来越大,为了应对这种挑战,人们将“老系统”中可以重用的代码抽取出来单独构建为 “组件(Component)”,开发新系统时,直接使用这些现成的组件而不是一切都重新再来,是“组件化开发(CBD:Component Based Development)”的基本思想。

Java应用程序开发时,最普遍使用的组件就是jar包,JDK的各个组件,基本上都是以jar包的形式提供给Java开发者的。

什么是Jar包?
▪ Jar文件其实是一个压缩包,遵循于Zip数据压缩标准,可以使用WinRAR等解压软件打开。
▪ Jar文件中包容一个清单(manifest)文件,包容一些重要信息。比如可以在windows资源管理器中“双击”执行的jar包,其清单文件必须指明包中哪个类是“主类(main class)”,从而让JVM知道应该从哪个类中的main方法开始执行。

组件化开发过程

下面我们通过一个例子一步步地展示以重用为目的的Java代码演化过程:

原始程序

比如说我在一个程序内写了一个倒序输出字符串的功能


public class ReverseString1 {

    // 示例程序功能:将一个字符串倒序输出
    public static void main(String[] args) {
        String str = "abcd";
        StringBuffer buff = new StringBuffer();
        for (int i = str.length() - 1; i >= 0; i--)
            buff.append(str.charAt(i));
        System.out.println(buff.toString());
    }

}

示例代码中,将所有代码都放到了main()方法中,并且混杂了数据处理代码(实现字符串倒序)和输出代码(println)。这导致代码无法重用。

重构:方法抽取

此时我们可以把倒序输出字符串的方法抽取出来,写成这样

public class ReverseString2 {

	public static void main(String[] args) {
		String str = "abcd";
		System.out.println(reverseString(str));
	}

	// 方法功能:将一个字符串倒序输出
	private static String reverseString(String inputStr) {
		StringBuffer buff = new StringBuffer();

		for (int i = inputStr.length() - 1; i >= 0; i--)
			buff.append(inputStr.charAt(i));

		return buff.toString();
	}

}

但是在同一个项目中,倒序输出的功能如果在多个地方都用到,就要把reverseString()方法的源代码在每个类中都Copy & Paste一遍。

重构:类的引入

//导入另一个模块包中的类
//Main.java文件
import cn.utils.MyStringUtil;

public class Main {
    public static void main(String[] args) {
        String str="abcd";
        System.out.println(MyStringUtil.reverseString(str));
    }
}
//MyStringUtil.java文件,放在Main.java 同目录的 cn/utils目录下
package cn.utils;
/**
 * 此类封装一些字符串操作的功能
 */
public class MyStringUtil {
    // 方法功能:将一个字符串倒序输出
    public static String reverseString(String inputStr) {
        StringBuffer buff = new StringBuffer();

        for (int i = inputStr.length() - 1; i >= 0; i--)
            buff.append(inputStr.charAt(i));

        return buff.toString();
    }
}

将需要重用的代码,放到独立的类中,同一项目中就能很容易地重用这一功能了。

只需要在项目要用到这个类时,import 这个类就能使用类中的方法。

不过问题又来了,如果我有一个新项目,如果需要调用许多不同的类

将需要跨项目重用的代码,封装为一个单独的jar包,然后在新项目中将其添加进来,这样一来,只要有一个jar包,就可以直接使用jar包中的代码。

 tips:如果你看这个文件夹名用 (.) 连接不习惯的话,可以更改一下显示方式

跨模块

在你的项目里新建一个模块

我这边是改名为MyJavaLibrary就点创建了,你也能改成任意名字

创建完之后,你会发现项目中多了一个模块,它也有一个src文件夹,可以向其中添加相应的Java文件。而原来主目录下的那个模块被称为默认模块。

tips:在IntelliJ中,每个“项目(Project)”都可以包容多个“模块(Module)”,模块是IntelliJ编译Java项目的基本单元。

你把模块里没用的那个Main.java删掉,并把 MyStringUtil.java 文件移到这个模块的src目录下。

然后你就会发现package 后面有一个红色的报错,因为你没有给你的包放在相应的目录下,你可以手动创建 cn/utils 目录,也可以把鼠标移上去,自动创建目录.

tips: IntelliJ提供了移动类到特定包中的“代码重构”功能,可以用它把MyStringUtil类移到指定的包中,IntelliJ会自动创建相应的文件夹。


更改好目录后,MyStringUtil.java文件 是不报错了,但是Main.java文件还没有成功导入

那是因为默认模块中的代码,如果要使用另一模块中的代码,需要在这两个模块之间建立依赖关系。

打开项目结构

打开模块 - 默认模块 - 依赖

正常情况下只有你使用的JDK的依赖,我这里是JDK22

点击“+”号,选择模块依赖,选择你刚刚创建的模块并确定

默认模块创建好对MyJavaLibrary模块的依赖关系之后,就可以使用里面的MyStringUtil类了。

如果你的idea还是显示报错,可以重新打开项目看看。

使用给模块添加依赖关系这种手段,可以方便地组织代码,实现同一项目内“源代码级别”的“跨模块”的代码重用。

jar包

更进一步,如果希望这些代码能“跨项目”重用,则可以将MyJavaClassLibrary模块导出为jar包,从而被另外的项目所重用。

在IDEA中生成jar包

还是在项目结构中,点击  工件 - JAR - 来自具有依赖项的模块  

选择需要导出成jar包的模块,确定。

继续确定,此时就已经准备好要构建的jar包了

然后在构建这里选择构建工件

在这里选构建

你就能发现jar包已经生成了。

使用命令行生成jar包

我们现在已经有一个 java 文件在"  …… \src\cn\utils\MyStringUtil.java "

把命令行定位到src目录下,(建议先把out文件夹清空,这样有变化了可以看的更佳直观。或者把\cn\utils\MyStringUtil.java 整体移到一个空文件夹操作)

执行这行命令来编译MyStringUtil.java  ,-d out 表示编译后的 .class 文件会被放入 out 目录,保持包的目录结构。

javac -d out cn/utils/MyStringUtil.java

接下来,你需要将编译好的 .class 文件打包成 .jar 文件。仍然在 src 目录中运行以下命令

注意:out 后面要加上一个空格和一个“ . ”

 jar cf my-string.jar -C out .

解释:

  • jar cf 是创建 .jar 文件的命令,其中 c 表示创建,f 表示指定文件名。
  • my-string.jar 是输出的 .jar 文件名。
  • -C out . 表示切换到 out 目录并将其中的文件打包进 .jar 文件。

打包后,你应该在当前目录中看到生成的 my-string.jar 文件。

验证 .jar 文件

你可以验证 .jar 文件内容,使用以下命令列出它包含的内容:

jar tf my-string.jar

然后你能看到jar文件内部的结构

使用jar包

此时你可以创建一个新项目。在这个项目的主目录下创建一个叫  libs  的文件夹,把之前生成的MyJavaLibrary.jar 文件放进这个目录。

就像这样

然后还是打开 项目结构 - 模块,添加JAR文件即可,和前面添加模块步骤一样,就不一一截屏了。

可执行的jar包

生成jar包时,可以指定主类(Main Class),在Windows资源管理器中,双击这个jar包,就能直接运行它。但这有个前提条件,那就是这个jar包必须包容所有所需的组件。

如果一个指定了主类(Main Class)的jar包,它依赖于另外的jar包,则必须将其合并起来,才能正确运行。

让JAR包可执行,关键在于指定主类。可以点击右侧的文件夹图标,在打开的对话窗口中选择主类。

所谓“主类”,就是程序入口点(即main方法)所在的那个类。

从依赖的jar包中抽取用到的类型,加入到jar包中。这里是已经帮你自动提取完了,点击确定即可。

还是一样点击,构建工件。

完成之后在artifacts文件夹下可以找到生成的jar包,在production文件夹下可以看到生成的jar包的内部结构。

此时生成的jar包,不再依赖于其他的jar包

我们可以将这个jar包移动到任何地方,并使用java的-jar参数,可以直接运行一个“可运行的”JAR包。

java -jar jar_Test.jar

tips:如果电脑里装了多个版本的java,要确保命令行默认的java版本和你编译时用的版本相同,(用  java -version  查看版本)否则可能会无法运行。如果不相同的话可以去系统环境变量里更改一下优先级,或者重新用另一个版本的JDK重新编译。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2185083.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入解析Python错误消息及解决方法

深入解析Python错误消息及解决方法 Python是开发者广泛使用的语言,因其简洁的语法和强大的标准库而深受欢迎。然而,Python程序在运行过程中,错误不可避免。理解Python的错误消息并正确处理这些错误,是提升代码质量和调试效率的重…

3.点位管理改造-列表查询——帝可得管理系统

目录 前言一、与页面原型差距1.现在:2.目标:3. 存在问题:所在区域和合作商ID展示的都是ID,而不是名称;同时合作商ID应改为合作商 二、修改1.重新设计SQL语句2.修改mapper层,使用Mybatis中的嵌套查询3.修改s…

AI人工智能人像修饰中文面板PS插件 Retouch Pro 3.2.0 中文汉化版

AI人工智能人像修饰PS扩展插件 Retouch Pro 3.2.0 中文汉化版 支持软件:PS 2018 – PS 2025或更高版本 系统要求:Windows系统 或 MacOS系统 出处:https://www.aeown.com/thread-3061-1-1.html Retouch Pro Panel 有一个非常强大和先进的人工…

Python Tips6 基于数据库和钉钉机器人的通知

说明 起因是我第一版quant程序的短信通知失效了。最初认为短信是比较即时且比较醒目的通知方式,现在看来完全不行。 列举三个主要问题: 1 延时。在早先还能收到消息的时候,迟滞就很严重,几分钟都算短的。2 完全丢失。我手机没有…

ACP科普:SoSM和CPO

在Scrum of Scrums(SoS)框架中,SoSM(Scrum of Scrums Master)和CPO(Chief Product Owner)是两个关键角色,负责协调多个Scrum团队的工作,确保项目的顺利进行。以下是对这两…

Android AMS介绍

注:本文为作者学习笔记,如有误,请各位大佬指点 系统进程运行环境的初始化 Context是一个抽象类,它可以访问application环境的全局信息和各种资源信息和类 context功能: 对Activity、Service生命周期的管理通过Intent发…

c++进阶之多态讲解

这篇文章和大家一起学习一下c中的多态 多态的概念 多态的概念:通俗来讲,就是多种形态。多态分为编译时多态(静态多态)和运⾏时多态(动态多态)。 什么是静态多态 前⾯讲的函数重载和函数模板,它们传不同类型的参数就可以调用不同的函数&…

深入理解 C 语言中的内存操作函数:memcpy、memmove、memset 和 memcmp

目录: 前言一、 memcpy 函数二、 memmove 函数三、 memset 函数四、 memcmp 函数总结 前言 在 C 语言中,内存操作函数是非常重要的工具,它们允许我们对内存进行直接操作,从而实现高效的数据处理。本文将深入探讨四个常用的内存操…

zabbix7.0web页面删除主机操作实现过程

前言 服务端配置 链接: rocky9.2部署zabbix服务端的详细过程 被监控端配置 链接: zabbix7.0监控linux主机案例详解 环境 主机ip应用zabbix-server192.168.10.11zabbix本体zabbix-client192.168.10.12zabbix-agent zabbix-server(服务端已配置) zabbix-client(被监控端已配置…

Bruno:拥有 11.2k star 的免费开源 API 测试工具

Github 开源地址: https://github.com/usebruno/bruno 官网地址: https://www.usebruno.com/ 下载地址: https://www.usebruno.com/downloads 使用文档: https://docs.usebruno.com/ Bruno 是一款全新且创新的 API 客户端&…

微调学习记录

目前看到的市面上的微调文章,想大体上给他们分个类,方便后续进行重点学习 参数高效微调 1. LoRA 不用多说含金量 2. Rein https://github.com/w1oves/rein 把它也算进来了,类似。 Adapter adapter类的我感觉都大差不差,具体…

VisionTS:基于时间序列的图形构建高性能时间序列预测模型,利用图像信息进行时间序列预测

构建预训练时间序列模型时面临的主要挑战是什么?获取高质量、多样化的时间序列数据。目前构建基础预测模型主要有两种方法: 迁移学习LLM:通过针对时间序列任务定制的微调或分词策略,重新利用预训练的大型语言模型(LLM…

餐饮重点企业在AI领域的布局,看方大的AI实践

大家好,我是Shelly,一个专注于输出AI工具和科技前沿内容的AI应用教练,体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具,拥抱AI时代的到来。 AI已经被应用在餐饮餐厨行业的哪些方面&am…

Spring注解系列 - @Autowired注解

文章目录 使用总结注入原理Autowired 注入过程InjectionMetadataInjectedElement依赖注入查找过程findAutowireCandidates 缓存注入信息 Resource 注解 使用总结 Autowired注解可以自动将所需的依赖对象注入到类的属性、构造方法或方法中,从而减少手动注入依赖的代…

Android Compose的基本使用

前言: Compose这个东西呢,好处我没发现,坏处就是学习成本和低版本兼容. 不过,看在官方力推的份儿上,有空就学一下吧. 当初的kotlin,很多人说鸡肋(包括我)!现在不也咔咔用纯kotlin做项目吗?哈哈哈哈. 未来的事情,谁说得清呢? 首先创建一个专用的Compose项目 对没错!看到E…

体系结构论文(五十三):Featherweight Soft Error Resilience for GPUs 【22‘ MIRCO】

Featherweight Soft Error Resilience for GPUs 一、文章介绍 背景:软错误通常由高能粒子(如宇宙射线和α粒子)打击电路造成的位翻转,可能导致程序崩溃或产生错误输出。随着电子技术的进步,电路对这种辐射引发的软错…

Arduino UNO R3自学笔记14 之 Arduino使用HC-SR04模块如何测量距离?

注意:学习和写作过程中,部分资料搜集于互联网,如有侵权请联系删除。 前言:学习使用HC-SR04模块测距。 1.HC-SR04模块介绍 基本参数: ●使用电压:DC---5V ●静态电流:小于2mA ●电平输出&#…

【计算机网络】传输层UDP和TCP协议

目录 再谈端口号端口号范围划分认识知名端口号查看知名端口号两个问题 UDP协议UDP特点UDP的缓冲区基于UDP的应用层协议 TCP协议TCP协议格式确认应答机制超时重传机制连接管理机制(三次握手与四次挥手)理解TIME_WAIT状态理解CLOSE_WAIT状态滑动窗口快重传…

wsl(1) -- win11环境配置

1.前言 本专栏主要记录了我配置wsl的过程,以便日后回忆。 2. 开启WSL可选功能 打开设置,点击应用,点击可选功能,点击更多Windows功能,查看是否开启了【适用于Linux的Windows子系统】和【虚拟机平台】 3. 更新wsl …

【JavaEE初阶】深入理解多线程阻塞队列的原理,如何实现生产者-消费者模型,以及服务器崩掉原因!!!

前言: 🌈上期博客:【JavaEE初阶】深入解析单例模式中的饿汉模式,懒汉模式的实现以及线程安全问题-CSDN博客 🔥感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客 ⭐️小编会在后端开发的学习中不断更新~~…