Author: Xiao Fu Ge blog: bugstack.cn – summary of a series of articles

Precipitation, share, grow, let yourself and others can gain something!

One, foreword

By the end of this chapter, most of the commonly used APIS of byte-Buddy, the bytecode framework, have been covered in case studies. The following sections cover how to implement an abstract class and create annotations (including class annotations and method annotations). This section of annotations is often used in monitoring or interception scenarios, so in this section we will use an example to create classes and methods with custom annotations.

If you’ve read the previous articles in the series, this tutorial will not be too unfamiliar, focusing on the use of the MethodDelegation method and adding custom annotations.

So, let’s use delegation and annotations to create such a case.

Second, development environment

  1. The JDK 1.8.0 comes with
  2. Byte – buddy 1.10.9
  3. Byte – buddy – agent 1.10.9
  4. This chapter covers the source code at:itstack-demo-bytecode-2-03, you can pay attention toThe public,:Bugstack wormhole stack, reply source download to obtain.You'll get a list of download links, and open it up to number 17, "Because I have a lot of open source code."Make sure you give me aStar!

Objective of the case

Here we define an abstract interface class with generics, as follows;

public abstract class Repository<T> {

    public abstract T queryData(int id);

}
Copy the code

The following example will implement abstract class methods using delegates and custom annotations, just as we would do with code.

@RpcGatewayClazz( clazzDesc = "Query data information", alias = "dataApi", timeOut = 350L )
public class UserRepository extends Repository<String> {      

