golang 实现程序运行时函数动态替换,举例说明动态注入和替换本地方法、系统库方法、第三方库方法,附完整源码实现。
1、先创建一个go文件,把包名设置为main,并写一个main方法;
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("====================")
}
测试结果:
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("====================")
}
测试结果:
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)
}
测试结果:
完整源码:
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()
}
更多有用库: