Mybatis interface proxy method Dao

Dao interface proxy

Case project skeleton

What is agent development?

Mapper interface development needs to follow the following specifications

Write StudentMapper interface

Case demonstration

Source code analysis

Analyze how dynamic proxy objects are generated?

How is the analysis method performed?

Dao interface proxy

Case project skeleton

Continue to use the previous Mybatis traditional implementation Dao case

What is agent development?

To implement Dao layer in the traditional way, we should write both interfaces and implementation classes. The mybatis framework can help us omit the steps of writing Dao layer interface implementation classes. Programmers only need to write the interface. The mybatis framework itself can create the dynamic proxy object of the interface according to the definition of the interface.

The agent development mode of Mybatis is adopted to realize the development of DAO layer, which is the mainstream of entering the enterprise later.

Mapper interface development (equivalent to Dao interface) method only requires programmers to write mapper interface. Mybatis framework creates the dynamic proxy object of the interface according to the interface definition. The method body of the proxy object is the same as the implementation class method of Dao interface above.

Mapper interface development needs to follow the following specifications

(1) Mapper. The namespace in the XML file is the same as the fully qualified name (full class name) of the mapper interface.

(2) Mapper interface method name and mapper The id of each statement defined in the XML is the same.

(3) Input parameter type of mapper interface method and mapper The parameterType of each sql defined in XML is of the same type.

(4) Mapper interface method output parameter type and mapper The resultType of each sql defined in XML is the same.

(1) Mapper. The namespace in the XML file is the same as the fully qualified name (full class name) of the mapper interface.

StudentMapper. The namespace attribute value of the mapper tag in the XML Mapping configuration file is the full class name of the studentmapper interface.

(2) Mapper interface method name and mapper The id of each statement defined in the XML is the same.

In StudentMapper If the id attribute value in the XML is selectAll, the abstract method name in the StudentMapper interface should be consistent with it.

 

(3) Input parameter type of mapper interface method and mapper The parameterType of each sql defined in XML is of the same type.

In the StudentMapper interface, the parameter type of the abstract method is Integer, and the value of parameterType in its corresponding mapping configuration file is also Integer.

(Note: This was originally java.lang.Integer, but writing int framework in Mybatis will automatically convert it to Integer)

 

(4) Mapper interface method output parameter type and mapper The resultType of each sql defined in XML is the same.

  

Write StudentMapper interface

According to the above description, in general, it is shown in the following figure:

Case demonstration

Let's use the code of the previous case to modify it.

(1) Delete the interface implementation class of mapper layer

(2) Modify mapping profile

All codes are as follows:

(1) The Student class of the bean layer remains unchanged

(2) The StudentController class of the controller layer remains unchanged

(3) The mapper layer deletes the impl package (which contains its implementation class), and the StudentMapper interface remains unchanged

(4) The StudentServiceImpl of the service layer is the main modified object!!!

package com.itheima.service.impl;

import com.itheima.bean.Student;
import com.itheima.mapper.StudentMapper;
import com.itheima.service.StudentService;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/*
    Business layer implementation class
 */
public class StudentServiceImpl implements StudentService {

