Preliminary knowledge for reading MyBatis source code - exception, serialization, reflection, annotation

1. exception

异常It means that unexpected things have been encountered while the program is running. In order to describe this abnormal situation, some general exceptions have been established in the Java standard library. Throwable is the parent class, which derives the Error class and the Exception class and its subclasses.

  • Error
    represents the exception of the JVM itself. When this type of exception occurs, it cannot be corrected by the program, and the JVM needs to be stopped as soon as possible.

  • Exception
    represents that something unexpected happened while the program was running. Situations other than these can be handled by Java's exception handling mechanism. Exception has two derived subclasses

  1. Exceptions such as RuntimeException
    are actually programming errors, which can be avoided by correcting the program, such as out-of-bounds subscripts, division-by-zero exceptions, etc.
  2. Exceptions such as non-RuntimeException
    are usually caused by external factors and are inevitable. Such as: IO abnormality, network abnormality

When encountering complex class relationships, drawing their UML class diagrams is a very good way to clarify their previous relationships.
Insert image description here
Among the exceptions shown in the above figure, Error and RuntimeException are called unchecked exceptions. There is no need to force these two types of exceptions. examine. Except for these two types of exceptions, other exceptions are called must-detect exceptions. You need to handle this type of exception when writing code.

Throwable object, its main member variables are detailMessage and cause.

  • detailMessage is a string used to store exception details.
  • cause is another Throwable object used to store the cause of the exception. This is because when an exception occurs, the upper-level program that usually causes the exception also occurs an exception, resulting in a series of exceptions, called 异常链. The cause attribute of an exception can point to the subordinate exception that raised it, thus saving the entire exception chain.Insert image description here

2. Serialization

Serialization: is the process of converting objects into byte sequences.
Deserialization: It is the process of restoring a byte sequence into an object.

Serialization of objects usually serves two purposes:

  1. Serialize the object into bytes and save it in the storage medium. is for persisting objects
  2. Serialize the object into bytes and then transmit it over the network. is for transferring objects

When using RPC frameworks such as dubbo, the entity object must implement the Serializable interface because the object must be serialized for transmission between networks.

In Java, to indicate that a class is serializable, it must be based on the Serializable interface or the Externalizable interface.
The use of the Serializable interface is very simple. You only need to implement the Serializable interface for the class that needs to be serialized. No need to add any methods.

2.1 Version issues during serialization

During the serialization and deserialization process, version issues must be faced.
For example: persist the User class object user to the hard disk. Then, new attributes are added to the User class. Can the user object persisted in the hard disk be deserialized into a new User class object at this time?

The answer to this question involves the serialVersionUID field of the Serializable interface. The serialVersionUID field is called the serialization version control field, and we often see it in classes that implement the Serializable interface.

public class User implements Serializable {
    
    
    private static final long serialVersionUID = 1L;
}

During the deserialization process, if the serialVersionUID in the object byte sequence is different from the value of the current class, the deserialization fails. Otherwise succeed.
If the serialVersionUID attribute is not explicitly defined for the class, one will be automatically generated. The automatically generated serialized versioning fields are related to class names, class and property modifiers, interfaces and interface order, properties, constructors, etc. Changes to any of these will cause serialVersionUID to change.

Once for the above question. Whether the user object can be restored to a new User class object needs to be discussed on a case-by-case basis:

  1. If there is a serialVersionUID field in both the old User class and the new User class, and the values ​​are the same. It can be restored to a new User class object. If a new attribute is added to the new User class, its value is null
  2. If the serialVersionUID in the old class and the new class are inconsistent, or the serialVersionUID attribute value is not explicitly set. Because the system will automatically generate serialVersionUID. The deserialization fails. Exception will be reportedInvalidClassException

When used, a serialVersionUID is generally explicitly declared for classes that implement the Serializable interface. This will do:

  • When you want serialization and deserialization compatibility between versions of a class, keep the serialVersionUID value unchanged.
  • Ensure that the serialVersionUID value changes when you want serialization and deserialization to be incompatible between versions of a class.

3.Reflection

Java's reflection mechanism means that in the running state of the program, you can construct an object of any class, you can understand the class to which any object belongs, you can understand the member variables and methods of any class, and you can call any object. Properties and methods. This function of dynamically obtaining program information and dynamically calling objects is called the reflection mechanism of the Java language. Reflection is seen as the key to dynamic languages. --from Baidu entry

  1. The reflection mechanism greatly improves the flexibility and scalability of the program, reduces the coupling of modules, and improves its own adaptability.
  2. The reflection mechanism allows the program to create and control objects of any class without having to hardcode the target class in advance.
  3. The reflection mechanism can be used to construct an object of a class at runtime, determine the member variables and methods of a class, and call methods of an object.
  4. The reflection mechanism is the basis for building framework technology. Using reflection can avoid writing code into the framework.

