Cglib’s dynamic proxy can proxy classes as well as interfaces

Open cglib’s dependencies and you can see that it relies on the ASM framework to implement dynamic proxies

Let’s start by using Cglib’s dynamic proxy to proxy the time it takes to print the call method.

Create class UserService to implement login logic

package asm;

public class UserService {
    public boolean login(String username, String password) {
        return "admin".equals(username) && "admin".equals(password); }}Copy the code

Implementation of the MethodInterceptor callback type, print time.

package asm;

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

import java.lang.reflect.Method;

public class UserMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            return proxy.invokeSuper(obj, args);
        } catch (Exception e) {
            throw e;
        } finally {
            System.out.println("invoke-" + obj.getClass().getName() + "." + method.getName() + ":" + (System.currentTimeMillis() - start) + "ms"); }}}Copy the code

Then use Enhancer to create the proxy class. Cglib is very convenient:

  1. Create an Enhancer instance
  2. Set the base class for which the proxy is required
  3. Set the callback type
package asm;

import net.sf.cglib.proxy.Enhancer;

public class Main {
    public static void main(String[] args) {
        System.out.println("Cglib dynamic proxy begins");
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        enhancer.setCallback(new UserMethodInterceptor());
        UserService userService = (UserService) enhancer.create();
        System.out.println(userService.login("admin"."admin"));
        System.out.println(userService.login("admin"."admin1")); }}Copy the code

Print result:

Let’s explore what a class generated by a dynamic proxy actually looks like

When you open the DebuggingClassWriter class, you can find that the output class file is in the directory of the DEBUG_LOCATION_PROPERTY value of the system configuration

Set the DEBUG_LOCATION_PROPERTY value to the file directory that we can easily open. I’m going to set it to ‘./cglib’.

The main method generates three class files, and the console output shows that the class we call is $$6a598181

Next look at the generated class UserService
E n h a n c e r B y C G L I B EnhancerByCGLIB
6a598181

  • Inheriting from our parent class UserService
  • Implements the interface Factory

Take a look at the interface Factory

Factory Interface Description

  • All enhanced instances returned by the Enhancer class implement this interface.
  • Using this interface for a new instance is faster than using the Enhancer interface or reflection.
  • In addition, to intercept methods called during object construction, you must use those methods instead of reflection.

The Factory method definition provides for getting instance objects and adding callbacks

  • No arguments structure
  • Have the cords structure
  • Set the callback type
  • Gets the callback type

public interface Factory {
    /** * create a new instance of the same type using the no-argument constructor. The class of this object must be created using a single callback type. If more than one callback is required, an exception is thrown. * Arguments: * callback - New interceptor to use * returns: new instance of the same type */     
    Object newInstance(Callback callback);
    
    /** * create a new instance of the same type using the no-argument constructor. * Arguments: * callbacks - new callback to use * returns: new instance of the same type */     
    Object newInstance(Callback[] callbacks);

    /** * creates a new instance of the same type using a constructor that matches the given signature. * Arguments: * types - constructor argument type * ARgs - constructor argument * callbacks - new interceptor to use * returns: new instance of the same type */
    Object newInstance(Class[] types, Object[] args, Callback[] callbacks);

    /** * returns Callback implementation at the specified index * argument: index - Callback index * returns: Callback implementation */
    Callback getCallback(int index);

    /** * Set the callback for this object for the given type. * Parameter: * index - callback index to replace * callback - new callback */
    void setCallback(int index, Callback callback);

    /** * Replace all callback * arguments to this object at once: * callbacks - the new callback to use */
    void setCallbacks(Callback[] callbacks);

    /** * gets the current callback set for this. * Returns: a new array instance */     
    Callback[] getCallbacks();
}
Copy the code

Finish see Factory, back to see class UserService EnhancerByCGLIBEnhancerByCGLIBEnhancerByCGLIB6a598181

You can see in the generated class, the methodCGLIB
l o g i n login
0
The login method of the parent UserService is called, and the login method will call the callback intercept method for proxy logic processing.

To call the Intercept method as an input parameter:

  • Obj: the generated proxy class object UserService EnhancerByCGLIBEnhancerByCGLIBEnhancerByCGLIB6a598181
  • Method: userService. login method
  • Args: method call parameter
  • Proxy: proxy that encapsulates the CGLIB LoginLogin0 method