Older rookie-"mybatis source code reading -" reflection module

As an older female programmer who has been working for 7 years, to be honest, I have never seen any source code. Forced by the confusion of the future. I want to change the status quo. I want to do something different from the previous years of work.

Looking at the starting point of the source code, I want to see how the code of the Great God is written, and I want to know what other people think. Then reflect on what you think if it is yourself.

The teacher at the training school told us that csdn is the best website for developers to communicate. Here, in my enlightenment and learning website. I set up a flag. I want to update the source code that I use . I may change my career before the update is complete, but I just want to do something.

Not to prove to anyone. Just want to start and end well. Have an account of the past. It turns out that I can export and settle something.

One: The following is the directory of the mybatis package. Our protagonist today is the reflection package.

Two: This reflection package, I look down, the most important is the following categories, I listed the key methods. Reflector reflector is the bottom layer processing reflection. The methods in this diagram are not the most complete. I only pick the key columns.

 

It can be seen from the figure above. The control of MetaObject is basically handed over to ObjectWrapper for control. The control of classes in ObjectWrapper depends on the MetaClass class, and the MetaClass class depends on ReflectorFactory and Reflector.

The above are the simplest attributes. When the attribute is like the following, word segmentation will be performed, and then the above getValue and setValue will enter a recursive loop. You can test it yourself.

 @Test
  void shouldGetAndSetNestedProperty() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richType.richProperty", "foo");
    assertEquals("foo", meta.getValue("richType.richProperty"));
  }
三: MetaObject 对象的 setValue 和 getValue 里面用了递归,递归的控制是由分词器PropertyTokenizer 来控制结束的。里面有单测类,强烈建议运行下单测看数据。就能理解我为啥说setValue 难。为啥麻烦。

The tokenizer PropertyTokenizer has a particularly high probability of appearing in reflection packets.

Four: PropertyTokenizer analysis is as shown in the figure below.

 

Five: Today is the first day of analysis. I read it for the first time, and maybe I can understand the seven or eight levels. It may not seem vivid to express it. Forgive me if you don’t write well. Below I am on the single test and step-by-step annotated source code

Embarrassing, code packages are not allowed in the article. I put the code in my resource file. You can download the resource files without points. https://download.csdn.net/download/lileronglilerong/15120273

Six: Additional supplements

a: Looking at the above code, I have encountered some unintelligible writing. Understand it myself. About function

package com.llr.reflect.test;

import java.util.function.Function;

public class FunctionTest {
    public static void main(String[] args) {
        String s="1234";
       /* method(s,(String inputValue)->{
            return  Integer.parseInt(inputValue);
        });*/
       // 这个写法和上面的是一样的
        method(s, Integer::parseInt);
        /**
         *    Reflector::new 等价于下面的表达式
         *    Function<Class,Reflector> function=input->new Reflector(input);
         */
    }

    public static void method(String s, Function<String,Integer> function){
        Integer i=function.apply(s);
        System.out.println(i);
    }
}

b: computeIfAbsent  和 isAssignableFrom

package com.llr.reflect.test;

import java.util.HashMap;

public class MapTest {
    public static void main(String[] args) {
        /**
         * 1: computeIfAbsent的方法
         * computeIfAbsent的方法有两个参数 第一个是所选map的key,第二个是需要做的操作。这个方法当key值不存在时才起作用
         */
        HashMap map=new HashMap();
        // java8之前。从map中根据key获取value操作可能会有下面的操作
        Object value = map.get("key");
        if (value == null) {
            value = new Object();
            map.put("key", value);
        }
        // java8之后。上面的操作可以简化为一行,若key对应的value为空,会将第二个参数的返回值存入并返回
        Object key2 = map.computeIfAbsent("key", k -> new Object());


        /**
         * 2:isAssignableFrom (is Assignable(可分配))    instanceof
         *
         * ClassA.isAssignableFrom(ClassB); 表示ClassA是ClassB父类就返回true,否则返回false
         *
         *  父类.class.isAssignableFrom(子类.class)
         *  子类实例 instanceof 父类类型
         */
    }
}

c: What is an example?

package com.llr.reflect.test;

