MyBatis-step01

InvocationHandler

InvocationHandler 接口是 Java 动态代理的核心部分,它里面有一个方法 invoke

当使用动态代理创建一个代理对象时,所有对代理对象的方法调用都会被路由到实现了 InvocationHandler 接口的 invoke 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MapperProxy<T> implements InvocationHandler, Serializable {

private static final long serialVersionUID = -6424540398559729838L;
// 此处省略一些,目的是为了结构更清晰 ...
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Object 类里的方法不代理
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
return "你的被代理了!" + sqlSession.get(mapperInterface.getName() + "." + method.getName());
}
}
}

如果创建了一个 MapperProxy 代理对象,那么就会调用 invoke 方法

invoke 方法里,它做了一些判断,对于 Object 类里的方法,不进行代理

Proxy.newProxyInstanse

是 Java 中用于创建动态代理对象的一个静态方法,参数列表如下

1
2
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
throws IllegalArgumentException
  • ClassLoader loader:指定类加载器,通常传入目标对象的类加载器
  • Class<?>[] interfaces :接口数组,代理类会实现这些接口,这些接口决定了代理类可以调用的方法
  • InvocationHandler h : 一个接口,代理对象上的所有方法调用都会委托给它的 invoke 方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
}

}

这个工厂类需要传入一个接口 mapperInterface,这个接口就是要代理的接口

调用 Proxy.newProxyInstance 方法,传入类加载器,要实现的接口,实现了 InvovationHandler 的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
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

MapperProxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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());
}
}

}

MapperProxyFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);
}

}

IUserDao

1
2
3
4
5
6
7
8
public interface IUserDao {

String queryUserName(String uId);

Integer queryUserAge(String uId);

}

测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@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);
}

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

本篇文章是在小傅哥的基础上,添加了自己的理解写下的
小傅哥博客:https://bugstack.cn


MyBatis-step01
http://showyoubug.cn/2024/07/21/MyBatis-step01/
作者
Dong Su
发布于
2024年7月21日
许可协议