美文网首页
lambda之‘::’方式获取类方法名(mybatis-plus

lambda之‘::’方式获取类方法名(mybatis-plus

作者: hihuzi | 来源:发表于2021-01-27 17:37 被阅读0次
    近来总是在用lambda的方式开发,偶然间发现mybatis-plus的lambda的使用很是新颖....也一直困惑,终于有空最近扒了一下代码  。。。
    

    疑惑通过lambad方式提取出类里面的东东(方法,属性,类名)-好处吗写框架的自然懂

    好吧开整。。。。。

    模型准备

    @Setter
    @Getter
    @Accessors(chain = true)  //这个链式注解很重用主要用于获取带参数的方法
    public class Person {
        private String name;
        private int age;
        private float height;
        private boolean haveACar;
        private BigDecimal money;
    }
    

    期望的结果

            String methodName = LambdaUtil.getMethodName(Person::getName);
            结果是: getName
            String methodName =  LambdaUtil.getMethodName((Person person) -> person.setAge());
            结果是: setAge
    
    #想想一下是不是可以接下来这么玩。。。。。。
       String names = LambdaUtil.getMethodNames(Person::getName,Person::getAge,Person::getHight,Person::isHaveACar,Person::getMoney);
       结果是: name,age,height,haveACar,money
    

    好吧这里直接上菜啦

    https://gitee.com/hihuzi-top/lambda-analysis.git

        @Test
        void lffSimple() {// 这里直接获取到这个对象的lambda的方法名称(不一定是get或者set开头的代码)
            SerializedLambda serializedLambda = AnalysisUtil.lffSimple(Person::isHaveACar);
            Assertions.assertEquals("isHaveACar", serializedLambda.getImplMethodName());
        }
    
        @Test
        void lfSimple() {// 这里直接获取到这个对象的lambda的方法名称(get开头的方法名)
            java.lang.invoke.SerializedLambda serializedLambda = AnalysisUtil.lfSimple(Person::getAge);
            Assertions.assertEquals("getAge", serializedLambda.getImplMethodName());
        }
    
        @Test
        void testLfSimple() {// 这里直接获取到这个对象的lambda的方法名称(set开头的方法名)
            java.lang.invoke.SerializedLambda serializedLambda = AnalysisUtil.lfSimple(Person::setMoney);
            Assertions.assertEquals("setMoney", serializedLambda.getImplMethodName());
        }
    
        @Test
        void lfS() {
            SerializedLambda serializedLambda = AnalysisUtil.lfS(Person::getName);
            Assertions.assertEquals("getName", serializedLambda.getImplMethodName());
        }
    

    核心代码说明

    实现上面的代码主要有两个

    1 自定义注解需要继承 java.io.Serializable

    @FunctionalInterface
    public interface LBiFunction<T, U, R> extends BiFunction<T, U, R>, Serializable {
    }
    

    2 通过反射方式获取类信息 返回类型是 java.lang.invoke.SerializedLambda
    其实下面两个方法其实是方法重载区别在于是否有参数

        /**
         * 获取类的对象方法-不带形参(反射方式)
         *
         * @param function
         * @param <T>
         * @return
         */
        public static <T> java.lang.invoke.SerializedLambda lfSimple(LFunction<T, ?> function) {
            Method method = function.getClass().getDeclaredMethods()[1];
            method.setAccessible(true);
            try {
                return (java.lang.invoke.SerializedLambda) method.invoke(function);
            } catch (IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }
        /**
         * 获取类的对象方法-带形参(反射方式)
         *
         * @param function
         * @param <T>
         * @return
         */
        public static <T, U> java.lang.invoke.SerializedLambda lfSimple(LBiFunction<T, U, ?> function) {
            Method method = function.getClass().getDeclaredMethods()[1];
            method.setAccessible(true);
            try {
                return (java.lang.invoke.SerializedLambda) method.invoke(function);
            } catch (IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }
    

    到这里其实已经结束啦 可是呢既然是扒代码是吧。。。那mybatis-plus的实现也是这样吗, 那 为啥返回值是java.lang.invoke.SerializedLambda,纳尼这是啥。。。 好吧慢慢来。。。

    mysqlbatis-plus 是通过序列化后直接自己定义的一个SerializedLambda.class 类而且版本号一致(必须一致否这反序列化时无法转换类型)。。

        /**
         * 获取类的对象方法-不带形参(序列化方式)
         *
         * @param function
         * @param <T>
         * @return
         */
        public static <T> SerializedLambda lffSimple(LFunction<T, ?> function) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
            try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
                oos.writeObject(function);
                oos.flush();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            try (ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())) {
                Class<?> clazz;
    
                @Override
                protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
                    clazz = super.resolveClass(desc);
                    return clazz == java.lang.invoke.SerializedLambda.class ? SerializedLambda.class : clazz;
                }
            }) {
                return (SerializedLambda) inputStream.readObject();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    

    其实代码不是很难只是用了序列化后在转型为自己定义的SerializedLambda.class
    其实也是可以想到SerializedLambda 类肯定也是需要继承 java.lang.invoke.SerializedLambda

    public class  SerializedLambda implements Serializable {
    
        private static final long serialVersionUID = 8025925345765570181L;
    
        private Class<?> capturingClass;
        private String functionalInterfaceClass;
        private String functionalInterfaceMethodName;
        private String functionalInterfaceMethodSignature;
        private String implClass;
        private String implMethodName; // 这个就是方法名称啦!!!
        private String implMethodSignature;
        private int implMethodKind;
        private String instantiatedMethodType;
        private Object[] capturedArgs;// 如果对象可被序列化其实这里面保存的就是对象的具体值
    }
    

    好久没写了,有空在完善。。。。

    相关文章

      网友评论

          本文标题:lambda之‘::’方式获取类方法名(mybatis-plus

          本文链接:https://www.haomeiwen.com/subject/kjwbzktx.html