This article is first published in the public number [look at the code to go to work], welcome to the crowd, the first time to get the latest article. Welcome to the original: mp.weixin.qq.com/s/PDeE329ng…

Hi, I’m Tin, and this is my 14th original article

Have you ever used Spring? Have you heard of Spring AOP? Must have both!

Cglib can be used as a proxy for a private method. Cglib can be used as a proxy for a private method.

  • What is Cglib
  • 2. Examples of using Cglib
  • Cglib source code analysis
  • Four, conclusion

What is Cglib

Cglib is an open source dynamic code generation tool, which is widely used in AOP, testing, data access frameworks, etc., to generate dynamic proxy objects and intercept method field access.Github.com/cglib/cglib… The purpose of cglib is to provide a proxy implementation for a class that does not implement an interfaceThis is different from JDK dynamic proxy and is a supplement to JDK dynamic proxy.

In Spring AOP, we use JDK dynamic proxy and Cglib proxy at the same time. By default, we use JDK dynamic proxy first and cglib proxy second.​ Docs. Spring. IO/spring – fram…

Cglib implements the proxy function by dynamically generating subclasses of the proxy class. The generated subclasses override all methods of the proxy class (excluding final methods, which will be discussed later on in private methods). The subclasses of cglib then use method interception to implement code weaving into the proxy class methods.

The bottom layer of Cglib uses the bytecode processing framework ASM operation to generate new subclasses. The following figure can intuitively understand the hierarchy of Cglib:

2. Examples of using Cglib

First introduce the jar package:

<dependency> <groupId>cglib</ artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>Copy the code

Define our own business class Developer:Write another method interceptor, DeveloperInterceptor:The MethodInterceptor implements cglib’s MethodInterceptor interface.

Finally, cglib’s bytecode enhancer generates a new proxy subclass:

package com.tin.example.cglib.cglib; import com.tin.example.cglib.design.pattern.SexEnum; import com.tin.example.cglib.design.pattern.employee.Developer; import net.sf.cglib.core.DebuggingClassWriter; import net.sf.cglib.proxy.Enhancer; /** * title: CglibTest * <p> * description: Public class CglibTest {public static void main(String args[]) {public static void main(String args[]) { / / additional output produced by the dynamic proxy class System. SetProperty (DebuggingClassWriter DEBUG_LOCATION_PROPERTY, "/Users/ericli/small-workshop/workspace/tin-example/cglib-class"); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Developer.class); DeveloperInterceptor enhancer. SetCallback (new DeveloperInterceptor()); // EnhancerByCGLIB$$... // EnhancerByCGLIB$$... Object obj = enhancer.create(); System.out.println("proxy class:" + obj.getClass()); Developer developer = (Developer) obj; developer.setLines(30000); Developer. setName(" programmer @ [watch code again] "); developer.setNumber(1L); developer.setSex(SexEnum.MALE); Developer. SetSalary (" RMB 15000 "); System.out.println(developer.print()); }}Copy the code

The final print result is as follows:

Cglib source code analysis

Cglib does this by subclassing a proxy class. Let’s find out through the source code.

The basic class diagram of Cglib is as follows:ClassGenerator is an interface for cglib to generate objects. It has only one method. The input of this method is the ASM ClassVisitor class.

package net.sf.cglib.core;

import org.objectweb.asm.ClassVisitor;

public interface ClassGenerator {
    void generateClass(ClassVisitor v) throws Exception;
}
Copy the code

In the CglibTest example, we use the henhancer.create () method to generate a proxy class for the target class.

The Enhancer. Create method calls createHelper(), which in turn calls the AbstractClassGenerator create() method:AbstractClassGenerator’s Create () method initializes a ClassLoaderData object:ClassLoaderData is an inner class that contains information about the classloader, generated proxy classes, and so on. Enter the constructor method of ClassLoaderData:

The constructor ends up calling AbstractClassGenerator’s generate method anyway:The generateClassName method defines the generateClassName generation rule for the proxy class.

... $$EnhancrByCGLIB $$...Copy the code

The DefaultGeneratorStrategy#generate() method returns an array of bytes using the asm bytecode framework inside.In Enhancer, we have overridden the generateClass() method, which manipulates class bytecode through ASM and generates a new class (our Cglib proxy class). The source code is as follows:At this point, the source code is basically finished, remember my test class main method added the following line of code:

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/ericli/small-workshop/workspace/tin-example/cglib-class");
Copy the code

It is used to output the class files of cglib generated proxy classes to local disk and, if not configured, will only be saved in the JVM by default. The generated cglib proxy class looks like this (the proxy class is so long that you can only put it on Git) : github.com/iam-tin/tin…

Let me just make two important points about lengthy proxy classes:

  • The proxy class inherits the business class

  • 2. The proxy class, as a subclass, overrides all the methods that the business class can override. These overrides are also the methods that the proxy class actually calls

For example, if we overwrite the Accept method in our business class, we will check if there is an interceptor configured, and execute the interceptor if there is:

Cglib generates a proxy class by inheriting and overwriting its parent class, so final classes and methods cannot pass the cglib proxy, and final methods cannot be found in the generated class file.

In that case, what about the private method? We know that subclasses cannot access the parent’s private methods, but we can write a method in a subclass that is exactly the same as the parent. Isn’t that enough? Why doesn’t CGLIb do the same?

This question, which is separate from Cglib itself, is actually a Basic Java knowledge point. In Java, methods in the parent class are private, and subclasses cannot access them. Even if a subclass implements a method identical to the parent class, it is actually just a new method that belongs to the subclass and does not override the corresponding method of the parent class.

For example, if the following BClass inherits AClass, the BClass “overrides” the private AClass method print() :

/** * title: AClass * <p> * description: Public class AClass {private void print() {private void print() { System.out.println("A"); } public static void main(String[] args) { AClass a = new BClass(); a.print(); BClass b = new BClass(); b.print(); new BClass().print(); } } class BClass extends AClass { public void print() { System.out.println("B"); }}Copy the code

Take a look at the output:If we change the AClass print() method to public, the result is different:This is the final conclusion: the Cglib proxy class cannot access the private methods of the business class, and therefore cannot proxy the private methods of the business class.

Four, conclusion

I am Tin, an ordinary engineer who is trying to make himself better. My experience is limited, knowledge is shallow, if you find something wrong with the article, you are very welcome to add me, I will carefully review and modify.

It is not easy to persist in creation. Your positive feedback is the most powerful motivation for me to persist in output. Thank you!

Finally, don’t forget to follow me! Attach the original link ⏬ ⏬ ⏬ mp.weixin.qq.com/s/PDeE329ng…