Skip to content

动态注入案例:实时修复一个空指针异常

许杰 edited this page Aug 24, 2020 · 3 revisions

动态注入案例:实时修复一个空指针异常

创建一个helloworld 空指针异常程序,该程序定时抛出NullPointerException,让我们来实时修复它

hellowrld代码:

package io.manbang.helloworld;

/**
 * @author xujie
 */

public class HelloWorld {
    public static void main(String[] args) throws InterruptedException {
        new HelloWorld().loop(null);

    }


    void loop(UserModel userModel) throws InterruptedException {
        while (true) {
            runPrint(userModel);
        }
    }

    void runPrint(UserModel userModel) throws InterruptedException {
        try {
            System.out.println(userModel.getName());
        } catch (Throwable cause) {
            cause.printStackTrace();
        }
        Thread.sleep(1000);
    }

    public static class UserModel {
        String name;
        int age;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }

}

运行代码结果:

java.lang.NullPointerException
	at io.manbang.helloworld.HelloWorld.runPrint(HelloWorld.java:22)
	at io.manbang.helloworld.HelloWorld.loop(HelloWorld.java:16)
	at io.manbang.helloworld.HelloWorld.main(HelloWorld.java:9)
java.lang.NullPointerException
	at io.manbang.helloworld.HelloWorld.runPrint(HelloWorld.java:22)
	at io.manbang.helloworld.HelloWorld.loop(HelloWorld.java:16)
	at io.manbang.helloworld.HelloWorld.main(HelloWorld.java:9)
java.lang.NullPointerException
	at io.manbang.helloworld.HelloWorld.runPrint(HelloWorld.java:22)
	at io.manbang.helloworld.HelloWorld.loop(HelloWorld.java:16)
	at io.manbang.helloworld.HelloWorld.main(HelloWorld.java:9)