public class BaseTest {
    public static void main(String[] args) {
        /**
         * 1: 什么是java的实例,什么是引用,什么是引用地址,什么是内存地址。
         *
         * Cat c 的意思是,在内存中分配一个变量,名字叫c,这个变量是Cat类型的
         *
         * new Cat(); 说明 new这个Cat类的一个对象,程序运行的时候,会调用构造方法Cat(),等这个构造方法执行完了,这个Cat类型的对象也就造出来了,真正的出现在内存当中了
         *
         * c就是引用,不是对象!我们new出来的这个东西,真正在内存中的这个东西叫做对象,叫做实例.
         */
        Cat c = new Cat();
        /**
         *
         * 2: 单例模式 和 静态方法。
         *
         * 这个怎么区分,如何进行使用。
         *
         * 目标:
         * a: 弄明白什么是单例模式,什么是 静态方法。
         * b: 弄明白二者的区别。
         * c: 弄明白适合的场景
         *
         * 静态方法和非静态方法:
         * 一: 静态方法和非静态方法。他们都是在第一次加载后就常驻内存
         * 二:
         * 在内存中的区别,非静态方法,创建实例对象的时候,因为属性的值对于每个对象不同,故new一个实例的时候,会把
         * 实例属性在GC heap 里copy一份,同时这个new出来的对象放在堆栈上,堆栈指针指向了刚才拷贝的那一份实例的内存地址上。
         * 而静态方法不需要。因为静态方法里面的静态字段,就是保存再 method table 里的,就只有一份。
         *
         * 三: 早期几乎所有方法都是“静态方法”,引入实例化方法概念是面向对象概念出险以后的事情。
         *
         * 结论:静态方法和实例方法是为了解决模式问题。 如果一个方法和他所在类的实例对象无关,那么他应该是静态的。否则应该是非静态的,像工具类,一般都是静态的
         *
         * 为什么使用单例模式而不用静态方法?
         * 如果一个方法和他所在类的实例对象无关,那么他应该是静态的,反之他就应该是非静态的,如果我们确实应该使用非静态的
         * 方法,但是在创建类时又确实只需要维护一份实例时,就需要用单例模式。
         *
         */
    }

    static class Cat{
        public Cat() {
        }
    }
}

d:

There are some methods in the Class class and some methods in the Method class. When looking at the ParamNameUtil method, I first discovered

Executable 类是 :方法和Constructor的共同功能的共享超类 
package com.llr.reflect.test;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;

public class MethodTest {
    public static void main(String[] args) {

        try {
            /**
             * 1:  Class 类中的 区别是什么:getMethod,getDeclaredMethod
             */
            Class studentClass = Student.class;
            // Member  接口中的 PUBLIC和 DECLARED就有对应的描述
            // getMethod 返回所有公用的(public) 包括继承的, 如果 getName 给的是private的话,是会报错的。
            Method getNameMethod = studentClass.getMethod("getName");
            // getDeclaredMethod 返回包括公用的,私有的,默认的,但是不包括继承的
            Method setNameMethod = studentClass.getDeclaredMethod("setName", String.class);
            System.out.println(getNameMethod.getName());
            System.out.println(setNameMethod.getName());

            /**
             *
             * 2:  getDeclaringClass 和 getClass区别
             * getDeclaringClass
             * 返回的是 (返回 类表示声明该对象表示的可执行的类或接口对象。 )
             * class com.llr.reflect.test.MethodTest$Student
             *
             * getClass: (返回此Object的运行时类。 返回的类对象是被表示类的static synchronized方法锁定的对象。 )
             * 返回的是:class java.lang.reflect.Method
             */
            System.out.println("+++++++++++++++++");
            System.out.println(getNameMethod.getDeclaringClass());
            System.out.println(getNameMethod.getClass());

            /**
             * 3: getParameterTypes和getGenericParameterTypes区别
             *
             * getParameterTypes 无法取到对象中是泛型的结构化参数。 setAgeList:List
             * getGenericParameterTypes 可以取到对象中泛型的结构化参数。 setAgeList:java.util.List<java.lang.Integer>
             *
             */
            System.out.println("+++++++++++++++++");
            Method[] methods = studentClass.getMethods();
            Arrays.stream(methods).forEach(method -> {
                Class[] pType = method.getParameterTypes();
                Type[] gPType = method.getGenericParameterTypes();
                if (method.getName().contains("setAgeList")) {
                    for (Class aClass : pType) {
                        System.out.println(method.getName() + ":" + aClass.getSimpleName());
                    }
                    for (Type type : gPType) {
                        System.out.println(method.getName() + ":" + type.getTypeName());
                    }
                }
            });
            System.out.println("+++++++++++++++++");

            /**
             * 2: Method   中的getGenericReturnType和getType的区别,
             *
             * Class 实现了 Type 接口。Type 是更上层的接口
             *
             * getType 输出 class java.lang.Object,而 getGenericType 输出的是 T。
             *
             * 如果 getGenericSignature 不为空,即如果当前类型是泛型,则返回泛型类型,反之返回 getType() 的值
             */
            Class getAge = ReturnTypeTest.class.getDeclaredFields()[0].getType();
            Type getGenericAge = ReturnTypeTest.class.getDeclaredFields()[0].getGenericType();
            System.out.println(getAge.getSimpleName());
            System.out.println(getGenericAge.getTypeName());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }


    static class Student {
        private String name;
        private List<Integer> ageList;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public List<Integer> getAgeList() {
            return ageList;
        }

        public void setAgeList(List<Integer> ageList) {
            this.ageList = ageList;
        }
    }

    static class ReturnTypeTest<T> {
        T ageInfo;
    }
}

 

Guess you like

Origin blog.csdn.net/lileronglilerong/article/details/113744229