    @RpcGatewayMethod( methodName = "queryData", methodDesc = "Query data" )
    public String queryData(int var1) {
 // ...  }  } Copy the code
  • Here is the end result, we simulate a gateway interface implementation and definition annotation expose the interface information (if you are doing development in the Internet, there are many such requirements, interface unified gateway service).

Fourth, technical implementation

In the process of technical implementation, we will gradually realize the functions we need, break down the knowledge points and explain them to achieve the final goal of the case.

1. Create custom annotations

Mock gateway class annotations

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface RpcGatewayClazz {

    String clazzDesc(a) default "";
 String alias(a) default "";  long timeOut(a) default 350;  } Copy the code

Mock gateway method annotations

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RpcGatewayMethod {

    String methodName(a) default "";
 String methodDesc(a) default "";  } Copy the code
  • This section allows you to create any type of annotation, mainly to simulate the effect of adding annotations to classes and methods and getting the final property value.

2. Create a delegate function

public class UserRepositoryInterceptor {

    public static String intercept(@Origin Method method, @AllArguments Object[] arguments) {
        return "Little Fuge blog, query article data: https://bugstack.cn/?id=" + arguments[0];
    }
 } Copy the code
  • Eventually our bytecode operations will implement the function of the abstract class by means of delegates.
  • The use of annotations in delegate functions was fully covered in the previous section and can be reviewed for reference.
  • @OriginYou can bind to the following types of parameters: Method The original Method called Constructor the original Constructor called Class The currently dynamically created Class MethodHandle MethodType String The return value of the dynamic Class toString() int The dynamic Method modifier.
  • @AllArgumentsBind an array of all parameters.

3. Create method body information

// Generate a generic implementation word class with annotations
DynamicType.Unloaded<? > dynamicType =new ByteBuddy()
        .subclass(TypeDescription.Generic.Builder.parameterizedType(Repository.class, String.class).build()) // Create generic annotations for complex types
        .name(Repository.class.getPackage().getName().concat(".").concat("UserRepository"))                  // Add class information including address
        .method(ElementMatchers.named("queryData"))                                                          // The method of matching processing
 .intercept(MethodDelegation.to(UserRepositoryInterceptor.class)) // To the delegate function  .annotateMethod(AnnotationDescription.Builder.ofType(RpcGatewayMethod.class).define("methodName"."queryData").define("methodDesc"."Query data").build())  .annotateType(AnnotationDescription.Builder.ofType(RpcGatewayClazz.class).define("alias"."dataApi").define("clazzDesc"."Query data information").define("timeOut".350L).build())  .make(); Copy the code
  • This part is basicallyByte-buddyTemplate method through the core API;subclass,name,method,intercept,annotateMethod,annotateTypeUse the build method.
  • The first is a custom annotation that defines the complex type as the parent class of this method, which is the abstract class.Repository<T>Through theTypeDescription.Generic.Builder.parameterizedType(Repository.class, String.class).build()To build.
  • Setting the class name has been used before, adding the path information of the class.concatThe function is the concatenation of the string, substitution+Number.
  • method, set the name of the matching processing method.
  • MethodDelegation.to(UserRepositoryInterceptor.class)The ultimate core is the use of delegate functions. The use here can also be called to the delegate function we defined above, and so we eventually generated bytecodeclassClass to view.
  • annotateMethod,annotateType, define class and method annotations, throughdefineSet value (can be used multiple times).

4. Write the created class to the directory

// Output the class information to the target folder
dynamicType.saveIn(new File(ApiTest.class.getResource("/").getPath()));
Copy the code
  • This part isByte-buddyAPI methods provided;saveIn, write the bytecode information asclassGo to the execution folder. This makes it very easy to validate method content created through the bytecode framework.

Bytecode method content

package org.itstack.demo.bytebuddy;

@RpcGatewayClazz(
    clazzDesc = "Query data information".    alias = "dataApi". timeOut = 350L ) public class UserRepository extends Repository<String> {  @RpcGatewayMethod(  methodName = "queryData". methodDesc = "Query data"  )  public String queryData(int var1) {  return FindOneInterceptor.intercept(cachedValue$aGmAjHXh$iha1qv0, new Object[]{var1});  }   public UserRepository(a) {  }   static {  cachedValue$aGmAjHXh$iha1qv0 = Repository.class.getMethod("queryData", Integer.TYPE);  } } Copy the code
  • As you can see from the above, our custom class already implements the abstract class and also adds class and method annotation information.
  • One step in the implementation class is to use a delegate function to handle the contents of a method.

5. Output custom comment information

// Load the class information from the target folder
Class<Repository<String>> repositoryClass = (Class<Repository<String>>) Class.forName("org.itstack.demo.bytebuddy.UserRepository");

// Get class annotations
RpcGatewayClazz rpcGatewayClazz = repositoryClass.getAnnotation(RpcGatewayClazz.class);
System.out.println("RpcGatewayClazz. ClazzDesc:" + rpcGatewayClazz.clazzDesc()); System.out.println("RpcGatewayClazz. Alias:" + rpcGatewayClazz.alias()); System.out.println("RpcGatewayClazz. A timeOut." + rpcGatewayClazz.timeOut());  // Get method annotations RpcGatewayMethod rpcGatewayMethod = repositoryClass.getMethod("queryData".int.class).getAnnotation(RpcGatewayMethod.class); System.out.println("RpcGatewayMethod. MethodName:" + rpcGatewayMethod.methodName()); System.out.println("RpcGatewayMethod. MethodDesc:" + rpcGatewayMethod.methodDesc()); Copy the code
  • In this case, we’re usingClass.forNameTo load class information. It can also be used as in previous chapters;unloadedType.load(XXX.class.getClassLoader())To directly process bytecode.
  • Finally, read the information content from the definition annotations, including classes and methods.

6. Test validation run

// instantiate the object
Repository<String> repository = repositoryClass.newInstance();
// Test the output
System.out.println(repository.queryData(10001));
Copy the code
  • throughClass.forNameIf the bytecode is loaded, it needs to be reflected (Previous chapters have cases to learn from).

The test results

RpcGatewayClazz. ClazzDesc: query data informationRpcGatewayClazz. Alias: dataApiRpcGatewayClazz. A timeOut:350
RpcGatewayMethod. MethodName: queryDataRpcGatewayMethod. MethodDesc: query dataQuery article data: HTTPS://bugstack.cn/?id=10001  Process finished with exit code 0 Copy the code
  • Not surprisingly, you can see the result above, with our bytecode creation method we can output the content as we want.

Five, the summary

  • In this chapter, we need to pay attention to the use of several knowledge points, including;Delegate method use,Generic creation of complex types,Add class and method custom annotationsAs well asWrites bytecode information to a file.
  • Up to now, we have basically completed the self-learning and sharing of the common bytecode framework, and some other API use can refer to the official documentation; bytebuddy.net
  • Every piece of knowledge can only be gained through systematic learning, and the fragmented experience brought by a few words always fails to give a comprehensive understanding of a technology. On this road of technology, more refueling!

Six, eggs

CodeGuide | programmers coding guidelines Go! This code base is a technical summary of the author’s learning process of Internet Java development for many years. It aims to provide you with a clear and detailed learning tutorial, focusing on the writing of Java core content. If the warehouse can help you, please give support (attention, like, share)!


CodeGuide | programmers coding guidelines

Bugstack wormhole stack
Precipitation, share, grow, let yourself and others can gain something!
Author Little Fu Ge has been engaged in front-line Internet Java development for many years. From 19 years, he began to compile the technical summary of his work and learning process, aiming to provide you with a clear and detailed core skills learning document. If this article can help you, please support (follow, like, share)!