3、搜索class文件

2020-04-22  本文已影响0人  陈桐Caliburn

gojvm目录
1、搭建go环境
2、cmd命令行参数解析
3、搜索class文件
4、添加testOption 便于单元测试
5、解析classfile文件
6、运行时数据区
7、指令集
8、解释器
9、创建Class
10、类加载器
11、对象实例化new object
12、方法调用和返回
13 类初始化
14、jvm支持数组
15、jvm支持字符串-数组扩展
16、本地方法调用
17、ClassLoader原理
18、异常处理
19、 启动jvm

1、知识扩展

java jvm根据类路径(class path)来搜索类,加载到内存

按照搜索先后顺序 位置
1、启动类路径(bootstrap classpath) Jre/lib
2、扩展类路径(extension classpath) Jre/lib/ext
3、用户类路径(user classpath) 当前目录 .

可以通过 -Xbootclasspath 修改启动类路径

参数 -classpath /-cp

go语言不需要显式实现接口
defer 确保异常及时处理

2、Cmd添加jre目录

// java [-options] class [args...]
type Cmd struct {
    XjreOption  string   // 指定jre启动类的目录
}

func parseCmd() *Cmd {
    flag.StringVar(&cmd.XjreOption,"Xjre","","path to jre")
}

3、类加载规则

package classpath

import (
    "os"
    "path/filepath"
)

type Classpath struct {
    bootClasspath Entry //启动类搜索
    extClasspath  Entry //扩展类搜索
    userClasspath Entry //用户类搜索
}

//创建解析器
func Parse(jreOption, cpOption string) *Classpath {
    cp := &Classpath{}
    //解析启动类加载
    cp.parseBootAndExtClasspath(jreOption)
    //解析用户类加载
    cp.parseUserClasspath(cpOption)
    return cp
}

// 读取文件名称为className的class文件
func (self *Classpath) ReadClass(className string) ([]byte, Entry, error) {
    className = className + ".class"
    // 1. 从启动类路径寻找读取 <className>.class 类
    if data, entry, err := self.bootClasspath.readClass(className); err == nil {
        return data, entry, err
    }
    // 2. 从扩展类路径寻找读取 <className>.class 类
    if data, entry, err := self.extClasspath.readClass(className); err == nil {
        return data, entry, err
    }
    // 3. 从用户类路径寻找读取 <className>.class 类
    return self.userClasspath.readClass(className)
}

func (self *Classpath) String() string {
    return self.userClasspath.String()
}

func (self *Classpath) parseBootAndExtClasspath(jreOption string) {
    jreDir := getJreDir(jreOption)
    self.bootClasspath = newWildcardEntry(filepath.Join(jreDir, "lib", "*"))       // jre/lib/*
    self.extClasspath = newWildcardEntry(filepath.Join(jreDir, "lib", "ext", "*")) // jre/lib/ext/*
}

func getJreDir(jreOption string) string {
    // 先读取命令行参数-Xjre,如果存在,直接返回(为了简化,不做错误输入的处理)
    if jreOption != "" {
        return jreOption
    }
    // 如果命令行没有传入-Xjre,使用JAVA_HOME/jre
    if javaHome := os.Getenv("JAVA_HOME"); javaHome != "" {
        return filepath.Join(javaHome, "jre")
    }
    panic("Can't find jre folder")
}

func (self *Classpath) parseUserClasspath(cpOption string) {
    if cpOption == "" {
        cpOption = "."
    }
    self.userClasspath = newEntry(cpOption)
}

4、类路径查找

1、Entry搜索类路径
2、DirEntry 搜索目录下类路径
3、ZipEntry 搜索zip或jar文件形式类路径
4、CompositeEntry 组合类路径
5、WildcardEntry 所有通配符下类路径

Entry 类路径查找

package classpath

import "os"
import "strings"

//分隔符 ":"
const pathListSeparator = string(os.PathListSeparator)

//定义接口
type Entry interface {
    // 寻找和读取 class 文件
    // 入参:className - class文件的相对路径,eg. 如果要读取 java.lang.Object 类,则className = java/lang/Object.class
    // 返回值:
    // 1. 读取到的class文件内容的[]byte
    // 2. 最终定位到包含className文件的Entry对象
    // 3. 错误信息error
    readClass(className string) ([]byte, Entry, error)
    //获得className
    string() string
}

//根据参数类型创建不同搜索模式
func newEntry(path string) Entry {

    //读取多个className文件 java -cp path1/classes:path2/classes
    if strings.Contains(path, pathListSeparator) {
        return newCompositeEntry(path)
    }

    // 读取path下所有jar文件的className文件  java -cp path/*
    if strings.HasSuffix(path, "*") {
        return newWildcardEntry(path)
    }

    // 从path/lib1.jar下查找并读取className文件:java -cp path/lib1.jar 或者 java -cp path/lib1.zip
    //读取zip/jar下 className文件 :java -cp path/lib1.jar
    if strings.HasSuffix(path, ".jar") || strings.HasSuffix(path, ".zip") {
        return newZipEntry(path)
    }

    //遍历目录
    return newDirEntry(path)
}

测试类


//测试classpath
func parseClasspath(cmd *Cmd) {
    cp := classpath.Parse(cmd.XjreOption, cmd.cpOption)
    fmt.Printf("classpath:%v class:%v args:%v\n",
        cp, cmd.class, cmd.args)

    className := strings.Replace(cmd.class, ".", "/", -1)
    classData, _, err := cp.ReadClass(className)
    if err != nil {
        fmt.Printf("Could not find or load main class %s\n", cmd.class)
        return
    }

    fmt.Printf("class data:%v\n", classData)
}

实战项目地址

https://github.com/yinlingchaoliu/jvmgo.git
提交标签classpath

上一篇下一篇

猜你喜欢

热点阅读