写在前面 - 回顾一下MyBatis中的配置
db entity:
public class TestUser {
private String userName;
private LocalDateTime createDt;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public LocalDateTime getCreateDt() {
return createDt;
}
public void setCreateDt(LocalDateTime createDt) {
this.createDt = createDt;
}
}
mapper接口:
public interface TestUserMapper {
public TestUser getTestUserById(Long id);
}
mapper xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="server.db.entity.TestUserMapper">
<select id="getTestUserById" resultType="testUser" parameterType="Long">
SELECT top 1 * from TEST_USER where id = #{id}
</select>
</mapper>
db-config.xml
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="configLocation" value="mybatis-config.xml"/>
</bean>
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="server.db.entity" />
<property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate" />
</bean>
使用:
TestUserMapper userMapper = (TestUserMapper)context.getBean(TestUserMapper.class);
TestUser user = userMapper.getTestUserById(Long.valueOf(1));
System.out.println(user);
问题来了,仅仅定义了mapper接口,并没有实现类,怎么就能调用它的方法了呢?
这是因为在运行时采用动态代理技术生成了代理类,调用的是代理类的实现方法。来看一下这个代理类是怎样生成的。
1. 创建mapper代理类
Spring容器初始化testUserMapper,发现它的root bean是MapperFactoryBean,这是一个工厂bean。
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T>
当后面getMapper时,spring容器查到这是一个工厂bean,就会调用MapperFactoryBean的如下getObject方法来创建真正的bean。
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
里面会采用动态代理来生成相应的代理类。
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
MapperProxyFactory:
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
2. 生成的mapper代理类
public final class $Proxy44 extends Proxy implements TestUserMapper {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy44(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final TestUser getTestUserById(Long var1) throws {
try {
return (TestUser)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.server.autoVerification.db.entity.TestUserMapper").getMethod("getTestUserById", Class.forName("java.lang.Long"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
网友评论