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:
- 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
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
- "Spring Hands-on Column" Chapter 1: Introduction, I'm going to show you Spring!
- Re-learning Java Design Patterns: Practical Factory Method Pattern "Multiple types of commodities with different interfaces, unified award service construction scenarios"
- Scheme design: Optimize the timeliness of distributed delay tasks based on segmented scanning of library tables and data Redis preheating
- I've been working for two or three years, but I don't understand what the architecture diagrams are all about?
- We have screened 400+ resumes in half a year's recruitment, and tell you how to write easy to be teased!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。