jar包怎么运行,jar包可以直接运行吗

spispi是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用框架扩展和替换组件。spi机制是这样的:读取META-INF/services/目录下的元信息,然后ServiceLoa

spi

spi 是 Java 提供的一套用来被第三方实现或者扩展的 API ,它可以用来启用框架扩展和替换组件。spi 机制是这样的:读取 META-INF/services/ 目录下的元信息,然后 ServiceLoader 根据信息加载对应的类,你可以在自己的代码中使用这个被加载的类。要使用 Java SPI,需要遵循如下约定:

jar包可以直接运行吗,当服务提供者提供了接口的一种具体实现后,在 jar 包的 META-INF/services 目录下创建一个以 “接口全限定名” 命名的文件,内容为实现类的全限定名;

接口实现类所在的 jar 包放在主程序的 classpath 中;

1.打开Exlipse文件,找到file---export 2.找到java这个文件,选择JAR file 3.选择需要打包的文件,选择一个jar文件导出的位置设置一个名字,点击下一步,注意不要点finish 4.点击下一步 5.选择你要启动的文件,最后点击fin。

主程序通过 java.util.ServiceLoder 动态装载实现模块,它通过扫描 META-INF/services 目录下的配置文件找到实现类的全限定名,把类加载到 JVM ;

SPI 的实现类必须携带一个不带参数的构造方法;

jar包怎么运行

现在我们来简单的使用一下吧。

spi 使用示例

建一个 maven 项目,定义一个接口 ( com.test.SpiTest ),并实现该接口( com.test.SpiTestImpl);然后在 src/main/resources/ 下建立 /META-INF/services 目录, 新增一个以接口命名的文件 ( com.test.SpiTest),内容是要应用的实现类( com.test.SpiTestImpl)。

public interface SpiTest { void test();}public class SpiTestImpl implements SpiTest { @Override public void test() { System.out.println("test"); }}

然后在我们的应用程序中使用 ServiceLoader来加载配置文件中指定的实现。

public static void main(String[] args) { ServiceLoader<SpiTest> load = ServiceLoader.load(SpiTest.class); SpiTest next = load.iterator().next(); next.test();}

这便是 spi 的使用方式了,简约而不简单。

jar包怎么运行

spi 技术的应用

那这一项技术有哪些方面的应用呢?最直接的 jdbc 中我们需要指定数据库驱动的全限定名,这便是 spi 技术。还有不少框架比如 dubbo ,都会预留 spi 扩展点比如:dubbo spi

写过 SpringBoot 的 starter 的都知道,需要在 src/main/resources/ 下建立 /META-INF/spring.factories 文件。这其实也是一种spi技术的变形。

jar 机制

通常项目中我们打 jar 包都是通过 maven 来进行的,导致很多人忽略了这个东西的存在,就像很多人不知道 jdb.exe 是啥玩意一样。下面我们不借助任何工具来打一个 jar 包并对 jar 文件结构进行解析。

命令行打 jar 包

Manifest-Version:用来定义 manifest 文件的版本,例如:Manifest-Version: 1.0

1、首先打开资源管理器的文件夹选项,在“文件类型”中找到 jar 文件。如果找不到,也可以自己新建一个。2、接着单击“高级”按钮,打开编辑文件类型对话框。在对话框中单击“新建”,打开新操作对话框。3、在操作名称中。

Main-Class:定义 jar 文件的入口类,该类必须是一个可执行的类,一旦定义了该属性即可通过 java -jar x.jar 来运行该 jar 文件。

Class-Path:指定该 jar 包所依赖的外部 jar 包,以当前 jar 包所在的位置为相对路径,无法指定 jar 包内部的 jar 包

签名相关属性,包括 Name, Digest-Algorithms, SHA-Digest 等

定义好元信息之后我们就可以打 jar 包了,以下是打包的一些常用命令

默认打包

生成的test.jar中就含test目录和jar自动生成的META-INF目录(内含MAINFEST.MF清单文件)

