Preface

I was writing before --> talk about how spi based on jdk integrates with spring to realize dependency injection . When the demo of this article was used, dynamic proxy was used. During debugging, I found a magical phenomenon. As shown below

在这里插入图片描述
The proxy object becomes null, but there will be no null pointer exception

Phenomenon analysis

First look at the core implementation logic of the sample agent

 @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        boolean canPass = preHandle(method,args);
        Object result = null;
        if(canPass){
             result = method.invoke(target,args);
             afterCompletion(method,args);
        }

        return result;

    }

When this logic is false, result will be null. The idea is to enable debugging. When calls an object, the toString method is called by default. When the proxy triggers invoke, because preHandle cannot find the toString method, it will cause canPass to be false, which triggers a null phenomenon.

Say there is no proof, we can verify, we adjust the core method of the agency

   @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if("toString".equals(method.getName())){
            return "我是toString方法";
        }
        boolean canPass = preHandle(method,args);
        Object result = null;
        if(canPass){
             result = method.invoke(target,args);
             afterCompletion(method,args);
        }

        return result;

    }

Do dubug at this time, as shown below
在这里插入图片描述

Problem fix

1. Method 1: Disable the default call toString method of idea

image.png

2. Method 2: In the proxy invoke method, add the following code snippets as follows
 // 如果Object方法直接反射调用
        if(Object.class.equals(method.getDeclaringClass())){
            return method.invoke(this, args);
        }

This kind of solution, the dynamic agent implemented in mybatis has appeared

@Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (method.isDefault()) {
        if (privateLookupInMethod == null) {
          return invokeDefaultMethodJava8(proxy, method, args);
        } else {
          return invokeDefaultMethodJava9(proxy, method, args);
        }
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }

The above is taken from the MapperProxy proxy fragment of mybatis

Summarize

Be more curious and look at the source code


linyb极客之路
344 声望193 粉丝