只需要在pom.xml文件中加入下面这个插件配置,再通过mvn clean package获取jar包即可。
打包后 通过下面的命令即可启动一个服务。
可以看到,主要有三个大目录META-INF,BOOT-INF以及org,
比较重要的是MAINIFEST.MF文件:
该文件声明了Main-Class 配置项:可以理解为jar包的启动类,这里设置为 spring-boot-loader 项目的 JarLauncher类,进行 Spring Boot 应用的启动。
还有一个Start-Class 配置项:配置的内容是我们springboot项目的主启动类。
classes文件中保存了 Java 类所编译的 .class文件以及配置文件等。
lib目录中保存了我们项目所依赖的jar包。
该文件中即springboot为我们提供的jar包启动类,亦即JarLauncher.class
当使用 java -jar filename.jar 命令启动时,会执行封装在 JAR 文件中的程序。JAR 文件需包含 manifest,其中一行格式为 Main-Class:classname,指定了一个包含 public static void main(String[] args) 方法的类,作为该程序的启动点。
对应在示例的这个项目,问题可以翻译为为什么不可以直接使用com.jsvc.jarlearn.JarlearnApplication类作为启动类?
主要是因为,Java 没有提供任何加载嵌套 jar 文件的标准方法(即加载本身包含在 jar 中的 jar 文件)。当需要分发一个可以从命令行运行而不需要解压缩的自包含应用程序时 , 会出现问题。
同时,我试了下,直接运行application类的话,是找不到主类的:
因为在文件目录中,JarlearnApplication实际上是在META-INF/maven/... 中的,所以会找不到。
所以,springboot以 org.springframework.boot.loader.JarLauncher 为启动类,
又自定义了 LaunchedURLClassLoader 用来加载BOOT-INF中的class文件以及BOOT-INF/lib中的嵌套jar包。
我这边通过引入 spring-boot-loader 模块来看下JarLaunch的源码:
可以看到main方法中,执行了launch方法,改方法由JarLaunch的父类Launcher提供:
launch方法主要分为三步:
基本思路就是将 org.springframework.boot.loader 包路径添加到 java.protocol.handler.pkgs 环境变量中,从而使用自定义的 URLStreamHandler 实现类 Handler处理 jar: 协议的 URL。
关于handler 可以自行百度下。
这里有两个主要方法:
也就是 getClassPathArchivesIterator 以及 createClassLoader
首先是 getClassPathArchivesIterator :
首先是isSearchCandidate,在JarLaunch中实现:
可以看出是只处理BOOT-INF/文件夹下的内容。
然后会通过 getNestedArchives 获取到嵌套的Archive,其中的 isNestedArchive 方法也由JarLaunch实现:
基本就是获取 BOOT-INF/classes/ 下的目录以及 BOOT-INF/lib/ 下的jar文件,最终通过 getNestedArchives 将其封装为对应的Archive并返回。
然后就是 createClassLoader 方法:
基本上就是通过archives获取到所有的URL,然后创建处理这些URL的ClassLoader。
主要就是通过 getMainClass 方法获取到manifest文件中配置的 Start-Class :
然后通过另一个launch方法,开始执行:
这里createMainMethodRunner创建出来的是什么呢?
最终调用的其实就是MainMethodRunner的run方法了,其实也就是通过反射调用Application的main方法了。
封装,Package,是把集成电路装配为芯片最终产品的过程,简单地说,就是把Foundry生产出来的集成电路裸片(Die)放在一块起到承载作用的基板上,把管脚引出来,然后固定包装成为一个整体。
因为芯片必须与外界隔离,以防止空气中的杂质对芯片电路的腐蚀而造成电气性能下降。另一方面,封装后的芯片也更便于安装和运输。由于封装技术的好坏还直接影响到芯片自身性能的发挥和与之连接的PCB(印制电路板)的设计和制造,因此它是至关重要的。
扩展资料
1、芯片封装材料
塑料、陶瓷、玻璃、金属等,
2、封装形式
普通双列直插式,普通单列直插式,小型双列扁平,小型四列扁平,圆形金属,体积较大的厚膜电路等。
3、封装体积
最大为厚膜电路,其次分别为双列直插式,单列直插式,金属封装、双列扁平、四列扁平为最小。
参考资料来源:百度百科-封装
封装就是把制定逻辑代码放到固定代码块里面去,然后起个名字存起来,使用某些权限控制被谁调用,public,protected等
1.系统给我们提供了许多函数,比如下面的:
如果给定索引处的值是一个完全用户数据, 函数返回其内存块的地址。 如果值是一个轻量用户数据, 那么就返回它表示的指针。 否则,返回 NULL 。
把给定索引处的值转换为一个 L ua 线程 (表示为 lu a_State*)。 这个值必须是一个线程; 否则函数返回 NULL。
2.把给定索引处的值转换为一般的 C 指针 (void*) 。 这个值可以是一个用户对象,表 ,线程或是一个函数; 否则, lu a_topointer 返回 NULL 。 不同的对象有不同的指针。 不存在把指针再转回原有类型的方法。
把给定索引处的 L ua 值转换为一个 C 字符串。 如果 len 不为 NULL , 它还把字符串长度设到 *len 中。 这个 L ua 值必须是一个字符串或是一个数字; 否则返回返回 NULL 。 如果值是一个数字, lu a_tolstring 还会 把堆栈中的那个值的实际类型转换为一个字符串。 (当遍历一张表的时候, 若把 l ua_tolstring 作用在键上, 这个转换有可能导致 lu a_next 弄错。)
lu a_tolstring 返回一个已对齐指针 指向 Lua 状态机中的字符串。 这个字符串总能保证 ( C 要求的)最后一个字符为零 ('\0') , 而且它允许在字符串内包含多个这样的零。
因为 Lu a 中可能发生垃圾收集, 所以不保证 lua_tolstring 返回的指针, 在对应的值从堆栈中移除后依然有效。
3.将一个零结尾的字符串 s 转换为一个数字, 将这个数字压栈,并返回字符串的总长度(即长度加一)。 转换的结果可能是整数也可能是浮点数, 这取决于 Lu a 的转换语法()。 这个字符串可以有前置和后置的空格以及符号。 如果字符串并非一个有效的数字,返回 0 并不把任何东西压栈。 (注意,这个结果可以当成一个布尔量使用,为真即转换成功。)
一个不透明的结构, 它指向一条线程并间接(通过该线程)引用了整个 Lu a 解释器的状态。 L ua 库是完全可重入的: 它没有任何全局变量。 状态机所有的信息都可以通过这个结构访问到。
4.如果给定索引处的值是一个完全用户数据, 函数返回其内存块的地址。 如果值是一个轻量用户数据, 那么就返回它表示的指针。 否则,返回 NULL 。
把给定索引处的值转换为一个 L ua 线程 (表示为 lu a_State*)。 这个值必须是一个线程; 否则函数返回 NULL。
5.把给定索引处的值转换为一般的 C 指针 (void*) 。 这个值可以是一个用户对象,表 ,线程或是一个函数; 否则, lu a_topointer 返回 NULL 。 不同的对象有不同的指针。 不存在把指针再转回原有类型的方法。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)