Mavean多工程依赖型

  

➠又多技术干货请戳:听云博客

葡京国际平台 1

0x01
 Mach-O格式简单介绍

前言

本篇文章基于Java开发小技巧(二):自定义Maven依赖遭创造的父工程project-monitor贯彻,运用我们于定义之负包进行多工程依赖型的开支。

下面为多但实施Jar包项目之开也例,进行Maven多工程依赖型开支的执教。

Mach-O文件格式是
OS X 与 iOS 系统及的可执行文件格式,类似于windows的 PE 文件 与
Linux(其他 Unix like)的 ELF
文件,如果无根本将清楚Mach-O的格式和有关内容,那么透彻钻研 xnu
内核就无从谈起。

要求分析

率先来拘禁一下封面图,我们而促成之功效是:
1.大多单门类共享一个类别之近乎与办法齐通用内容
2.每个子项目单独导入所待依赖,以及个别填充父项目安排文件中之占有位符
3.子项目比照指定目录结构进行打包
4.所有子项目并打包到一个联之目,共享依赖包及配备文件等情节
5.于包后目录结构:

  • bin:存放脚本文件,用来安环境变量,执行相应的jar包
  • lib:依赖、项目jar包
  • etc:配置文件
  • ……

吓啊,目标显然的,接下要拓展实际支出实现了

Mach-O文件之格式如下图所示:

实现

葡京国际平台 2

包装配置

于齐同一首文章被已创办好了一个自定义的Maven依赖,相当给一个父项目,接下去我们新建一个子项目,命名为project-onepom.xml文件以及大项目基本相同,所有乘包都必独立引入,不同的是差不多矣针对性大人项目之借助:

<dependency>
    <groupId>com.demo</groupId>
    <artifactId>project-monitor</artifactId>
    <version>0.0.1</version>
</dependency>

以及Maven插件maven-assembly-plugin的引入,用来兑现依靠的由包和包装后的目结构:

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <appendAssemblyId>false</appendAssemblyId>
        <descriptors>
            <descriptor>package.xml</descriptor>
        </descriptors>
    </configuration>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>

目结构布局在项目根本目录下package.xml配置文件中:

<assembly xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/assembly-1.0.0.xsd">
    <id>package</id>
    <formats>
        <format>zip</format>
    </formats>
    <includeBaseDirectory>true</includeBaseDirectory>

    <fileSets>
        <fileSet>
            <directory>src/main/resources</directory>
            <includes>
                <include>*.properties</include>
                <include>*.xml</include>
            </includes>
            <outputDirectory>etc</outputDirectory>
        </fileSet>
    </fileSets>
    <dependencySets>
        <dependencySet>
            <outputDirectory>lib</outputDirectory>
            <scope>runtime</scope>
        </dependencySet>
    </dependencySets>
</assembly>

以上就是兑现了路打包的布工作,实现流程图中最后的品种结构,打包结果也zip文件

起如下几单有组成:

填充配置文件占位符

前面我们在大项目之spring上下文中定义了一个数量源bean,配置信息运用了占位符填充,所以如果我们怀念如果使用这bean,就待替换其中的占位符信息,要怎么开吧?
先是当然是创建布局文件了,在路遭到创造jdbc.propertiesJDBC配置文件,如:

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localdb:3306/test?characterEncoding=utf8&useSSL=true&serverTimezone=UTC
jdbc.username=root
jdbc.password=5EF28C5A9A0CE86C2D231A526ED5B388

下一场我们用借助PropertyPlaceholderConfigurer这看似来兑现,在品种spring上下文中定义bean:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <value>classpath:jdbc.properties</value>
    </property>
    <property name="ignoreResourceNotFound" value="false"/>
</bean>

Bingo,占位符修改完,别忘了引入父项目之上下文,毕竟我们如果填充占位符的bean是于大项目被之:

<import resource="classpath*:project-monitor.xml"/>

1.
Header:保存了Mach-O的局部中心信息,包括了阳台、文件类型、LoadCommands的个数等等。

测试Demo

