Skip to content

Very easy java agent framework for inject proxy code.

License

Notifications You must be signed in to change notification settings

joongsoo/easy-agent

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

52 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

easy-agent

This library was created to easily develop a Java agent that injects proxy code into the class bytecode.

If you write code in Java without needing to know the bytecode instrumentation, it is injected into bytecode.

If you want see more info about this framework, See Github wiki documentation

Table of content


πŸš€ Summary

From an architectural point of view, the Java agent is a good way to inject logic from outside your application.

Many applications are increasingly using cloud and virtualized environments. In that case, there are times when you need to write code that is infrastructure dependent.

For example, if you need to implement istio distributed tracing, You will write code to propagate HTTP headers inside your application.

However, if you write like this, your application will depend to istio.

If using java agent, infrastructure dependent logic can be managed at the infrastructure level. And independence and reusability increase, because it is injected at the infrastructure layer.

image

easy-agent helps you develop java agent easily.


πŸš€ Feature

Fast

easy-agent uses ASM, it is low-level library. ASM provide high performance.

Easy

You don't need to know bytecode transform. You can easily inject a proxy with simple java code.

Productivity

Productivity is improved by placing infrastructure-dependent code at the infrastructure layer.

You don't have to think about infrastructure when developing and deploying applications. Because the infrastructure-dependent logic is injected by the agent.

Extension

easy-agent provides a easy-agent-api that can be easily extended. You can easily develop reusable plugins.

You can see more info in plugin wiki page.

Documentation

We try to give you the most detailed and friendly documentation possible. If there is any room for improvement in the document, please make a suggestion.


πŸš€ Extend via plugin

You can make reusable easy-agent plugin. it is very simple. See more details


πŸš€ Quick start

Just follow 6 simple steps.

(1) Add maven dependency to pom.xml

<dependency>
    <groupId>software.fitz</groupId>
    <artifactId>easy-agent-core</artifactId>
    <version>0.4.0-RELEASE</version>
</dependency>

(2) Implements AroundInterceptor

Override only necessary methods.

public class YourInterceptor implements AroundInterceptor {

    @Override
    public Object[] before(Object target, Method targetMethod, Object[] args) {
        // your proxy code
        if (args[0] instanceof String) {
            args[0] = args[0] + " hi"; // possible replace to target method arguments
        }
        return args;
    }

    @Override
    public Object after(Object target, Method targetMethod, Object returnedValue, Object[] args) {
        // your proxy code
        return returnedValue; // possible replace to return value
    }

    @Override
    public void thrown(Object target, Method targetMethod, Throwable t, Object[] args) {
        // your proxy code
    }
}

(3) Define your plugin & Register interceptor to your target class

public class YourPlugin implements Plugin {

    @Override
    public void setup(TransformerRegistry transformerRegistry) {

        transformerRegistry.register(
                TransformDefinition.builder()
                        // "+" means applies to all classes that extend this class
                        .transformStrategy(TransformStrategy.className("package.Class+")) 
                        .matchArgs(MethodDefinition.all("targetMethodName"))
                        .addInterceptor(YourInterceptor.class)
                        .build()
        );
    }
}

(4) Define premain class & Register your plugin

public class PremainClass {

    public static void premain(String agentArgs, Instrumentation instrumentation) {

        EasyAgentBootstrap.initialize(agentArgs, instrumentation)
                .addPlugin(new YourPlugin())
                .start();
    }
}

(5) Add maven plugin to your pom.xml

  1. Replace {your-jar-name} with the name of the jar you want.
  2. Replace {package.to.premain-class} with a class that implements the premain method.
<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>2.2</version>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
            <configuration>
                <finalName>{your-jar-name}</finalName>
                <appendAssemblyId>false</appendAssemblyId>
                <archive>
                    <manifest>
                        <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                        <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                    </manifest>
                    <manifestEntries>
                        <Premain-Class>{package.to.premain-class}</Premain-Class>
                        <Can-Retransform-Classes>true</Can-Retransform-Classes>
                        <Can-Redefine-Classes>true</Can-Redefine-Classes>
                        <Boot-Class-Path>{your-jar-name}.jar</Boot-Class-Path>
                    </manifestEntries>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </execution>
    </executions>
</plugin>

(6) Run with your application

Specify your agent jar in the -javaagent argument.

java -javaagent:/path/{your-agent}.jar -jar target-application.jar

πŸš€ Example

Example of replacing method arguments.

You can see more examples in wiki page.

AroundInterceptor

public class YourInterceptor implements AroundInterceptor {

    @Override
    public Object[] before(Object target, Method targetMethod, Object[] args) {
        if (args[0] != null && args[0] instanceof String) {
            args[0] = args[0] + " Hi!";
        }
        return args;
    }
}

Plugin

The process of registering the module was omitted.

public class YourPlugin implements Plugin {

    @Override
    public void setup(TransformerRegistry transformerRegistry) {

        transformerRegistry.register(
                TransformDefinition.builder()
                        .transformStrategy(TransformStrategy.className("package.TargetClass")) 
                        .addTargetMethod(matchArgs("printName", String.class))
                        .addInterceptor(YourInterceptor.class)
                        .build()
        );
    }
}

Target class & Main class

public class TargetClass {
    
    public void printName(String name) {
        System.out.println(name); 
    }

    public static void main(String[] args) {
        new TargetClass().printName("joongsoo");
    }
}

Execute result

joongsoo Hi!

About

Very easy java agent framework for inject proxy code.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages