我们知道在mybatis中,Mapper接口方法是不能被其他类重写的,而该接口就相当于。
接口:UserMapper.java
@Mapper
package cn.jxufe.web.mybatis;
public interface UserMapper {
public void insertUser(User user);
public User getUser(String name);
}
对应的映射文件:UserMapper.xml
<mapper namespace="cn.jxufe.web.mybatis.UserMapper">
<insert id="insertUser" parameterType="User">
insert into user(name,age) values(#{name},#{age})
</insert>
<select id="getUser" resultType="User" parameterType="java.lang.String">
select * from user where name=#{name}
</select>
</mapper>
其中:UserMapper.xml中每个标签中的id对应UserMapper接口中的方法。
那映射文件时如何根据对应的接口实现持久层中与数据库进行交互的呢?解析如下:
1.MapperRegistry
应用程序启动的时候就会创建这个类的实例,它有一个HashMap类型的属性用于存储每个Mapper接口(key)和相应的MapperProxyFactory(value);
另外有两个重要的方法getMapper()和addMapper(),分别用于获取和注册Mapper接口到这个HashMap中。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if(mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
return mapperProxyFactory.newInstance(sqlSession);//通过Mapper接口的type返回一个相应的mapperProxyFactory的一个实例
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
public <T> void addMapper(Class<T> type) {
if(type.isInterface()) {
if(this.hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
this.knownMappers.put(type, new MapperProxyFactory(type));//将这个Mapper接口“注册”
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type);
parser.parse();
loadCompleted = true;
} finally {
if(!loadCompleted) {
this.knownMappers.remove(type);
}
}
}
}
2.MapperProxyFactory
作用:用于创建mapper代理对象的工厂,而mapper代理对象负责代替mapper接口完成POJO到数据库的映射。
在MapperProxyFactory中的两个重要方法如下,用于创建mapper代理类的一个实例。
protected T newInstance(MapperProxy<T> mapperProxy) {
//用了java的动态代理,获得真正的代理对象
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
3. MapperProxy
通过调用特定的mapper代理对象的invoke()方法,实现到数据库的映射,实际上invoke()中又调用了MapperMethod中的execute方法,execute方法主要是用到sqlSession的insert、update、select、delete等。
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 var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
} else {
MapperMethod mapperMethod = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
}
}
4. MapperMethod
public Object execute(SqlSession sqlSession, Object[] args) {
Object param;
Object result;
if(SqlCommandType.INSERT == this.command.getType()) {
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
} else if(SqlCommandType.UPDATE == this.command.getType()) {
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
} else if(SqlCommandType.DELETE == this.command.getType()) {
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
} else if(SqlCommandType.SELECT == this.command.getType()) {
if(this.method.returnsVoid() && this.method.hasResultHandler()) {
this.executeWithResultHandler(sqlSession, args);
result = null;
} else if(this.method.returnsMany()) {
result = this.executeForMany(sqlSession, args);
} else if(this.method.returnsMap()) {
result = this.executeForMap(sqlSession, args);
} else if(this.method.returnsCursor()) {
result = this.executeForCursor(sqlSession, args);
} else {
param = this.method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(this.command.getName(), param);
}
} else {
if(SqlCommandType.FLUSH != this.command.getType()) {
throw new BindingException("Unknown execution method for: " + this.command.getName());
}
举例:
UserDAO被@Autowired注解,由spring完成bean的自动装配,其中spring会去获取一个MyBatis的mapperProxy代理对象作为这个bean,它是一个真正的对象而不是一个Interface类型,由这个代理人完成到数据库的映射。即持久层由代理人来完成。
public class UserDamoImpl{
@Autowired
UserDAO userDAO;
public void contextLoads() {
User user = new User();
user.setName("user1");
user.setPassword("");
user.setSalt("");
user.setHeadUrl("xxx.png");
userDAO.addUser(user);
}
}