Dynamic proxy functionality: The target method is enhanced through interceptor method callbacks.
The implication is to enhance the target target method. The above statement is true, but don’t take it as truth, but dynamic agents have the power to beat the flow of hegemony, not even the target of science fiction mode.
Note: This article assumes that the reader understands the principle of dynamic proxy. If you do not understand the meaning of target, you are advised to understand dynamic proxy first.
1. Customized JDK dynamic proxy to achieve automatic Mapper
Start by defining a POJO.
public class User {
private Integer id;
private String name;
private int age;
public User(Integer id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
// getter setter
}
Copy the code
Define another interface, usermapper.java.
public interface UserMapper {
public User getUserById(Integer id);
}
Copy the code
Next, let’s look at how to use the dynamic proxy to whip out the flow to instantiate the interface and call the interface methods to return data.
Create a custom InvocationHandler.
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class MapperProxy implements InvocationHandler { @SuppressWarnings("unchecked") public <T> T newInstance(Class<T> clz) { return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[] { clz }, this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass())) { try { // Methods such as hashCode(), toString(), equals(), etc. target to the current object. This return method.invoke(this, args); } catch (Throwable t) {}} return new User((Integer) args[0], "Tom ", 18); }}Copy the code
In the code above, target is referred to as this when the method in Object.java is executed. Target has become a puppet, symbol, placeholder. At the time of the flagellate intercept, there is no target.
Write a test code:
public static void main(String[] args) {
MapperProxy proxy = new MapperProxy();
UserMapper mapper = proxy.newInstance(UserMapper.class);
User user = mapper.getUserById(1001);
System.out.println("ID:" + user.getId());
System.out.println("Name:" + user.getName());
System.out.println("Age:" + user.getAge());
System.out.println(mapper.toString());
}
Copy the code
The output:
ID:1001
Name:zhangsan
Age:18
x.y.MapperProxy@6bc7c054
Copy the code
This is the basic implementation principle of Mybatis automatic Mapper.
Some readers may wonder: How do you write code like a beginner? There is no structure and no aesthetic.
It must be said that an experienced master who can write programs like beginners must be the master of the master. In this way, beginners can feel friendly, comfortable and in line with their own Style. They or they can feel that the code written by Daniel is no more than this, and they even write better than those written by Daniel. From then on, they are full of confidence and enthusiasm, believing that the gap between them and Daniel is only three minutes.
2. Mybatis automatic Mapper source analysis
Start by writing a test class:
public static void main(String[] args) { SqlSession sqlSession = MybatisSqlSessionFactory.openSession(); try { StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class); List<Student> students = studentMapper.findAllStudents(); for (Student student : students) { System.out.println(student); } } finally { sqlSession.close(); }}Copy the code
A Mapper looks like this:
public interface StudentMapper {
List<Student> findAllStudents();
Student findStudentById(Integer id);
void insertStudent(Student student);
}
Copy the code
Org. Apache. Ibatis. Binding. MapperProxy. Part of Java source code.
public class MapperProxy<T> implements InvocationHandler, Serializable { private static final long serialVersionUID = -6424540398559729838L; private final SqlSession sqlSession; private final Class<T> mapperInterface; private final Map<Method, MapperMethod> methodCache; public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) { this.sqlSession = sqlSession; this.mapperInterface = mapperInterface; this.methodCache = methodCache; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass())) { try { return method.invoke(this, args); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); }} final MapperMethod MapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); } / /...Copy the code
Org. Apache. Ibatis. Binding. MapperProxyFactory. Part of Java source code.
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
Copy the code
This is Mybatis using dynamic proxy to whip out the flow.
3. Can methods in Mapper overLoad? (important)
Something like the following:
public User getUserById(Integer id);
public User getUserById(Integer id, String name);
Copy the code
Answer: No.
Mybatis uses package+Mapper+method full name as key to find unique SQL to execute in XML. Similar: key = X.Y.U serMapper getUserById, so, when overloaded methods will lead to conflict. For Mapper interfaces, Mybatis forbids method overLoad.
Note: learning, is the first study of the source code, understand the principle. When writing a blog post, explain the principle first, then read the source code. The order is reversed, so I hope the reader doesn’t get confused and think I’m too powerful to know.