哼了,接下来测试项目的来头,主要实现用大项目概念之数源来对MySql进行询问。
事先创造一个DemoService好像,内容如下:

package com.demo.project.one.service;

import org.apache.log4j.Logger;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class DemoService {
    private static final Logger logger = Logger.getLogger(DemoService.class);
    private DataSource dataSource;

    public void queryDb(){
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;

        try {
            conn = dataSource.getConnection();
            stmt = conn.createStatement();
            rs = stmt.executeQuery("select * from movie limit 1");
            while(rs.next()){
                logger.info(String.format("Movie[Id=%d,Title=%s,Director=%s,Genre=%s,Language=%s]",
                        rs.getInt(1),
                        rs.getString(2),
                        rs.getString(3),
                        rs.getString(4),
                        rs.getString(5)
                        ));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if(rs != null){
                    rs.close();
                }
                if(stmt != null){
                    stmt.close();
                }
                if(conn != null){
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
}

于内外文中为其流dataSource定义:

<bean id="demoService" class="com.demo.project.one.service.DemoService">
    <property name="dataSource" ref="dataSource"/>
</bean>

变动忘了丰富log4j.properties部署文件,这里虽无贴发出文件内容了。
OK,新建一个入口类来推行DemoService的测试吧:

package com.demo.project.one;

import com.demo.project.one.service.DemoService;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Application {
    public static void main(String[] args){
        ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("/project-one.xml");
        DemoService demoService = (DemoService)context.getBean("demoService");
        demoService.queryDb();
    }
}

末的门类结构要图
葡京国际平台 3

2.
LoadCommands:这同一截紧跟Header,加载Mach-O文件时见面利用此的多寡来规定内存的布。

打包

全部准备妥当,轮到品种自包了,在项目根本目录执行以下Maven命令即可

mvn clean package

履到位后若见面发现target目录的结构如图所示
葡京国际平台 4
project-one.zip就是我们如果之自包结果,解压后若会意识,依赖包和布置文件已在了个别的目录下
葡京国际平台 5

3.
Data:每一个segment的现实性数额都封存于此地,这里包含了切实可行的代码、数据等等。

实行文书

色开支到位,接下便执行顺序了,以Windows平台下呢例,首先创建bin目,目录中创造批处理文件setenv.batproject-one.bat
为jar包与配置文件之分开,所以我们需要指定执行jar包时的classpath,批处理文件内容如下:

0x02
FAT二前进制数据 ,数据结构定义在 \<mach-o/fat.h\>

setenv.bat

@echo off
set SRC_DIR=%cd%

cd %~dp0
cd ..
set MAIN_HOME=%cd%

cd %SRC_DIR%

set BIN_HOME=%MAIN_HOME%\bin
set ETC_HOME=%MAIN_HOME%\etc
set LIB_HOME=%MAIN_HOME%\lib
set CLASSPATH=%ETC_HOME%;%JAVA_HOME%\lib\tools.jar

for %%i in (%LIB_HOME%\*.jar) do set CLASSPATH=!CLASSPATH!;%%i

葡京国际平台 6

project-one.bat

@echo off
@setlocal enableextensions enabledelayedexpansion
call setenv.bat

chcp 65001
java -cp %CLASSPATH% com.demo.project.one.Application
pause

bat文件的情即无详细说明,有趣味可以百度了解一下,主要是为拼接出完全的CLASSPATH,执行project-one-0.0.1.jar可执行jar包

葡京国际平台 7

运行

点击project-one.bat运行程序
葡京国际平台 8

1.
首先截为magic 魔数,这里注意大小端,读出来之后需要看下是0xCAFEBABE还是
0xBEBAFECA(否则即为thin),需要基于这个来转后续读取的字节的许节序。
 可以扣押出来 前4byte 为 0xBEBAFECA ,说明为fat。

结语

种类终于开发示范了,这里只是创建一个造而尽jar包的子项目作为例子,你还可以创建多单子项目,最后打包的上合并相同之负和部署文件,然后在bin惨遭创造相应品种的实行文书即可,各个子项目之间吧可是进行互倚仗。
上述开发技巧不仅适用于可实行jar包的开支,同样适用于WEB项目之开销,具体或出于项目要求决定。

章项目源码已披露暨Github:https://github.com/ZKHDEV/MultDependPjo

本文为作者kMacro原创,转载请注明来源:http://www.jianshu.com/p/3fa98dd52520。

2.
亚截为arch
count,也就是是该App或dSYM中含有哪些CPU架构,比如armv7、arm64对等,这个事例中为2(后4byte
 0x 00 00 00 02),表示包含了少种植cpu架构。  

  `sizeof(struct fat-header) = 8byte`

3.
继续截遭遇包含cputype(0x  0C 00  00 01)、cpusubtype (0x 00 00 00
00)、offset (0x 00 10 00  00)、size(0x 00  F0 27
00)等数码,根据fat中的结构定义,依次读取,这里需要证明的凡,如果单纯含一种CPU架构的话,是尚未及时段fat头定义的,可以超越了及时部分,直接读取Arch数据。

   `sizeof(struct fat-arch) = 20byte`

4.
冲fat头中读取的offset数据,我们得超越到文件对应之arch数据的职务,当然如果仅仅发同样种架构的说话就未需要计算偏移量了。
下图为有分析的函数

葡京国际平台 9

0x03
Mach Header二进制数据

通过magic我们得以分别出是32-bit还是64-bit,64-bit多了4独字节的保留字段,这里同样用专注字节序的题目,也就是判定magic,来确定是否用转移字节序。
 

`sizeof(struct mach-header-64) = 32byte`  ; `sizeof(struct mach-header) = 28byte`

葡京国际平台 10

根据mach-header与mach-header_64之概念,很显然好看看,Headers的要害意图就是协助系统迅速的定位Mach-O文件的运作环境,文件类型。

葡京国际平台 11

FileType 

盖Mach-O文件不但用来贯彻可执行文件,同时还用来落实了别样情节

1.
基本扩展

2.
库文件

3.
CoreDump

4.
 其它

葡京国际平台 12

脚是一些上佳用到之文件类型

1.
MH-OBJECT    编译过程遭到出的  obj文件 (gcc -c xxx.c
生成xxx.o文件)

2.
MH-EXECUTABLE  可实行二进制文件 (/usr/bin/ls)

3.
MH-CORE      CoreDump (崩溃时的Dump文件)

4.
MH-DYLIB  动态库(/usr/lib/里面的那些共享库文件)

5.
MH-DYLINKER  连接器linker(/usr/lib/dyld文件)

6.
MH-KEXT-BUNDLE   内核扩展文件 (自己开之略内核模块)

flags

Mach-O
headers还蕴含了一部分坏重要之dyld的加载参数。

葡京国际平台 13

1.
MH-NOUNDEFS   目标并未不定义之标记,不存链接依赖

2.
MH-DYLDLINK     该目标文件是dyld的输入文件,无法为再次的静态链接

3.
MH-PIE      允许擅自的地方空间(开启ASLR  -\>Address Space Layout
Randomization)

4.
MH-ALLOW-STACK-EXECUTION   栈内存可执行代码,一般是默认关闭的。

5.
MH-NO-HEAP-EXECUTION   堆内存无法履行代码

葡京国际平台 14

0x04
LoadCommands

Load
Commands 直接就是与当Header后面,所有command占用内存的总数在Mach-O
Header里面已经于起了。在加载了Header之后尽管经过解析LoadCommand来加载接下的数了。定义如下:

葡京国际平台 15

cmd字段

依据cmd字段的类不同,使用了不同之函数来加载。简单的排有同样摆设表看一样扣押以基础代码中不同之command类型都生怎样作用。

1.
LC-SEGMENT;LC-SEGMENT-64   在本中出于load-segment
函数处理(将segment中之数码加载并映射到过程的内存空间去)

2.
LC-LOAD-DYLINKER    在本中由load-dylinker
函数处理(调用/usr/lib/dyld程序)

3.
LC-UUID 于基本中由于load-uuid 函数处理 (加载128-bit之唯一ID)

4.
LC-THREAD  以基础中出于load-thread 函数处理
(开启一个MACH线程,但是非分配栈空间)

5.
LC-UNIXTHREAD 当本中出于load-unixthread 函数处理 (开启一个UNIX
posix线程)

6.
LC-CODE-SIGNATURE 于根本中由load-code-signature 函数处理
(进行数字签名)

7.
LC-ENCRYPTION-INFO 在本中由于 set-code-unprotect 函数处理
(加密二进制文件)

UUID
二进制数据    128byte

UUID是16单字节(128bit)的平截数据,是文本之绝无仅有标识,前面提到的符号化时,这个UUID必须使跟App二进制文件中之UUID一致,才能够被正确的符号化。dwarfdump查看的UUID就是即刻段数据。读博就部分数目常常经过Command结构读取的,也不怕是第一截(0x0000001B)表示接下的数据类型,第二段(0x00000018)数据的深浅(包含Command数据)。 

SymTab
二前进制数据

1.
标记表数据块结构,前亚段落仍是Command数据。后边4段子分别吗标志在文件被的偏移量(0x001DF5E0)、符号个数(0x001DF5E0)、字符串在文件被的偏移量(0x0020C3A0)、字符串表大小(0x000729A8)。 

2.
搭下去便是朗诵取Segment和Section数据块了,和上面读取数据块结构同样是基于Command结构读取,下图展示的Segment数据及Section数据,它们当二进制文件中它是连的,也不怕是各一样漫漫Segment数据背后会跟多修对应的Section数据,Section的数据总数是由此Segment结构面临的nsects决定的。 

3.
这里自己形容了一个略地Mach-O解析工具 [https://github.com/liutianshx2012/Tmacho\](https://github.com/liutianshx2012/Tmacho)

葡京国际平台 16

Segment数据

加载数据时,主要加载的便是LC-SEGMET活在LC-SEGMENT_64。其他的Segment的用在此地不举行探索。

LCSEGMENT以及LC-SEGMENT-64
定义如下图。

 

葡京国际平台 17

葡京国际平台 18

可观看,这里大部分的数目是用来扶持内核将Segment映射到虚拟内存的。

nsects
字段,标示了Segment中发生小secetion
,section是实际产生因此之多寡存放的地方。

TEXT的vmaddr也尽管是次的加载地址;
—DWARF中标明了DWARF数据块的消息,表示dSYM是DWARF格式的数据结构。 

` sizeof(struct segment-command) = 56byte   ;   sizeof(struct segment-command-64) = 72byte`

Section数据

葡京国际平台 19

从今Section数据被,我们得以找到—debug-info、—debug-pubnames,
—debug-line等调试信息,通过这些调试信息我们好找到程序中符号的序曲地址、变量类型等消息。如果我们而符号化的话,就足以经过分析这些数量获得我们怀念如果的音信。

Symbol
数据

由此SymTab中之数据可博得Symbol在文书被的位置和个数,Symbol块数据遭到隐含了标记的起始地址、字符串的偏移量等数,这有些数据结构可以参照\<nlist.h\>

\<stabl.h\>。在当下有数目总体读取后,就得读取所有的记数据了,也即是接下去的数量。 

Symbol
String 数据

1.
通过SymTab和Symbo中的数目好取得每个符号字符串在文书中之偏移量和尺寸,每个符号数据是以0最后的字符串。 

2.
咱由此上述两组成部分数据的咬合就得收获每个symbo在程序中之加载地址了。这些多少对于后做标记工作且大之发出协助。

3.
到是,关于dSYM文件中头部数据读取就完成了。头部数都发对应的数据结构定义,读取时相对会较好些,解析数据常常如留意字节序的问题,32-bit和64-bit数据结构的异样、字节长度的异样,DWARF版本的歧异,每个数据块之间还是紧密联系的,一个字节的读取偏差就会促成后续数据的读取错误,正所谓差之毫厘,失之千里。

 

原文链接:http://blog.tingyun.com/web/article/detail/1341