It is precisely because reflection has the above characteristics that it can dynamically compile and create objects, which greatly stimulates the flexibility of programming languages, strengthens the polymorphic characteristics, and further enhances the abstraction ability of object-oriented programming. Therefore, it is favored by the programming community. favor.

Although the reflection mechanism brings great flexibility and convenience, reflection also has disadvantages. The reflection mechanism is very powerful, but it cannot be abused. When it can be done without using reflection, try not to use it for the following reasons:

  1. Performance issues. The Java reflection mechanism contains some dynamic types, so the Java virtual machine cannot optimize these dynamic codes. Therefore, reflection operation is much less efficient than normal operation. We should avoid using reflection in performance-critical programs or code that is executed frequently. Furthermore, how you use reflection determines performance. If it's a less running part of the program, performance won't be an issue.
  2. Security restrictions. Using reflection usually requires that the program run without security restrictions. If a program has security requirements, it is best not to use reflection.
  3. Program robustness. Reflection allows code to perform operations that are not normally allowed, so using reflection may lead to unintended consequences. Reflective code destroys the abstraction of Java program structure, so when the platform on which the program runs changes, because the abstract logical structure cannot be recognized, the effect of the code will be different from before.

Reflection is a must-have feature of every framework. So understanding reflection is crucial to reading frames.

3.1 Reflection example

Requirement: To compare whether the attributes of two classes are consistent.

  1. Entity class
public class Student {
    
    
    private Integer id;
    private String name;
}
public class Car {
    
    
    private String name;
    private String type;
}
  1. Tool class compares whether the properties of two Student objects are consistent
public class StudentUtils {
    
    
    /**
     * 比较两个student对象的不同属性
     */
    public static Map<String,String> diffStudent(Student oldStu,Student newStu){
    
    
        Map<String,String> diffMap=new HashMap<>();
        if(oldStu.getId()!=null && !oldStu.getId().equals(oldStu.getId())){
    
    
            diffMap.put("id","from "+oldStu.getId()+" to " + newStu.getId());
        }
        if(oldStu.getName()!=null && !oldStu.getName().equals(oldStu.getName())){
    
    
            diffMap.put("id","from "+oldStu.getName()+" to " + newStu.getName());
        }
        return diffMap;
    }
}

We know what properties the Student object has when coding, so we can write it like this. So what if we want to compare the differences of other objects?
There are two problems to face here:

  • Don’t know the specific type of object that needs to be compared
  • Don’t know the specific properties of the comparison object

To solve the above two problems, it is necessary to directly determine the type of the incoming object and the properties and methods it contains after the parameters are passed in. Reflection can help us solve it.
The Java reflection mechanism mainly provides the following functions.

  • Determine the class to which any object belongs at runtime;
  • Construct objects of any class at runtime;
  • Modify the member variables of any object at runtime;
  • Call any object's method at runtime.
    public static Map<String,String> diffObject(Object oldObj,Object newObj) throws IllegalAccessException {
    
    
        Map<String,String> diffMap=new HashMap<>();
        Class oldStuClass = oldObj.getClass();
        Class newStuClass = newObj.getClass();
        //判断是否是同一类
        if(!oldStuClass.equals(newStuClass)){
    
    
            return diffMap;
        }
        //获取对象的所有属性
        Field[] declaredFields = oldStuClass.getDeclaredFields();
        //对属性逐一比对
        for (Field field : declaredFields) {
    
    
            field.setAccessible(true);
            Object oldValue = field.get(oldObj);
            Object newValue = field.get(newObj);
            if(oldValue!=null && !oldValue.equals(newValue)){
    
    
                diffMap.put(field.getName(),"from "+oldValue+" to " + newValue);
            }
        }
        return diffMap;
    }

    public static void main(String[] args) throws IllegalAccessException {
    
    
        Student oldStu = new Student(1, "huazige");
        Student newStu = new Student(2, "mybatis");
        Map<String, String> stringStringMap = diffObject(oldStu, newStu);
        System.out.println(JSON.toJSONString(stringStringMap));

        Car oldCar = new Car("比亚迪", "电车");
        Car newCar = new Car("红旗", "油车");
        Map<String, String> carMap = diffObject(oldCar, newCar);
        System.out.println(JSON.toJSONString(carMap));
    }

operation result:

{
    
    "name":"from huazige to mybatis","id":"from 1 to 2"}
{
    
    "name":"from 比亚迪 to 红旗","type":"from 电车 to 油车"}

The diffObject method completes the comparison of object attributes of two different classes, student and Car, and reduces the coupling of parameters to make the function more versatile.

