头图

Mybatis Hands-on Column Chapter 2: Creating a Simple Mapper Proxy Factory

小傅哥
中文

Author: Xiao Fu Ge Blog: https://bugstack.cn

Precipitate, share, grow, and let yourself and others gain something! 😄

I. Introduction

着急和快,是最大的障碍!

Slow down, slow down, only by slowing down can you see more complete information and learn more solid techniques. While those short stories that satisfy you are sometimes more eye-catching, they are also easy to bias people in technical learning, always thinking that the sooner the better.

In the process of Xiao Fu's writing technical articles, he also encountered such a situation, and many readers prefer to read it; the beginning of a series of content, the sharing of a growth story, and the secret book of one day becoming an architecture. Of course, I can understand this kind of liking. After all, most people like to take shortcuts, just like buying sports and fitness equipment in winter and not unpacking them after summer.

Alright, let's get down to business now!

2. Goals

By the time you can read this article, I believe you are already a skilled worker using the Mybatis ORM framework tool, so do you know how this ORM framework shields us from the details of database operations?

For example, when we use JDBC, we need to manually establish a database link, encode SQL statements, perform database operations, and encapsulate the returned results by ourselves. But after using the ORM framework, you only need to perform database operations on the defined DAO interface through simple configuration.

Then in this chapter, we will solve the first problem of associating the object interface and the mapping class in the ORM framework, and use the proxy class for the DAO interface to wrap the mapping operation.

3. Design

Usually, if you can find the common content of what everyone is working on and have a unified process, then it can be condensed and refined, made into a common component or service, and used by everyone, reducing repeated human input.

Referring to the way we first used JDBC, connection, query, encapsulation, and return are actually a fixed process, so this process can be refined and encapsulated and complemented by the functions you need.

When we design an ORM framework, we must first consider how to connect the user-defined database operation interface, the SQL statement configured by xml, and the database. In fact, the most suitable operation is to use the proxy method, because the proxy can encapsulate a complex process as the implementation class of the interface object, as shown in Figure 2-1:

图 2-1 代理类设计

  • First, provide a proxy implementation class of the MapperProxy , which wraps the operation of the database through the proxy class. At present, we will first provide a simple wrapper in this chapter to simulate the call to the database.
  • Afterwards, for the MapperProxy proxy class, provide the factory instantiation operation MapperProxyFactory#newInstance to generate a proxy class for each IDAO interface. This is actually a simple factory pattern

Next, we will implement a simple mapper proxy operation according to this design, and the coding process is relatively simple. If you are not familiar with agent knowledge, you can add it first.

4. Realization

1. Engineering structure

 mybatis-step-01
└── src
    ├── main
    │   └── java
    │       └── cn.bugstack.mybatis.binding
    │           ├── MapperProxy.java
    │           └── MapperProxyFactory.java
    └── test
        └── java
            └── cn.bugstack.mybatis.test.dao
                ├── dao
                │   └── IUserDao.java
                └── ApiTest.java

Project source code: https://t.zsxq.com/bmqNFQ7

Mybatis mapper proxy class relationship, as shown in Figure 2-2

如图 2-2 代理类关系图

  • At present, the proxy operation of the Mybatis framework only implements the most core functions, which is equivalent to a bare-ass doll, and no clothes have been added yet. However, such a gradual implementation allows everyone to understand the core content first, and we will continue to improve it in the future.

    • MapperProxy is responsible for implementing the invoke method of the InvocationHandler interface, and ultimately all actual calls will call the logic wrapped by this method.
    • MapperProxyFactory is a wrapper for MapperProxy and provides external operations for instantiating objects. When we start to register proxies for each interface mapper that operates the database later, we need to use this factory class.

2. Mapper proxy class

