在Javaagent 中使用 javassit 修改原项目代码

demo

Java agent 启动参数

启动应用程序的时候我们在jvm的命令行参数上加上

-javaagent:${jar_ball_path}/agent.jar

${jar_ball_path} 就是agent jar包的路径,可以是绝对路径,也可以是相对路径,取决于你working directory

Java agent 的打包

需要javassit 的依赖,打包的时候直接把jar包输出到一个指定目录,和Javassit的jar平级,省的后面还需要指定classpath


        
            org.javassist
            javassist
        
    


    
        agent
        

            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    1.8
                    1.8
                
            

            
                org.apache.maven.plugins
                maven-jar-plugin
                
                    
                        package
                    
                
                
                    ${project.basedir}/lib
                    
                        
                            com.qunhe.instdeco.Agent
                            true
                        
                        
                            true
                            true
                            
                                com.qunhe.instdeco.Agent
                            
                        
                    

                
            
        
    

建议在parent目录下打包

mvn --projects agent clean package

结果
在Javaagent 中使用 javassit 修改原项目代码_第1张图片

spring boot 采用jetty的maven plugin启动

export MAVEN_OPTS=-javaagent:agent/lib/agent.jar
mvn --projects spring-boot jetty:run -Djetty.port=12345

agent的代码

在premain里面 instrument需要添加一个transformer,核心代码都在transformer里面,需要在classPool里添加classpath,否则会无法加载spring里的类,因为业务代码基本都由 WebAppClassLoader加载,ClassPool的默认ClassLoader是AppClassLoader 其实就是

Thread.currentThread().getContextClassLoader()

实现方法替换的代码,类有可能需要先defrost。

@Override
    public byte[] transform(final ClassLoader loader, final String className,
            final Class classBeingRedefined,
            final ProtectionDomain protectionDomain, final byte[] classfileBuffer)
            throws IllegalClassFormatException {

        String targetClassName = "MainController";
        if (className.endsWith(targetClassName)) {
            try {
                return mockClass(loader, String.join(".", className.split("[\\W]")),
                        classfileBuffer);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return classfileBuffer;
    }


    private byte[] mockClass(ClassLoader loader, String className, byte[] classfileBuffer)
            throws Exception {
        ClassPool classPool = ClassPool.getDefault();
        classPool.insertClassPath(new LoaderClassPath(loader));
        CtClass targetClass = classPool.getCtClass(className);
        ClassLoader classLoader = targetClass.getClass().getClassLoader();

        targetClass.defrost();
        CtMethod ctMethod = targetClass.getDeclaredMethod("person");
        String packageName = "com.qunhe.instdeco";
        ctMethod.setBody("{" +
                String.format("%s.Person person = new %s.Person();", packageName, packageName) +
                "person.setAge(Integer.valueOf(27));" +
                "person.setName(\"shengxun\");" +
                "return person;" +
                "}");
        targetClass.freeze();
        return targetClass.toBytecode();
    }

demo里面使用的时候可以用项目里的run.sh跑起来试一下

你可能感兴趣的:(在Javaagent 中使用 javassit 修改原项目代码)