Understanding MyBatis Dynamic Proxy: How Mapper Interfaces Are Implemented
This article explains the core principle of MyBatis by demonstrating how Mapper interfaces are turned into dynamic proxy objects using JDK proxy mechanisms, walks through manual simulation code, and clarifies each step of the proxy creation and method invocation process.
MyBatis relies on dynamic proxy generation to turn Mapper interfaces into concrete objects that can execute SQL statements; this tutorial first shows a typical UserMapper interface and its usage within a Spring service, then questions how an interface method can be called directly.
Verifying MyBatis Uses Dynamic Proxy
By inspecting the code path of session.getMapper(UserMapper.class) , we see it ultimately calls Proxy.newProxyInstance , confirming that JDK dynamic proxy is used.
Manual Simulation of MyBatis Dynamic Proxy
A custom MySession class is introduced with a getMapper method that creates a proxy instance using Proxy.newProxyInstance with three required arguments: a class loader, an array of interfaces, and an InvocationHandler implementation.
public class MySession {
public static Object getMapper(Class clazz) {
Class[] clazzs = new Class[]{clazz};
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Object object = Proxy.newProxyInstance(MySession.class.getClassLoader(), clazzs, new MyInvocationHandler());
return object;
}
}The three arguments are explained:
Class loader – the proxy and the calling class must share the same loader.
Class array – the proxy must implement the target interface (e.g., UserMapper ).
InvocationHandler – contains the enhancement logic that runs when a method is invoked.
The MyInvocationHandler parses the @Select annotation to obtain the SQL, then simulates execution by printing the statement.
public class MyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Select annotation = method.getAnnotation(Select.class);
String sql = annotation.value()[0];
System.out.println(sql + " executing...");
return null;
}
}A simple Main class demonstrates the whole flow: obtaining the proxy via MySession.getMapper and calling queryAll() , which results in the SQL being printed.
public class Main {
public static void main(String[] args) {
UserMapper userMapper = (UserMapper) MySession.getMapper(UserMapper.class);
userMapper.queryAll();
}
}
// Output: select * from user executing...Summary
The essential MyBatis principles are:
Developers define Mapper interfaces and use them directly.
MyBatis generates a dynamic proxy that implements the interface, enriches each method by extracting the associated SQL and executing it (abstracting JDBC details).
This mechanism makes database operations as simple as invoking ordinary Java methods.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.