golang 实现程序运行时函数动态替换,举例说明动态注入和替换本地方法、系统库方法、第三方库方法,附完整源码实现。

1、先创建一个go文件,把包名设置为main,并写一个main方法;

golang 实现程序运行时函数动态替换,举例说明动态注入和替换本地方法、系统库方法、第三方库方法,附完整源码实现_hook

2、测试本地方法动态替换

func originFunc() {
str := "this is origin func"
fmt.Println(str)
}

func replaceFunc() {
str := "this is replace func"
fmt.Println(str)
}
func testLocalMethod() {
originFunc()
hook.Hook(originFunc, replaceFunc, nil)
originFunc()
fmt.Println("====================")
}

测试结果:

golang 实现程序运行时函数动态替换,举例说明动态注入和替换本地方法、系统库方法、第三方库方法,附完整源码实现_hook_02

3、测试系统方法动态替换,以time下的方法为例

func nowTime() time.Time {
return time.Date(2022, 1, 1, 0, 0, 0, 0, &time.Location{})
}

func Local3(t time.Time) time.Time {
return time.Date(2022, 1, 1, 0, 0, 0, 0, &time.Location{})
}

func Local4() time.Time {
return time.Date(2022, 1, 1, 0, 0, 0, 0, &time.Location{})
}
func testSystemLib() {

fmt.Println(time.Now())
hook.Hook(time.Now, nowTime, nil)
fmt.Println(time.Now())
fmt.Println("====================")

t1 := time.Time{}
fmt.Println(t1.Local())
hook.HookMethod(t1, "Local", Local3, nil)
fmt.Println(t1.Local())
hook.Hook(t1.Local, Local4, nil)
fmt.Println(t1.Local())
fmt.Println("====================")
}

测试结果:

golang 实现程序运行时函数动态替换,举例说明动态注入和替换本地方法、系统库方法、第三方库方法,附完整源码实现_golang_03

4、测试第三方库方法,动态注入和替换,以net/http包下http请求方法为例:

func do1(req *http.Request) (*http.Response, error) {
return nil, fmt.Errorf("replace request success")
}

func do2(*http.Client, *http.Request) (*http.Response, error) {
return nil, fmt.Errorf("replace request success")
}
func ThirdRequest(url, method, token string, data map[string]interface{}) (error, map[string]interface{}) {
//Method: "OPTIONS" | "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "TRACE" | "CONNECT"
client := &http.Client{
Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}},
}
jsonBytes, err := json.Marshal(data)
if err != nil {
fmt.Println("11", err)
return err, nil
}
request, err := http.NewRequest(method, url, bytes.NewReader(jsonBytes))
if err != nil {
fmt.Println("22", err)
return err, nil
}
// 设置请求头
request.Header.Add("Content-Type", "application/json;charset=utf-8")
if len(token) > 0 {
request.Header.Add("token", token)
}
// 设置5秒的超时时间
client.Timeout = 5 * time.Second

// 发起请求
resp, err := client.Do(request)
if err != nil {
return err, nil
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err, nil
}

res := map[string]interface{}{}
err = json.Unmarshal(body, &res)
if err != nil {
return err, nil
}
return nil, res
}
func testThirdLib() {
params := map[string]interface{}{
"query": "test",
}
err, result := ThirdRequest("http://www.baidu.com", "GET", "", params)
fmt.Println(err, result)
client := &http.Client{}
hook.HookMethod(client, "Do", do2, nil)
err, result = ThirdRequest("http://www.baidu.com", "GET", "", params)
fmt.Println(err, result)

}

测试结果:

golang 实现程序运行时函数动态替换,举例说明动态注入和替换本地方法、系统库方法、第三方库方法,附完整源码实现_动态替换_04


完整源码:

package main

import (
"bytes"
"crypto/tls"
"encoding/json"
"fmt"
"github.com/YouAreOnlyOne/goutils/hook"
"io/ioutil"
"net/http"
"time"
)

func originFunc() {
str := "this is origin func"
fmt.Println(str)
}

func replaceFunc() {
str := "this is replace func"
fmt.Println(str)
}

func do1(req *http.Request) (*http.Response, error) {
return nil, fmt.Errorf("replace request success")
}

func do2(*http.Client, *http.Request) (*http.Response, error) {
return nil, fmt.Errorf("replace request success")
}

func nowTime() time.Time {
return time.Date(2022, 1, 1, 0, 0, 0, 0, &time.Location{})
}

func Local3(t time.Time) time.Time {
return time.Date(2022, 1, 1, 0, 0, 0, 0, &time.Location{})
}

func Local4() time.Time {
return time.Date(2022, 1, 1, 0, 0, 0, 0, &time.Location{})
}

func testThirdLib() {
params := map[string]interface{}{
"query": "test",
}
err, result := ThirdRequest("http://www.baidu.com", "GET", "", params)
fmt.Println(err, result)
client := &http.Client{}
hook.HookMethod(client, "Do", do2, nil)
err, result = ThirdRequest("http://www.baidu.com", "GET", "", params)
fmt.Println(err, result)

}

func ThirdRequest(url, method, token string, data map[string]interface{}) (error, map[string]interface{}) {
//Method: "OPTIONS" | "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "TRACE" | "CONNECT"
client := &http.Client{
Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}},
}
jsonBytes, err := json.Marshal(data)
if err != nil {
fmt.Println("11", err)
return err, nil
}
request, err := http.NewRequest(method, url, bytes.NewReader(jsonBytes))
if err != nil {
fmt.Println("22", err)
return err, nil
}
// 设置请求头
request.Header.Add("Content-Type", "application/json;charset=utf-8")
if len(token) > 0 {
request.Header.Add("token", token)
}
// 设置5秒的超时时间
client.Timeout = 5 * time.Second

// 发起请求
resp, err := client.Do(request)
if err != nil {
return err, nil
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err, nil
}

res := map[string]interface{}{}
err = json.Unmarshal(body, &res)
if err != nil {
return err, nil
}
return nil, res
}

func testLocalMethod() {
originFunc()
hook.Hook(originFunc, replaceFunc, nil)
originFunc()
fmt.Println("====================")
}

func testSystemLib() {

fmt.Println(time.Now())
hook.Hook(time.Now, nowTime, nil)
fmt.Println(time.Now())
fmt.Println("====================")

t1 := time.Time{}
fmt.Println(t1.Local())
hook.HookMethod(t1, "Local", Local3, nil)
fmt.Println(t1.Local())
hook.Hook(t1.Local, Local4, nil)
fmt.Println(t1.Local())
fmt.Println("====================")
}

func main() {
testLocalMethod()
testSystemLib()
testThirdLib()

}

更多有用库:

​github.com/YouAreOnlyOne/goutils​