See the source code for details : cn.bugstack.mybatis.binding.MapperProxy

 public class MapperProxy<T> implements InvocationHandler, Serializable {

    private static final long serialVersionUID = -6424540398559729838L;

    private Map<String, String> sqlSession;
    private final Class<T> mapperInterface;

    public MapperProxy(Map<String, String> sqlSession, Class<T> mapperInterface) {
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        } else {
            return "你的被代理了!" + sqlSession.get(mapperInterface.getName() + "." + method.getName());
        }
    }

}
  • By implementing the InvocationHandler#invoke proxy class interface and encapsulating the operation logic, the external interface provides database operation objects.
  • At present, we simply encapsulate a Map object of sqlSession here. You can imagine that all database statement operations are used as a logical method through 接口名称+方法名称作为key . Then in the reflection call, the corresponding operation can be obtained and executed directly and the result can be returned. Of course, this is only the core simplified process. After continuous addition of content, you will see the operation of the database.
  • In addition, it should be noted here that if the methods such as toString and hashCode provided by Object do not need to be executed by proxy, add Object.class.equals(method.getDeclaringClass()) judge.

3. Proxy factory

See the source code : cn.bugstack.mybatis.binding.MapperProxyFactory

 public class MapperProxyFactory<T> {

    private final Class<T> mapperInterface;

    public MapperProxyFactory(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    public T newInstance(Map<String, String> sqlSession) {
        final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface);
        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
    }

}
  • The factory operation is equivalent to encapsulating the creation of the proxy. If you do not do this layer of encapsulation, then each operation to create a proxy class needs to be processed by yourself Proxy.newProxyInstance , then such an operation method appears More troublesome.
  • In addition, if you are not too familiar with proxies, you can focus on the content of JDK Proxy by doing a few cases to supplement the content of this section.

5. Test

1. Prepare in advance

cn.bugstack.mybatis.test.dao.IUserDao

 public interface IUserDao {

    String queryUserName(String uId);

    Integer queryUserAge(String uId);

}
  • First provide a DAO interface and define 2 interface methods.

2. Test case

 @Test
public void test_MapperProxyFactory() {
    MapperProxyFactory<IUserDao> factory = new MapperProxyFactory<>(IUserDao.class);
    Map<String, String> sqlSession = new HashMap<>();

    sqlSession.put("cn.bugstack.mybatis.test.dao.IUserDao.queryUserName", "模拟执行 Mapper.xml 中 SQL 语句的操作:查询用户姓名");
    sqlSession.put("cn.bugstack.mybatis.test.dao.IUserDao.queryUserAge", "模拟执行 Mapper.xml 中 SQL 语句的操作:查询用户年龄");
    IUserDao userDao = factory.newInstance(sqlSession);

    String res = userDao.queryUserName("10001");
    logger.info("测试结果:{}", res);
}
  • Create a MapperProxyFactory factory in a single test, and manually assign a value to the sqlSession Map. The assignment here is equivalent to simulating the operation in the database.
  • Next, pass the assignment information to the proxy object instantiation operation, so that we can get the value from the sqlSession when we call the specific DAO method.

Test Results

 17:03:41.817 [main] INFO  cn.bugstack.mybatis.test.ApiTest - 测试结果:你的被代理了!模拟执行 Mapper.xml 中 SQL 语句的操作:查询用户姓名

Process finished with exit code 0
  • As can be seen from the test results, our interface has been implemented by the proxy class, and we can encapsulate our own operations in the proxy class. Then in our subsequent database operations, we can extend this part of the content.

6. Summary

  • In this chapter, we initially link the database DAO operation interface and mapper in the Mybatis framework through proxy classes, which is also a very core part of the ORM framework. With the content of this piece, you can extend your own logic in the proxy class.
  • In the framework implementation, the simple factory pattern is introduced to wrap the proxy class, and the creation details are shielded. These are also the design patterns that everyone needs to pay attention to in the learning process.
  • At present, the content is relatively simple and can be practiced manually. As our content increases, more and more packages and classes will be introduced to improve the ORM framework function.

Seven, series recommendation

阅读 1k

CodeGuide_程序员编码指南
公众号:bugstack虫洞栈,回复:设计模式,可以下载《重学Java设计模式》PDF,全网下载量17万+ | 这是一...

CodeGuide | 程序员编码指南 - 原创文章、案例源码、资料书籍、简历模版等下载。

4.4k 声望
28.3k 粉丝
0 条评论

CodeGuide | 程序员编码指南 - 原创文章、案例源码、资料书籍、简历模版等下载。

4.4k 声望
28.3k 粉丝
文章目录
宣传栏