jar -cvf test.jar test

查看包内容

jar -tvf test.jar

解压jar包

jar -xvf test.jar

提取jar包部分内容

jar -xvf test.jar test\test.class

追加内容到jar包

追加 MAINFEST.MF 清单文件以外的文件,会追加整个目录结构

jar -uvf test.jar other\ss.class

追加清单文件

会追加整个目录结构( test.jar 会包含 META-INF 目录)

jar -uMvf test.jar META-INF\MAINFEST.MF

创建自定义MAINFEST.MF的jar包

jar -cMvf test.jar test META-INF

通过 -m 选项配置自定义 MAINFEST.MF 文件时,自定义MAINFEST.MF 文件必须在位于工作目录下才可以

jar -cmvf MAINFEST.MF test.jar test

jar 运行的过程

1、IDEA开发工具,项目使用maven打包命令打包,打包成功后在项目target目录下可以看到项目的jar包。1、打开jar包所在位置,点击地址栏,直接输入cmd,打开命令行窗口。2、在cmd中输入运行指令 注:以上demo基于SpringCloud的maven。

jar 运行过程和类加载机制有关,而类加载机制又和我们自定义的类加载器有关,现在我们先来了解一下双亲委派模式。

java 中类加载器分为三个:

BootstrapClassLoader 负责加载 ${JAVA_HOME}/jre/lib 部分 jar 包

ExtClassLoader 加载 ${JAVA_HOME}/jre/lib/ext 下面的 jar 包

AppClassLoader 加载用户自定义 -classpath 或者 Jar 包的 Class-Path 定义的第三方包

当我们执行 java -jar 的时候 jar 文件以二进制流的形式被读取到内存,但不会加载到 jvm 中,类会在一个合适的时机加载到虚拟机中。类加载的时机:

遇到 new、getstatic、putstatic 或 invokestatic 这四条字节码指令时,如果类没有进行过初始化,则需要先对其进行初始化。这四条指令的最常见的 Java 代码场景是使用 new 关键字实例化对象的时候,读取或设置一个类的静态字段调用一个类的静态方法的时候。

使用 java.lang.reflect 包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。

当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

当虚拟机启动时,用户需要指定一个要执行的主类(包含 main() 方法的那个类),虚拟机会先初始化这个主类。

当触发类加载的时候,类加载器也不是直接加载这个类。首先交给 AppClassLoader ,它会查看自己有没有加载过这个类,如果有直接拿出来,无须再次加载,如果没有就将加载任务传递给 ExtClassLoader ,而 ExtClassLoader 也会先检查自己有没有加载过,没有又会将任务传递给 BootstrapClassLoader ,最后 BootstrapClassLoader 会检查自己有没有加载过这个类,如果没有就会去自己要寻找的区域去寻找这个类,如果找不到又将任务传递给 ExtClassLoader ,以此类推最后才是 AppClassLoader 加载我们的类。这样做是确保类只会被加载一次。通常我们的类加载器只识别 classpath (这里的 classpath 指项目根路径,也就是 jar 包内的位置)下 .class 文件。jar 中其他的文件包括 jar 包被当做了资源文件,而不会去读取里面的 .class 文件。但实际上我们可以通过自定义类加载器来实现一些特别的操作

Tomcat 的类加载器

Tomcat 的类加载机制是违反了双亲委托原则的,对于一些未加载的非基础类(Object,String等),各个 web 应用自己的类加载器(WebAppClassLoader) 会优先加载,加载不到时再交给 commonClassLoader 走双亲委托。

tomcat 的类加载器:

Common 类加载器:负责加载 /common 目录的类库,这儿存放的类库可被 tomcat 以及所有的应用使用。

Catalina 类加载器:负责加载 /server 目录的类库,只能被 tomcat 使用。

Shared 类加载器:负载加载 /shared 目录的类库,可被所有的 web 应用使用,但 tomcat 不可使用。

