有的时候需要把单个类文件放到 Linux 环境上去运行,但是又不想引入 SpringBoot 相关的依赖以接口的形式来访问,如下介绍下使用 Maven 指定加载的类,打包到 Linux 环境运行准备工作拿这篇文章的类 【打破 OS 壁垒:Java 跨平台硬件信息采集的“终极方案”】中的 SystemInfoCollector.java 来举例首先需要把 main 方法给加上,在 SystemInfoCollector -- 这里指定类名 --> <mainClass>com.xdr630.util.SystemInfoCollector</mainClass> 但当同时用 maven-shade-plugin 生成一个 shaded (fat) jar 时,最终的 shaded JAR 的 manifest 可能不会自动来自 maven-jar-plugin 常见做法:保留或关闭取决于你是否要把生成的 POM 用作发布到仓库的 POM。
<project xmlns="http://<em>maven</em>.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance " xsi:schemaLocation="http://<em>maven</em>.apache.org/POM/4.0.0 http://<em>maven</em>.apache.org/xsd/<em>maven</em>-4.0.0 >1.8</<em>maven</em>.compiler.source> <<em>maven</em>.compiler.target>1.8</<em>maven</em>.compiler.target> </properties build,项目的编译 jdk 总是会变成 1.5 版本,一开始通过<em>maven</em>-compiler-plugin配置<em>指定</em>都不生效,后来在 <properties> 中<em>指定</em>了<<em>maven</em>.compiler.source >1.8</<em>maven</em>.compiler.source> 和 <<em>maven</em>.compiler.target>1.8</<em>maven</em>.compiler.target> 才解决,还未探得终极原因。。。
类加载器子系统作用 类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识。 加载的类信息存放于一块称为方法区的内存空间。 除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射) 类加载器ClasLoader角色 class file存在于本地硬盘上 Class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全。 由于Java采用的是懒加载策略,只有当我们需要用到这个类的时候才会去加载他 初始化阶段就是执行类构造器方法<clinit>()的过程。
, Extention ClassLoader 加载额外的 /lib/ext 类库 , Application ClassLoader 加载开发者自己开发的类库 ; 加载完 开发者 开发的类库 后 , ClassLoader 应用类加载器 Application ClassLoader 自定义类加载器 Custom ClassLoader 在双亲委托机制中 , 上层的类加载器 是 下层类加载器 的父类 类加载任务 之后 , 也会 委托 父类的父类 类加载器 执行 ; 委托操作 , 会一直传递到 最顶层的 启动类加载器 Bootstrap ClassLoader ; 如果 启动类加载器 Bootstrap ; 同理 , 父类 委托 给子类的 类加载任务 , 如果 子类类加载器 可以完成加载 , 成功返回 , 如果子类类加载器无法完成加载 , 就再次 将 类加载任务 委托给 子类的子类 , 继续向下传递 ; 无法 被替代 , 系统类只能由 启动类加载器 Bootstrap ClassLoader 加载 , 应用类加载器 加载被篡改的 Java 核心类是无效的 ;
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId >maven-compiler-plugin</artifactId> <version>3.3</version> <configuration> <source 1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build> maven-compiler-plugin
- (UIImage *)imageNamed:(NSString *)name ofBundle:(NSString *)bundleName {
/bin/bash# 定义要安装的 Maven 版本MAVEN_VERSION="3.6.3"# 定义安装目录INSTALL_DIR="/opt"cd ${INSTALL_DIR}# 下载并解压 Mavenwget "https://downloads.apache.org/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}- bin.tar.gz"tar -vf apache-maven-${MAVEN_VERSION}-bin.tar.gz# 移动 Maven 到安装目录mv apache-maven-${MAVEN_VERSION } maven# 配置环境变量echo "export PATH=${INSTALL_DIR}/maven/bin:$PATH" | tee /etc/profile.d/maven.shsource /etc/profile.d/maven.sh# 验证安装mvn --versionecho "clear temp"rm -rf apache-maven-${MAVEN_VERSION}-bin.tar.gz
-- 指定默认环境 --> <activeByDefault>true</activeByDefault> </activation> </profile 其他的区间配法示例(,1.0] x <= 1.0[1.0] x = 1.0 跟直接指定1.0没有区别[1.2,1.3] 1.2 <= x <= 1.3[ ,会提示:Reason: Range defies version ordering有了这个认知后,我们在依赖其他jar时,就可以指定形如下<dependency> <groupId SNAPSHOT,1.0.0]</version> </dependency>比如开发环境没有1.0.0版本,则会引用1.0.0-SNAPSHOT,而正式环境有1.0.0则会引1.0.0总结maven version区间确实能减少我们一些配置的工作量,但是凡事都有两面性,如果版本之间存在不兼容情况下,最好还是具体指定版本
概念 类加载 加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象 链接:将Java类的二进制代码合并到 JVM的运行状态之中的过程 验证:确保加载的类信息符合JVM规范,没有安全方面的问题 准备:正式为类变量(static)分配内存并设置类变量默认初始化值的阶段,这些内存都将在方法区中进行分配 解析:虚拟机常量池的符号引用 (类构造器是构造类的信息的,不是构造该类对象的构造器) 当初始化一个类的时候,如果发现其父类还没有初始化,则需要先触发其父类的初始化 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步 什么时候会发生类的初始化 比如:当通过子类引用父类的静态变量,不会导致子类初始化 通过数组定义类引用,不会触发此类的初始化 引用常量不会触动此类的初始化(常量在链接阶段就存入调用类的常量池中了) 类加载的作用 将class文件字节码内容加载到内存中 类缓存 标准的JavaSE类加载起器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。
文章目录 前言 自定义类加载器加载.class文件 自定义类加载器加载jar包文件 前言 在web开发中,一般我们是不需要去自己实现类加载器的,常见的web容器已经帮我们实现了指定路径下的加载,比如我们熟悉的 tomcat容器,关于tomcat类加载机制可以阅读博主的这篇文章: Java类加载机制和Tmcat模型 有些时候我们需要实现自定义的类加载器来重定向我们的.class文件的加载路径或者jar包里的打包的内容 2.我们可以实现一个自定义的类加载器,用它来加载我们所需要加载的内容,然后通过反射生成一个调用对象。 本文主要介绍第二种方式。 自定义类加载器加载.class文件 想要实现一个自定义的类加载器,首先要继承JDK中的ClassLoader类,如果我们要打破双亲委派模型,就去重写他的loadClass方法;如果我们想遵循双亲委派模型 补充测试的细节: 测试时候要注意先编译,然后把得到的User.class复制到你的指定目录下,然后要记得删除编译过后的User.class,因为双亲委派模型会先去查缓存,如果你不删除缓存JDK还是会用父类加载器去加载
> <project xmlns="http://<em>maven</em>.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance " xsi:schemaLocation="http://<em>maven</em>.apache.org/POM/4.0.0 http://<em>maven</em>.apache.org/xsd/<em>maven</em>-4.0.0 -- 要下载<em>的</em>项目 --> <dependency> <groupId>org.sample</groupId> <artifactId> -- 复制<em>的</em>包去掉版本信息 --> <stripVersion>true</stripVersion> <! -- 复制到当前路径下<em>的</em>target文件夹里 --> <outputDirectory>.
它们的源码都位于sun.misc.Launcher中,是一个静态内部类。继承自URLClassLoader,具备通过目录或者指定jar包将字节码文件加载到内存中的能力。 URLClassLoader:提供了根据URL获取目录下或者指定jar包进行加载,获取字节码的数据的能力。扩展类加载器和应用类加载器继承自URLClassLoader,获得了上述的三种能力。 路径中要包含原来ext文件夹,同时在最后加上扩展的路径。应用程序类加载器应用程序类加载器会加载classpath下的类文件,默认加载的是项目中的类以及通过maven引入的第三方jar包中的类。 ClassLoader classLoader = Student.class.getClassLoader(); System.out.println(classLoader); //maven (); //利用加载器去加载一个指定的文件 //参数:文件的路径(放在src的根目录下,默认去那里加载) //返回值:字节流。
背景 方式一 方式二 背景 有的时候,我们经常会碰到java.lang.NoSuchMethodError的错误信息。 究其根源,是由于JVM的 全盘负责委托机制导致的。 关于 全盘负责委托机制 ,请查看另一篇博文 全盘负责委托机制 特别是对于一些web项目,jar包很多,如何精确的查找呢? result; } %> <html> <head> <title>srcAdd.jartitle> head> <body bgcolor="#ffffff"> 使用方法,className参数为类的全名 classLocation = ""+getClassLocation(Class.forName(className)); if (error == null) { out.print("类" ("类" + className + "没有对应的物理文件。")
这就是虚拟机的类加载。 类加载概念 ? 上图是类加载和卸载的整个过程示意图,其中验证、准备、解析统称为连接阶段。 类加载-加载阶段 加载是类加载的第一个阶段,加载阶段的主要目标是: 通过一个类的全限定名来获取定义此类的二进制字节流 将字节流的静态信息结构转换为方法区(元数据区)的运行时数据结构 在内存中生成一个代表这个类的 非数组类的加载需要通过类加载器实现,既可以使用系统的提供的引导类加载,也可以使用用户自定义的类加载器去完成,关于类加载器后续我会单独写一篇文章来介绍,并且实现我们自己的一个类加载器。 对于数组类来说,数组类是由Java虚拟机直接创建的,但是数组中的元素类型需要通过类加载器加载。数组类的可见性与数组中元素的可见性一致,如果元素不是引用类型,数组类的可见性将默认为public。 本期类加载的加载阶段就介绍到这,下期我们会讲解类加载的连接阶段,我们下期再见!!!
记得第一次遇见这个问题的时候,同学给我的回答是: 1.虚拟机会加载JDK里类的核心包 2.虚拟机会加载JDK里类的扩展包 3.虚拟机会加载JDK里类的系统包 4.虚拟机再会加载我们写好的java类。 再次之前我想补充一个名词解释,类加载器:虚拟机把 实现 类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流” 这个过程的代码称为类加载器 1. 加载 加载只是类加载过程的一个阶段而已,但往往被大家弄成了这就是类的加载过程,所以才有了博文开头时同学给我的那个回答; 希望大家不要混淆出这个很相似的名词,从而对类加载有所误读。 Loader(标准扩展类加载器) 3.Bootstrap Loader 自动加载 AppClass Loader(系统类加载器) 4.最后由 AppClass Loader 加载 我们指定(想要运行) 3.初始化一个类的时候,如果其父类还没有被初始化,那么会先去初始化其父类; 4.当 JVM 启动时,用户需要指定一个要执行的主类(包含static void main(String 【】args)的那个类
记得第一次遇见这个问题的时候,同学给我的回答是: 1.虚拟机会加载JDK里类的核心包 2.虚拟机会加载JDK里类的扩展包 3.虚拟机会加载JDK里类的系统包 4.虚拟机再会加载我们写好的java类。 再次之前我想补充一个名词解释,类加载器:虚拟机把 实现 类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流” 这个过程的代码称为类加载器 1. 加载 加载只是类加载过程的一个阶段而已,但往往被大家弄成了这就是类的加载过程,所以才有了博文开头时同学给我的那个回答; 希望大家不要混淆出这个很相似的名词,从而对类加载有所误读。 Loader(标准扩展类加载器) 3.Bootstrap Loader 自动加载 AppClass Loader(系统类加载器) 4.最后由 AppClass Loader 加载 我们指定(想要运行 3.初始化一个类的时候,如果其父类还没有被初始化,那么会先去初始化其父类; 4.当 JVM 启动时,用户需要指定一个要执行的主类(包含static void main(String 【】args)的那个类
什么叫类加载(classloader)? 类加载简单的说就是JVM通过类加载器ClassLoader,把.class文件中的信息,拼装成Class对象放入内存中。 另外需要注意的是可以通过启动jvm时指定-Xbootclasspath和路径来改变Bootstrap ClassLoader的加载目录。 比如java -Xbootclasspath/a:path被指定的文件追加到默认的bootstrap路径中。 还可以加载-D java.ext.dirs选项指定的目录。 > loadClass ( String name , boolean resolve ) throws ClassNotFoundException{ //检查指定类是否被当前类加载器加载过
类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件,然后产生与所加载类对应的Class对象。加载完成后,Class对象还不完整,所以此时的类还不可用。 3 ) 当初始化一个类的时候, 如果发现其父类还没有进行过初始化, 则需要先触发其父类的初始化。 4) 当虚拟机启动时, 用户需要指定一个要执行的主类(包合 main()方法的那个类) . 除此之外,所有引用类的方式都不会触发初始化, 称为被动引用。 类的加载 加载是类加载过程的一个阶段,这两个概念一定不要混淆。 符号引用验证可以看做是对类自身以外(常量池中的各种符号引用) 的信息进行匹配性的校验, 通常需要校验以下内容: 符号引用中通过字将串描述的全限定名是否能找到对应的类 在指定类中是否存在符合方法的字段描述符以及简单名称所描述的方法和字段 类的初始化阶段主要是对类变量进行初始化,在Java类中对类变量指定初始值有两种方式: 声明类变量时指定初始值 使用静态初始化块为类变量指定初始值 JVM初始化一个类一般包括如下几个步骤: 假如这个类还没有被加载和连接
在 springboot 项目中,除了启动类的主函数 mainclass,如果还出现其他的 main 方法,本地运行是没有任何问题,但是在打包 package 时,就会报错,说 repackage 时 ,在项目中有多个候选的主方法。 这时候,我们就需要在 maven 的 pom.xml 文件中指定打包时的 mainClass,具体是在 spring-boot-maven-plugin 中指定,配置如下: <build> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin
“音乐是天使的演讲”,这句话形容得妙极。 ——(英国作家)卡莱尔 今天springboot项目install报错出现多个主类的问题,最后看这篇博客在pom.xml中指定了主类解决了 <build> <plugins> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin