Blog: bugstack.cn

Precipitation, share, grow, let yourself and others can gain something! 😄

One, foreword

Hurry and fast, is the biggest obstacle!

Slow down, slow down, only slow down, you can see more complete information, can learn more solid technology. And those short content that satisfy you fast, although sometimes more eye-catching, but also easy to take people away from the technical learning, always think the faster the better.

In the process of small Fu Ge writing technical articles, will also encounter such a situation, many readers prefer to see; The beginning of a series of content, the sharing of a growing story, a day to become the architecture of the secret. Of course, I can understand this kind of love, after all, most people like to take shortcuts, just like the sports equipment they bought in winter, but they haven’t opened it in summer.

All right, now let’s get down to business!

Second, the target

By the time you are able to read this article, you will be a skilled user of the Mybatis ORM framework tool. Do you know how the ORM framework hides the details of our database operation?

For example, when we use JDBC, we need to manually establish database links, encode SQL statements, perform database operations, and encapsulate returned results ourselves. However, with the ORM framework, only a simple configuration is required to define the DAO interface for database operations.

In this chapter, we will solve the problem of ORM framework’s first associated object interface and mapping class, and use the DAO interface as a proxy class to wrap the mapping operation.

Three, the design

Generally, if we can find the common content of what we are doing and have a unified process, it can be condensed and refined to make a common component or service for all to use and reduce repeated human input.

And the way we started using JDBC, from connection, query, encapsulation, return, is actually a fixed process, so this process can be refined and encapsulated and complete the functionality we need.

When designing an ORM framework, we should first consider how to connect the user defined database operation interface, THE SQL statement of XML configuration and the database. In fact, the most suitable operation is to use proxy for processing, because proxy can encapsulate a complex process into the implementation class of the interface object, as shown in Figure 2-1:

  • You first provide a proxy implementation class for the mapperMapperProxyFor now in this section we will first provide a simple wrapper to simulate the call to the database.
  • After theMapperProxyProxy classes that provide factory instantiation operations MapperProxyFactory#newInstance that generate proxy classes for each IDAO interface.This is actually using a simple factory pattern

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

Four, implementation,

1. Engineering structure

mybatis-step-01└ ─ ─ the SRC ├ ─ ─ the main │ └ ─ ─ Java │ └ ─ ─ cn. Bugstack. Mybatis. Binding │ ├ ─ ─ MapperProxy. Java │ └ ─ ─ MapperProxyFactory. Java └ ─ ─ The test └ ─ ─ Java └ ─ ─ cn. Bugstack. Mybatis. Test. The dao ├ ─ ─ dao │ └ ─ ─ IUserDao. Java └ ─ ─ ApiTest. JavaCopy the code

Project source: t.zsxq.com/bmqNFQ7

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

  • At present, the Mybatis framework agent operation is only the most core functions, quite like a naked doll, without adding clothes. However, such gradual implementation can let you understand the core content of the first, we will continue to improve.
    • MapperProxy is responsible for implementing the Invoke method of the InvocationHandler interface, and eventually all actual calls are made to the logic wrapped by this method.
    • MapperProxyFactory is a wrapper of MapperProxy and provides operations for instantiating objects. We’ll need to use this factory class later when we start registering agents for each interface mapper that operates on the database.

2. Mapper proxy classes

Source see: 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 "Yours is deputized!" + sqlSession.get(mapperInterface.getName() + "."+ method.getName()); }}}Copy the code
  • By implementing the InvocationHandler#invoke proxy class interface, encapsulating the operation logic, the external interface provides the database operation object.
  • So far we have just a simple Map object that encapsulates a sqlSession. You can imagine that all database operations are performed byInterface name + method name as keyOperations are used in a logical manner. In a reflection call, the corresponding operation is executed directly and the result is returned.Of course, this is just the core of the simplification process, and as you continue to add content, you will see the operation on the database
  • The toString, hashCode, and other methods provided by Object do not need to be executed by the agentObject.class.equals(method.getDeclaringClass())Judgment.

3. Agent factory

Source see: 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(), newClass[]{mapperInterface}, mapperProxy); }}Copy the code
  • The factory operation encapsulates the creation of the proxy. Without this encapsulation, each operation that creates the proxy class needs to be used by itselfProxy.newProxyInstanceProcessing, then such a way of operation is more troublesome.
  • In addition, if you are not familiar with proxies, you can focus on the JDK Proxy content to do a few examples to supplement this section.

Five, the test

1. Prepare

cn.bugstack.mybatis.test.dao.IUserDao

public interface IUserDao {

    String queryUserName(String uId);

    Integer queryUserAge(String uId);

}
Copy the code
  • Start by providing a DAO interface and defining two interface methods.

2. Test cases

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

    sqlSession.put("cn.bugstack.mybatis.test.dao.IUserDao.queryUserName"."Simulating the execution of an SQL statement in mapper.xml: Query user name");
    sqlSession.put("cn.bugstack.mybatis.test.dao.IUserDao.queryUserAge"."Simulating the execution of an SQL statement in mapper. XML: Query user age");
    IUserDao userDao = factory.newInstance(sqlSession);

    String res = userDao.queryUserName("10001");
    logger.info("Test result: {}", res);
}
Copy the code
  • Create a MapperProxyFactory factory in a single test and manually assign values to the sqlSession Map, which is equivalent to simulating operations in the database.
  • The assignment information is then passed to the proxy object instantiation operation so that it can be evaluated from the sqlSession when we call the specific DAO method.

The test results

17:03:41.817[the main] INFO cn. Bugstack. Mybatis. Test. The ApiTest - test results: you have been agent! Example Query user names. Process finished with exit code0
Copy the code
  • As you can see from the test results, our interface has been implemented by the proxy class, and we can encapsulate our own operations in the proxy class. This section can be extended in the database operations we implement later.

Six, summarized

  • In this chapter, we preliminarily linked the database DAO operation interface and mapper in Mybatis framework by proxy class, which is also a very core part of ORM framework. With this content, you can extend your own logic in the proxy class.
  • The introduction of a simple factory pattern wrapper agent class in the framework implementation, shielding the creation details, are also design pattern points that you need to pay attention to during the learning process.
  • At present, the content is relatively simple, you can manually operate the exercise, as we increase the content, more and more packages and classes will be introduced to improve the ORM framework functionality.

Seven, series recommendation

  • “Spring masturbation column” chapter 1: Introduction, I will take you to the Spring!
  • Relearning Java design mode: Actual factory method mode “Different interfaces of various types of goods, unified prize awarding service setting scene”
  • Scheme design: Based on the segmented scanning of library table and Redis preheating of data, the touch timeliness of distributed delay task was optimized
  • Have you been working for two or three years and have no idea what the architecture diagram is?
  • Half a year recruitment screening 400+ resume, tell you how to write easy to be flirted!