WebApp 类加载器:负载加载单个 Web 应用下 classes 目录以及 lib 目录的类库,只能当前应用使用。

Jsp 类加载器:负责加载 Jsp ,每一个 Jsp 文件都对应一个 Jsp 加载器。

我们将一堆 jar 包放到 tomcat 的项目文件夹下, tomcat 运行的时候能加载到这些 jar 包的 class 就是因为这些类加载器对读取到的二进制数据进行处理解析从中拿到了需要的类

SpringBoot 的 jar 包

当我们将一个 SpringBoot 项目打好包之后,不妨解压看看里面的结构是什么样子的的

run.jar|——org| |——springframework| |——boot| |——loader| |——JarLauncher.class| |——Launcher.class|——META-INF| |——MANIFEST.MF|——BOOT-INF| |——class| |——Main.class| |——Begin.class| |——lib| |——commons.jar| |——plugin.jar| |——resource| |——a.jpg| |——b.jpg

classpath 可加载的类只有 JarLauncher.class, Launcher.class, Main.class, Begin.class。在 BOOT-INF/lib 和 BOOT-INF/class 里面的文件不属于 classloader 搜素对象直接访问的话会报 NoClassDefDoundErr 异常。Jar 包里面的资源以 Stream 的形式存在(他们本就处于 Jar 包之中),java 程序时可以访问到的。当 springboot 运行 main 方法时在 main 中会运行 org.springframework.boot.loader.JarLauncher 和 Launcher.class 这两个个加载器(你是否还及得前文提到过得 spi 技术),这个加载器去加载受 stream 中的 jar 包中的 class。这样就实现了加载 jar 包中的 jar 这个功能否则正常的类加载器是无法加载 jar 包中的 jar 的 class 的,只会根据 MAINFEST.MF 来加载 jar 外部的 jar 来读取里面的 class。

如何自定义类加载器

继承 ClassLoader 重写 findClass() 方法

