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
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.
easy-agent helps you develop java agent easily.
easy-agent
uses ASM, it is low-level library. ASM provide high performance.
You don't need to know bytecode transform. You can easily inject a proxy with simple java code.
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.
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.
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.
You can make reusable easy-agent plugin. it is very simple. See more details
Just follow 6 simple steps.
<dependency>
<groupId>software.fitz</groupId>
<artifactId>easy-agent-core</artifactId>
<version>0.4.0-RELEASE</version>
</dependency>
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
}
}
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()
);
}
}
public class PremainClass {
public static void premain(String agentArgs, Instrumentation instrumentation) {
EasyAgentBootstrap.initialize(agentArgs, instrumentation)
.addPlugin(new YourPlugin())
.start();
}
}
- Replace
{your-jar-name}
with the name of the jar you want. - Replace
{package.to.premain-class}
with a class that implements thepremain
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>
Specify your agent jar in the -javaagent
argument.
java -javaagent:/path/{your-agent}.jar -jar target-application.jar
Example of replacing method arguments.
You can see more examples in wiki page.
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;
}
}
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()
);
}
}
public class TargetClass {
public void printName(String name) {
System.out.println(name);
}
public static void main(String[] args) {
new TargetClass().printName("joongsoo");
}
}
joongsoo Hi!