소스 검색

同步代码.

nieqiurong 5 년 전
부모
커밋
a6ae6ab4e9

+ 71 - 26
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/override/MybatisMapperProxy.java

@@ -21,10 +21,12 @@ import org.apache.ibatis.reflection.ExceptionUtil;
 import org.apache.ibatis.session.SqlSession;
 
 import java.io.Serializable;
+import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.Map;
 
@@ -37,16 +39,16 @@ import java.util.Map;
  */
 public class MybatisMapperProxy<T> implements InvocationHandler, Serializable {
 
-    private static final long serialVersionUID = -6424540398559729838L;
+    private static final long serialVersionUID = -5154982058833204559L;
     private static final int ALLOWED_MODES = MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
         | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC;
     private static final Constructor<MethodHandles.Lookup> lookupConstructor;
     private static final Method privateLookupInMethod;
     private final SqlSession sqlSession;
     private final Class<T> mapperInterface;
-    private final Map<Method, MybatisMapperMethod> methodCache;
+    private final Map<Method, MapperMethodInvoker> methodCache;
 
-    public MybatisMapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MybatisMapperMethod> methodCache) {
+    public MybatisMapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethodInvoker> methodCache) {
         this.sqlSession = sqlSession;
         this.mapperInterface = mapperInterface;
         this.methodCache = methodCache;
@@ -83,38 +85,81 @@ public class MybatisMapperProxy<T> implements InvocationHandler, Serializable {
         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);
-                }
+            } else {
+                return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
             }
         } catch (Throwable t) {
             throw ExceptionUtil.unwrapThrowable(t);
         }
-        final MybatisMapperMethod mapperMethod = cachedMapperMethod(method);
-        return mapperMethod.execute(sqlSession, args);
     }
-
-    private MybatisMapperMethod cachedMapperMethod(Method method) {
-        return CollectionUtils.computeIfAbsent(methodCache, method,
-            k -> new MybatisMapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
+    
+    private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
+        try {
+            return CollectionUtils.computeIfAbsent(methodCache, method, m -> {
+                if (m.isDefault()) {
+                    try {
+                        if (privateLookupInMethod == null) {
+                            return new DefaultMethodInvoker(getMethodHandleJava8(method));
+                        } else {
+                            return new DefaultMethodInvoker(getMethodHandleJava9(method));
+                        }
+                    } catch (IllegalAccessException | InstantiationException | InvocationTargetException
+                        | NoSuchMethodException e) {
+                        throw new RuntimeException(e);
+                    }
+                } else {
+                    return new PlainMethodInvoker(new MybatisMapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
+                }
+            });
+        } catch (RuntimeException re) {
+            Throwable cause = re.getCause();
+            throw cause == null ? re : cause;
+        }
     }
 
-    private Object invokeDefaultMethodJava9(Object proxy, Method method, Object[] args)
-        throws Throwable {
+    private MethodHandle getMethodHandleJava9(Method method)
+        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
         final Class<?> declaringClass = method.getDeclaringClass();
-        return ((MethodHandles.Lookup) privateLookupInMethod.invoke(null, declaringClass, MethodHandles.lookup()))
-            .findSpecial(declaringClass, method.getName(),
-                MethodType.methodType(method.getReturnType(), method.getParameterTypes()), declaringClass)
-            .bindTo(proxy).invokeWithArguments(args);
+        return ((MethodHandles.Lookup) privateLookupInMethod.invoke(null, declaringClass, MethodHandles.lookup())).findSpecial(
+            declaringClass, method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()),
+            declaringClass);
     }
-
-    private Object invokeDefaultMethodJava8(Object proxy, Method method, Object[] args)
-        throws Throwable {
+    
+    private MethodHandle getMethodHandleJava8(Method method)
+        throws IllegalAccessException, InstantiationException, InvocationTargetException {
         final Class<?> declaringClass = method.getDeclaringClass();
-        return lookupConstructor.newInstance(declaringClass, ALLOWED_MODES).unreflectSpecial(method, declaringClass)
-            .bindTo(proxy).invokeWithArguments(args);
+        return lookupConstructor.newInstance(declaringClass, ALLOWED_MODES).unreflectSpecial(method, declaringClass);
+    }
+
+    interface MapperMethodInvoker {
+        Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable;
+    }
+    
+    private static class PlainMethodInvoker implements MapperMethodInvoker {
+        private final MybatisMapperMethod mapperMethod;
+        
+        public PlainMethodInvoker(MybatisMapperMethod mapperMethod) {
+            super();
+            this.mapperMethod = mapperMethod;
+        }
+        
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
+            return mapperMethod.execute(sqlSession, args);
+        }
+    }
+    
+    private static class DefaultMethodInvoker implements MapperMethodInvoker {
+        private final MethodHandle methodHandle;
+        
+        public DefaultMethodInvoker(MethodHandle methodHandle) {
+            super();
+            this.methodHandle = methodHandle;
+        }
+        
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
+            return methodHandle.bindTo(proxy).invokeWithArguments(args);
+        }
     }
 }