3.2type interface and its subclasses

The Type interface only defines one method.

   default String getTypeName() {
    
    
        return toString();
    }

Type interface and subclass class diagram:
Insert image description here

  • Class class: It represents the classes and interfaces in the running Java program. Enumeration types (belonging to classes) and annotations (belonging to interfaces) are also subclasses of the Class class.
  • WildcardType interface: It represents wildcard expressions. For example, "?", "?extends Number" and "?super Integer" are all wildcard expressions.
  • TypeVariable interface: It is the parent interface of type variables. For example, "K" and "V" in "Map<K,V>" are type variables.
  • ParameterizedType interface: It represents parameterized types. For example, "Collection <String>" is a parameterized type.
  • GenericArrayType interface: It represents a list containing ParameterizedType or TypeVariable elements.

4.Annotation

Java annotations, also known as Java annotations, are new features introduced in JDK5, annotations (also known as metadata).
Java annotations provide a safe annotation-like mechanism to associate any information or metadata with program elements (classes, methods, member variables, etc.).
Java annotations are some meta-information attached to the code, which are used by some tools to parse and use during compilation and runtime, and serve the function of explanation and configuration.

4.1 Java annotation application

  1. Generating documents is the most common and the earliest annotation provided by Java;
  2. Perform format check at compile time, for example, if @Override is placed before the method, if your method does not cover the super class method, it can be checked at compile time;
  3. Track code dependencies and implement alternative configuration file functions. The more common one is annotation-based configuration starting from spring 2.5, which serves to reduce configuration;
  4. In reflection's Class, Method, Field and other functions, there are many interfaces related to Annotation, and Annotation can be parsed and used in reflection.

4.2 Java annotation classification

  1. Java's own standard annotations
    include @Override, @Deprecated, @SuppressWarnings, and @FunctionalInterface. The compiler will check after using these annotations.
  • @Override: Its function is to mark methods that override methods in the super class. If the marked method does not actually override the method in the super class, the compiler will issue an error warning.
  • @Deprecated: Its function is to add annotations to methods that should no longer be used. When programmers use these methods, a prompt message will be displayed at compile time.
  • @SuppressWarnings: Its parameters are:
    deprecation: a warning when an obsolete class or method is used
    unchecked: a warning when an unchecked conversion is performed
    fallthrough: a warning when the switch block leads directly to the next situation without break
    path : Warning when there are non-existent paths in the classpath, source file path, etc.
    serial : Warning when serialVersionUID definition is missing on a serializable class
    finally : Warning when any finally clause does not complete normally
    all : About the above Warning for all situations
  • @FunctionalInterface: Java 8 introduces a new annotation @FunctionalInterface for functional interfaces, which is mainly used for compile-level error checking. With this annotation, when the interface you write does not conform to the functional interface definition, the compiler will report an error
  1. Meta-annotations
    Meta-annotations are annotations used to define annotations, including @Retention, @Target, @Inherited, @Documented, and @Repeatable.
    Meta-annotations are also standard annotations that come with Java, but they are used to modify annotations, which is quite special.
  • @Retention is used to define at which level the annotation is available, in source code (SOURCE), class file (CLASS) or runtime (RUNTIME).
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    
    
    RetentionPolicy value();
}
public enum RetentionPolicy {
    
    
	//此注解类型的信息只会记录在源文件中,编译时将被编译器丢弃,也就是说不会保存在编译好的类信息中
    SOURCE,
    //编译器将注解记录在类文件中,但不会加载到JVM中。如果一个注解声明没指定范围,则系统默认就是CLASS
    CLASS,
    //注解信息会保留在源文件、类文件中,在执行的时也加载到Java的JVM中,因此可以反射性的读取。
    RUNTIME
}
  • @Documented: Keep annotations when generating document information and provide auxiliary explanations for classes.
  • @Target: used to describe the scope of use of annotations (ie: where the described annotations can be used)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    
    
    ElementType[] value();
}
public enum ElementType {
    
    
    /** Class, interface (including annotation interface), enum, or record
     * declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation interface declaration (Formerly known as an annotation type.) */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     * @since 1.8
     */
    TYPE_USE,

    /**
     * Module declaration.
     * 
     * @since 9
     */
    MODULE,

    /**
     * Record component
     *
     * @jls 8.10.3 Record Members
     * @jls 9.7.4 Where Annotations May Appear
     *
     * @since 16
     */
    RECORD_COMPONENT;
}
  • @Inherited: Indicates that subclasses can inherit this annotation from the parent class
  • @Repeatable indicates that the annotation can be used repeatedly.
  1. Custom annotations
    Users can define annotations according to their own needs.

Guess you like

Origin blog.csdn.net/d495435207/article/details/130373825