public class MyClassLoader extends ClassLoader{ private String classpath; public MyClassLoader(String classpath) {this.classpath = classpath; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { // 该方法是根据一个name加载一个类,我们可以使用一个流来读取path中的文件然后从文件中解析出class来 }}

调用 defineClass() 方法加载类

public static void main(String []args) throws ClassNotFoundException,InstantiationException,IllegalAccessException,NoSuchMethodException,SecurityException,IllegalArgumentException,InvocationTargetException{ //自定义类加载器的加载路径 MyClassLoader myClassLoader=new MyClassLoader("D:\\lib"); //包名+类名 Class c=myClassLoader.loadClass("com.test.Test")if(c!=null){ // 做点啥 }}

总结

本文从比较基础的层面解读了我们频繁使用却大部分人不是很了解的两个知识点—— spi 和 jar 机制。希望大家看完这篇文章后能对 SpringBoot 中的一些“黑魔法”有更深入的了解,而不是停留在表面。

1、首先确保自己的系统是在安装好java环境条件下,按下Windows+R键,在弹出的运行框中输入CMD:2、先在弹出的黑框框中切换到.jar文件的所在目录,在黑框中输入java -jar ***.jar,***表示要运行的.jar文件名,如图。

上一篇 2023年02月05 10:59
下一篇 2023年02月08 23:18

相关推荐

  • 怎么更改文件属性,windows怎么修改文件属性

    无论是学习还是工作,我们都需要用到电脑上的文件夹,windows怎么修改文件属性,文件夹在我们的生活中扮演着重要的角色。正因为如此,我们有时候需要给自己的文件夹设置密码和设置权限,这样我们自己的文件夹

    2023年01月22 296
  • 华硕bios怎么升级,华硕主板一键升级bios的按键

    说起升级BIOS,其实很多普通用户还是不敢轻易尝试的,一方面是因为刷BIOS是有风险的,少有不慎可能造成电脑无法正常启动,另一方面也是因为不知道BIOS是否有必要升级。今天快启动小编以华硕主板为例,华

    2023年01月22 279
  • 怎么设置字间距,电脑上每行字的间距怎么调整

    电脑上每行字的间距怎么调整,word文档字间距怎么调?word我们大家都知道什么,也用的不少,办公软件中每个成员都有自己的优点,word文档自然也不例外,Word文件平时最适合用于内容编辑。但是相信大

    2023年02月14 297
  • 发出去的邮件怎么撤回,外域邮箱有没有办法撤回

    有很多注册VIP邮箱都是因为他的容量、安全、和一些特色功能,外域邮箱有没有办法撤回,TOMVIP邮箱的安全和便捷性高,其中邮件撤回功能解决误发邮件的情况。企业邮箱邮件撤回1、首先先在电脑上登录自己的个

    2023年01月23 247
  • 华硕怎么进bios,华硕不进系统只进BIOS

    华硕主板bios如何设置?一些用户想要学习华硕主板bios设置教程,华硕不进系统只进BIOS,不知华硕主板bios如何设置的用户,下面就让小编教你华硕主板bios如何设置的教程吧,希望对你们有所帮助。

    2023年02月04 224
  • 谷歌怎么登陆

    早在2014年,Google就宣布了MaterialDesign(材料设计),这是一种视觉语言,可以帮助弥合其Web和Android用户界面。从那时起,谷歌账号登入,谷歌就一直在更新其GSuite应用

    2023年02月04 286
  • 麦克风降噪怎么调,win10麦克风怎么设置降噪

    首先排查故障原因:1.麦克风本身没有问题!(经测试可以正常使用)2.声卡设置没有问题!(换过声卡!还是同样出现问题!)打开设置——其他设置——双麦克风降噪开启或关闭。圆圈中打钩表示功能开启,取消勾表示

    2023年02月08 214
  • 怎么增加虚拟内存,win10

    win10,如何建立虚拟内存和如何操作呢?它不像你想的那么困难,那么如何操作它呢?在这里,我将向您展示设置虚拟内存的详细操作方法。什么是虚拟内存?这里有一个简单的解释给你。虚拟内存实际上使用硬盘上方的

    2023年02月05 272
  • 微博怎么删除评论,微博评论列表能清空吗

    刘俊海也表示,前述“6块糖卖466元”一事,若如顾客所讲,那存在人为误导消费者,损害了消费者的知情权、选择权和公平交易权,涉嫌价格欺诈,除非商家能自证清白。值得一提的是,在中消协近日公布的2022年十

    2023年02月13 214
  • 交换机怎么连接,内网交换机怎么连接

    好听的音乐会伴随你更好地学习成长!点击图标链接自动播放音乐。概述:交换机的连接主要有三种方式,级联方式、堆叠方式和集群方式。级联方式实现简单,内网交换机怎么连接,只需一根普通的双绞线即可,节约成本而且

    2023年01月16 217
  • 怎么看显卡驱动版本,如何查看nvidia显卡驱动版本

    如何查看nvidia显卡驱动版本,IT之家1月7日消息,NVIDIA今天发布了适用于GNU/Linux、FreeBSD和Solaris系统的NVIDIA525.78.01显卡驱动程序,以解决先前版本中

    2023年02月06 213
  • 微信怎么开通微众银行,微信里怎么开通微众银行账户

    4月7日消息,微信支付已在所有试点区域中全面开放对数字人民币的支持。用户实名开通微众银行(微信支付)数字人民币钱包后,微信里怎么开通微众银行账户,可以使用数字人民币App或微信进行支付。,日前,由人民

    2023年01月21 236
  • win7怎么安装,win7系统重装

    win7系统重装,Windows7系统已经发布十多年了,时至今日仍然有不少朋友想给电脑装上Win7使用,但并不是所有电脑都可以装win7系统的。更多教程尽在小白系统重装官网1.首先我们在网页中输入zj

    2023年01月15 218
关注微信