    @Override
    public List<Student> selectAll() {
        InputStream is = null;
        SqlSession sqlSession = null;
        List<Student> list = null;
        try {
            // 1. Load core configuration file
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            // 2. Get SqlSessionFactory factory object
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            // 3. Obtain SqlSession object through factory object
            sqlSession = sqlSessionFactory.openSession(true);

            // ***4. Get the implementation class object of StudentMapper interface (generated dynamically through Mybatis)
            // getMapper() needs a class object of interface type
            // Equivalent to: StudentMapper mapper = new StudentMapperImpl();
            // It's just that MyBatis obtains the implementation class object for us in a dynamic form
            StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

            // 5. Call the method by implementing the class object and accept the result
            list = mapper.selectAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 6. Release resources
            if(sqlSession != null) {
                sqlSession.close();
            }
            if(is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        // 7. Return results
        return list;
    }

    @Override
    public Student selectById(Integer id) {
        InputStream is = null;
        SqlSession sqlSession = null;
        Student stu = null;
        try {
            // 1. Load core configuration file
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            // 2. Get SqlSessionFactory factory object
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            // 3. Obtain SqlSession object through factory object
            sqlSession = sqlSessionFactory.openSession(true);

            // ***4. Get the implementation class object of StudentMapper interface (generated dynamically through Mybatis)
            StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

            // 5. Call the method by implementing the class object and accept the result
            stu = mapper.selectById(id);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 6. Release resources
            if(sqlSession != null) {
                sqlSession.close();
            }
            if(is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        // 7. Return results
        return stu;
    }

    @Override
    public Integer insert(Student stu) {
        InputStream is = null;
        SqlSession sqlSession = null;
        Integer result = null;
        try {
            // 1. Load core configuration file
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            // 2. Get SqlSessionFactory factory object
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            // 3. Obtain SqlSession object through factory object
            sqlSession = sqlSessionFactory.openSession(true);

            // ***4. Get the implementation class object of StudentMapper interface (generated dynamically through Mybatis)
            StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

            // 5. Call the method by implementing the class object and accept the result
            result = mapper.insert(stu);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 6. Release resources
            if(sqlSession != null) {
                sqlSession.close();
            }
            if(is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        // 7. Return results
        return result;
    }

    @Override
    public Integer update(Student stu) {
        InputStream is = null;
        SqlSession sqlSession = null;
        Integer result = null;
        try {
            // 1. Load core configuration file
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            // 2. Get SqlSessionFactory factory object
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            // 3. Obtain SqlSession object through factory object
            sqlSession = sqlSessionFactory.openSession(true);

            // ***4. Get the implementation class object of StudentMapper interface (generated dynamically through Mybatis)
            StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

            // 5. Call the method through the implementation class object to accept the result
            result = mapper.update(stu);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 6. Release resources
            if(sqlSession != null) {
                sqlSession.close();
            }
            if(is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        // 7. Return results
        return result;
    }

    @Override
    public Integer delete(Integer id) {
        InputStream is = null;
        SqlSession sqlSession = null;
        Integer result = null;
        try {
            // 1. Load core configuration file
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            // 2. Get SqlSessionFactory factory object
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            // 3. Obtain SqlSession object through factory object
            sqlSession = sqlSessionFactory.openSession(true);

            // ***4. Get the implementation class object of StudentMapper interface (generated dynamically through Mybatis)
            StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

            // 5. Call the method by implementing the class object and accept the result
            result = mapper.delete(id);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 6. Release resources
            if(sqlSession != null) {
                sqlSession.close();
            }
            if(is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        // 7. Return results
        return result;
    }
}

(5) Core configuration file mybatisconfig XML invariant

(6) Mapping configuration file studentmapper XML needs to be changed

The namespace attribute under the mapper tag inside is changed to the full class name

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
    mapper: Core root label
    namespace Attributes: namespaces
-->

<mapper namespace="com.itheima.mapper.StudentMapper">
    <!--
    select: Label of query function
    id Attribute: unique identification
    resultType Property: Specifies the result mapping object type
    parameterType Property: Specifies the type of parameter mapping object
    -->
    <select id="selectAll" resultType="student">
        SELECT * FROM student
    </select>
    
    <select id="selectById" resultType="student" parameterType="int">
        SELECT * FROM student WHERE id = #{id}
    </select>

    <!--
        Returns a int Number of rows of type! Therefore, it can be omitted resultType
        But, SQL Parameters of the statement id,name,age It comes from students, so there should be parameterType
    -->
    <insert id="insert" parameterType="student">
        INSERT INTO student VALUES (#{id},#{name},#{age})
    </insert>

    <update id="update" parameterType="student">
        UPDATE student SET name = #{name},age = #{age} WHERE id = #{id}
    </update>

    <!-- java.lang.Integer -> int-->
    <delete id="delete" parameterType="int">
        DELETE FROM student WHERE id = #{id}
    </delete>
</mapper>




Source code analysis

Analyze how dynamic proxy objects are generated?

Through the dynamic agent development mode, we only write an interface, not an implementation class. We finally get org. Org through the getMapper() method apache. ibatis. binding. Mapperproxy proxy object and then perform functions. MyBatis uses JDK's dynamic proxy technology to help us generate proxy implementation class objects. Thus, relevant persistence operations can be performed.

Get the implementation class object of StudentMapper interface (generated dynamically through Mybatis), and the bottom layer of getMapper() is as follows:

getMapper() is from SqlSeesion

<T> T getMapper(Class<T> var1);

The implementation class of sqlsession is DefaultSqlSession, in which the getMapper() method is rewritten

Note: the type inside is the class object of the StudentMapper interface, and this is the SqlSession object

Then the getMapper method of configuration is called

public <T> T getMapper(Class<T> type) {
    return this.configuration.getMapper(type, this);
}

The getMapper() method in the configuration object calls the getMapper method of mapperRegistry

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return this.mapperRegistry.getMapper(type, sqlSession);
}

The mapping proxy factory object mapperProxyFactory is obtained, and the factory calls newInstance again

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
    if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    } else {
        try {
            return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
        }
    }
}

The mapping object mapperproxy is created, and the newInstance method is called to transfer the mapping proxy object mapperproxy

public T newInstance(SqlSession sqlSession) {
    MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
    return this.newInstance(mapperProxy);
}

Finally, proxy is called Newproxyinstance (dynamic proxy provided by JDK)

The three parameters are: class loader, class type object array and proxy rule

protected T newInstance(MapperProxy<T> mapperProxy) {
    return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}

How is the analysis method performed?

When the dynamic proxy implementation class object executes the method, it finally calls mappermethod Execute () method. In this method, the switch statement is used to judge the operations of adding, modifying, deleting and querying according to the operation type. The last step returns to the most original SqlSession mode of MyBatis to execute adding, deleting, modifying and querying.

To execute the method, the dynamic agent first needs to use the invoke() method to get the mapperMethod object and call the execute method

Judge the type of method through switch! Finally, use the insert() method of SqlSession object!

Keywords: Java Mybatis Spring

Added by cpharry on Sat, 26 Feb 2022 20:45:22 +0200