+ 4 - 7
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/override/MybatisMapperProxyFactory.java

@@ -32,19 +32,16 @@ import java.util.concurrent.ConcurrentHashMap;
  * @since 2018-06-09
  */
 public class MybatisMapperProxyFactory<T> {
-
+    
     @Getter
     private final Class<T> mapperInterface;
-    private final Map<Method, MybatisMapperMethod> methodCache = new ConcurrentHashMap<>();
-
+    @Getter
+    private final Map<Method, MybatisMapperProxy.MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
+    
     public MybatisMapperProxyFactory(Class<T> mapperInterface) {
         this.mapperInterface = mapperInterface;
     }
 
-    public Map<Method, MybatisMapperMethod> getMethodCache() {
-        return methodCache;
-    }
-
     @SuppressWarnings("unchecked")
     protected T newInstance(MybatisMapperProxy<T> mapperProxy) {
         return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);

+ 1 - 2
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/MybatisMapperRegistryTest.java

@@ -17,7 +17,6 @@
 package com.baomidou.mybatisplus.test.h2;
 
 import com.baomidou.mybatisplus.core.MybatisMapperRegistry;
-import com.baomidou.mybatisplus.core.override.MybatisMapperMethod;
 import com.baomidou.mybatisplus.core.override.MybatisMapperProxyFactory;
 import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
 import com.baomidou.mybatisplus.test.h2.config.DBConfig;
@@ -97,7 +96,7 @@ class MybatisMapperRegistryTest extends BaseTest {
             
             H2StudentChildrenMapper h2StudentChildrenMapper = mapperRegistry.getMapper(H2StudentChildrenMapper.class, sqlSession);
             Assertions.assertFalse(configuration.hasStatement(H2StudentChildrenMapper.class.getName() + ".selectById"));
-            Map<Method, MybatisMapperMethod> methodCache = mybatisMapperProxyFactory.getMethodCache();
+            Map<Method, ?> methodCache = mybatisMapperProxyFactory.getMethodCache();
             Assertions.assertTrue(methodCache.isEmpty());
             
             h2StudentChildrenMapper.selectById(2);

+ 1 - 1
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/cache/model/CacheModel.java

@@ -25,7 +25,7 @@ import java.io.Serializable;
 @Data
 @NoArgsConstructor
 @AllArgsConstructor
-@TableName(value = "cache")
+@TableName(value = "t_cache")
 public class CacheModel implements Serializable {
 
     private Long id;

+ 6 - 6
mybatis-plus/src/test/resources/cache/init.ddl.sql

@@ -1,10 +1,10 @@
-CREATE TABLE IF NOT EXISTS  cache (
+CREATE TABLE IF NOT EXISTS  t_cache (
 	id BIGINT(20) NOT NULL,
 	name VARCHAR(30) NULL DEFAULT NULL ,
 	PRIMARY KEY (id)
 );
-insert into cache values (1,'a');
-insert into cache values (2,'b');
-insert into cache values (3,'c');
-insert into cache values (4,'d');
-insert into cache values (5,'e');
+insert into t_cache values (1,'a');
+insert into t_cache values (2,'b');
+insert into t_cache values (3,'c');
+insert into t_cache values (4,'d');
+insert into t_cache values (5,'e');