在框架中找到client/plugins文件夹,创建自定义插件 simple-hotfix 如:(simplehotfix示例

将工程引入框架pom依赖

        <dependency>
            <groupId>io.manbang</groupId>
            <artifactId>helloworld</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>provided</scope>
        </dependency>

Easy-byte-coder 提供注解帮您快速编写字节码注入代码

simplePlugin代码:

package io.manbang.easybytecoder.plugin.simplehotfix;

import com.google.auto.service.AutoService;


import io.manbang.easybytecoder.traffichandler.AttachTrafficHandler;
import io.manbang.easybytecoder.traffichandler.annotation.ModifyClassName;
import io.manbang.easybytecoder.traffichandler.annotation.ModifyMethod;
import io.manbang.easybytecoder.traffichandler.annotation.ResourceToImport;
import io.manbang.easybytecoder.traffichandler.annotation.constant.CodePatternEnum;


/**
 * @author xujie
 */

@AutoService(AttachTrafficHandler.class)
@ResourceToImport({
        "io.manbang.easybytecoder.runtimecommonapi.utils.EasyByteCoderResourceObjectPool",
        "io.manbang.easybytecoder.plugin.simplehotfix.mock.runtime.FixHandle"
})
@ModifyClassName("io/manbang/helloworld/HelloWorld")
public class SimplePlugin implements AttachTrafficHandler {
    
    @ModifyMethod(methodName = "runPrint", pattern = CodePatternEnum.Before)
    public String modifyBefore() {
        return "$1=FixHandle.fixModel($1);";
    }

}

FixHandle代码:

package io.manbang.easybytecoder.plugin.simplehotfix.mock.runtime;


import io.manbang.helloworld.HelloWorld.UserModel;

/**
 * @author xujie
 */
public class FixHandle {
    public static UserModel fixModel(UserModel userModel) {
        if (userModel == null) {
            UserModel newUserModel = new UserModel();
            newUserModel.setName("zhangsan");
            newUserModel.setAge(18);
            return newUserModel;
        }
        return userModel;
    }

    public static void test() {
        System.out.println("111");
    }
}

在框架顶级目录执行部署:

mvn clean install
sh copyfile.sh

切换至copyfile.sh文件中自定义的目录

执行:

java -Xbootclasspath/a:$JAVA_HOME/lib/tools.jar -jar bootstrap.jar

选择对应的jvm进程:

选择后命令行输出:

Attaching to target JVM with PID: 20971
Attached to target JVM and loaded Java agent successfully

被注入的java.lang.NullPointerException项目会在控制台打印:

easyByteCoder::[INFO ] 2020-08-24 10:55:26,599 method:io.manbang.easybytecoder.clientbootstrap.PluginClassLoaderFactory.createPluginClassLoader(PluginClassLoaderFactory.java:45)Adding 'file:/Users/xujie/work/ymm/doom-jar/simplecount.jar' to classloader
easyByteCoder::[INFO ] 2020-08-24 10:55:26,600 method:io.manbang.easybytecoder.clientbootstrap.PluginClassLoaderFactory.createPluginClassLoader(PluginClassLoaderFactory.java:45)Adding 'file:/Users/xujie/work/ymm/doom-jar/systemtime.jar' to classloader
easyByteCoder::[INFO ] 2020-08-24 10:55:26,600 method:io.manbang.easybytecoder.clientbootstrap.PluginClassLoaderFactory.createPluginClassLoader(PluginClassLoaderFactory.java:45)Adding 'file:/Users/xujie/work/ymm/doom-jar/bootstrap.jar' to classloader
easyByteCoder::[INFO ] 2020-08-24 10:55:26,600 method:io.manbang.easybytecoder.clientbootstrap.PluginClassLoaderFactory.createPluginClassLoader(PluginClassLoaderFactory.java:45)Adding 'file:/Users/xujie/work/ymm/doom-jar/doom-agent.jar' to classloader
easyByteCoder::[INFO ] 2020-08-24 10:55:26,600 method:io.manbang.easybytecoder.clientbootstrap.PluginClassLoaderFactory.createPluginClassLoader(PluginClassLoaderFactory.java:45)Adding 'file:/Users/xujie/work/ymm/doom-jar/acceleratepigeon.jar' to classloader
easyByteCoder::[INFO ] 2020-08-24 10:55:26,600 method:io.manbang.easybytecoder.clientbootstrap.PluginClassLoaderFactory.createPluginClassLoader(PluginClassLoaderFactory.java:45)Adding 'file:/Users/xujie/work/ymm/doom-jar/simpleattach.jar' to classloader
easyByteCoder::[INFO ] 2020-08-24 10:55:26,601 method:io.manbang.easybytecoder.clientbootstrap.PluginClassLoaderFactory.createPluginClassLoader(PluginClassLoaderFactory.java:45)Adding 'file:/Users/xujie/work/ymm/doom-jar/simplehotfix.jar' to classloader
easyByteCoder::[INFO ] 2020-08-24 10:55:26,601 method:io.manbang.easybytecoder.clientbootstrap.PluginClassLoaderFactory.createPluginClassLoader(PluginClassLoaderFactory.java:45)Adding 'file:/Users/xujie/work/ymm/doom-jar/common.jar' to classloader
easyByteCoder::[INFO ] 2020-08-24 10:55:26,601 method:io.manbang.easybytecoder.clientbootstrap.PluginClassLoaderFactory.createPluginClassLoader(PluginClassLoaderFactory.java:45)Adding 'file:/Users/xujie/work/ymm/doom-jar/start.sh' to classloader
easyByteCoder::[INFO ] 2020-08-24 10:55:26,623 method:io.manbang.easybytecoder.clientbootstrap.EasyByteCoderClientBootStrap.agentmain(EasyByteCoderClientBootStrap.java:122)initing plugin, name: io.manbang.easybytecoder.plugin.simplehotfix.SimplePlugin, jar path: /Users/xujie/work/ymm/doom-jar/simplehotfix.jar
easyByteCoder::[INFO ] 2020-08-24 10:55:26,642 method:io.manbang.easybytecoder.clientbootstrap.EasyByteCoderClientBootStrap.agentmain(EasyByteCoderClientBootStrap.java:129)adding transformer io.manbang.easybytecoder.traffichandler.annotation.process.AnnotationProcess$3
easyByteCoder::[INFO ] 2020-08-24 10:55:26,722 method:io.manbang.easybytecoder.traffichandler.DoTransformer.execute(DoTransformer.java:71)find transform method end [io/manbang/helloworld/HelloWorld#runPrint(io.manbang.helloworld.HelloWorld$UserModel)] .
easyByteCoder::[WARN ] 2020-08-24 10:55:26,723 method:io.manbang.easybytecoder.traffichandler.DoTransformer.execute(DoTransformer.java:52)skip method because methodModifier is null method:main
easyByteCoder::[WARN ] 2020-08-24 10:55:26,723 method:io.manbang.easybytecoder.traffichandler.DoTransformer.execute(DoTransformer.java:52)skip method because methodModifier is null method:loop
zhangsan
zhangsan
zhangsan
zhangsan
zhangsan
zhangsan

此时空指针异常被修复