葡京娱乐总站平台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