What is CGLIB?

In summary, whether cglib, JDK dynamic proxy, or AOP aspect oriented programming utilizes one of the most important design patterns — the proxy pattern! 10 million change does not leave its end, learn agent mode, hit the world invincible hand!

Cglib is a bytecode generation and conversion library. This is understandable, as it is primarily used by AOP, test, and data access frameworks to generate dynamic proxy objects and intercept field access.

Today we will talk about the application of Cglib in agent!

Two, CGLIB source rough interpretation!

Cglib source code package structure:

The cglib core package contains a proxy package. Expand proxy to find:

The Enhancer class and MethodInterceptor interface in this package are the core of the package! M: Enhancer! Primarily used to generate dynamic subclasses to enable method interception, what do you mean? Speak like this! The basic idea of the cglib class proxy is to generate a new class (proxy) from the promenade class. This class inherits from the promenade class and performs some operations on the promenade method. These operations are usually callback operations, which can be a MethodInterceptor. LazyLoader, CallbackFilter, including MethodInterceptor is the most commonly used.

All Enhancer objects by default implement the Factory interface, which provides a set of methods to set the object’s callback type. You can disable this feature by calling setUseFactory(false)!

It is important to note that cglib cannot proxy final methods because this is determined by the Java language specification!

MethodInterceptor is a generic callback interface that provides circular notifications! Aop has terms like pre notification, post notification, and wrap notification, which are pretty easy to understand, one notification before a method is executed, one notification after a method is executed, and one notification before and after a method is executed.

The interface has only one intercept() method:

 public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                               MethodProxy proxy) throws Throwable;
Copy the code

All executions of propped methods jump to this Method, and the original Method is called from the reflected Method object or MethodProxy object.

Three, the old rules, to a chestnut reunion!

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

class Student {

	private String name = "zhangsan";

	public String getStuName() {
		returnname; }} public class CglibMethodInterceptTest {public static void main(String[] args) = new Enhancer(); // Set the conjured class enchaner.setsuperclass (student.class); // Create a Callback interceptor = newMethodInterceptor() {

			@Override
			public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
					throws Throwable {
				System.err.println(The original method name is: + method.getName());
				System.err.println("The class declared by the original method is + method.getDeclaringClass());
				System.err.println("I am" + (String) proxy.invokeSuper(obj, args));
				System.err.println("I'm done calling.");
				returnnull; }}; enchaner.setCallback(interceptor); Student student = (Student) enchaner.create(); student.getStuName(); }}Copy the code

The output is:

The name of the method is getStuName. The name of the method is wokao666.test.Student and the name is zhangsanCopy the code

Use of filters

package wokao666.test;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.NoOp;

class Student {

	private String name = "zhangsan";
	private String rename = "rename";

	public String getStuName() {
		return name;
	}

	public String getRename() {
		returnrename; }} public class CglibMethodInterceptTest {public static void main(String[] args) = new Enhancer(); // Set the conjured class enchaner.setsuperclass (student.class); // Create a Callback interceptor = newMethodInterceptor() {

			@Override
			public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
					throws Throwable {
				System.err.println(The original method name is: + method.getName());
				System.err.println("The class declared by the original method is + method.getDeclaringClass());
				System.err.println("I am" + (String) proxy.invokeSuper(obj, args));
				System.err.println("I'm done calling.");
				returnproxy.invokeSuper(obj, args); }}; CallbackFilter callbackFilter = newCallbackFilter() {

			@Override
			public int accept(Method method) {
				int flag = 0;
				if ("getStuName".equals(method.getName())) {
					System.err.println("I'm filtering out this method, I'm not blocking this method.");
					return 1;
				}
				return0; }}; Callback[] callbacks = new Callback[] { interceptor, NoOp.INSTANCE }; enchaner.setCallbackFilter(callbackFilter); enchaner.setCallbacks(callbacks); Student student = (Student) enchaner.create(); System.err.println(student.getStuName()); System.err.println(student.getRename()); }}Copy the code
Student = wokao666.test.Student = wokao666.test.Student = wokao666.test.Student = wokao666.test.Student = wokao666.testCopy the code

NoOp.INSTANCE: This NoOp stands for no operator, that is, nothing is done. The proxy class calls the proxied method directly without intercepting it.

Index 1 is defined in the corresponding CallbackFilter to getStuName, and the filter used in the Callback[] array is NoOp, so the propped method is executed directly.

GetRename corresponds to index 0 defined in CallbackFilter. The filter used in the Callback[] array is interceptor, so a method interceptor is executed.

I write just a little fur, I suggest that on the basis of this more hands-on, combined with the source code to write some examples, write more, know more!