用mybatis的时候有一个问题困扰着我就是mybatis的mapper都是接口,没有实现类为什么可以直接调用xml中的sql语句进行实现?带着疑问我去看mybatis源码:
以在spring中整合mybatis为例:首先在web容易启动的时候,加载在spring中配置的SqlSessionFactoryBean和MapperScannerConfigurer。
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:com/stark/app/mappers/**/*Mapper.xml" />
</bean>
<!-- 扫描相关的Mapper接口 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com/stark/app/mappers" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>
SqlSessionFactoryBean会扫描所有的xml文件,解析这些xml文件,封装到Configuration中。在Configuration这个类中有一个属性MapperRegistry mapperRegistry = new MapperRegistry(this);在解析namespace的时候会调用 configuration.addMapper()方法。
private void bindMapperForNamespace() {
String namespace = builderAssistant.getCurrentNamespace();
if (namespace != null) {
Class<?> boundType = null;
try {
boundType = Resources.classForName(namespace);
} catch (ClassNotFoundException e) {
//ignore, bound type is not required
}
if (boundType != null) {
if (!configuration.hasMapper(boundType)) {
// Spring may not know the real resource name so we set a flag
// to prevent loading again this resource from the mapper interface
// look at MapperAnnotationBuilder#loadXmlResource
configuration.addLoadedResource("namespace:" + namespace);
configuration.addMapper(boundType);
}
}
}
}
//调用configuration.addMapper(boundType)就转为调用下面的方法
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
//放到一个map集合中该集合是:
//public class MapperRegistry {
//private Configuration config;
// private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new //HashMap<Class<?>, MapperProxyFactory<?>>();
knownMappers.put(type, new MapperProxyFactory<T>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
看上面的分析现在也就是 MapperProxyFactory<?>> knownMappers, MapperProxyFactory<?>> 是什么东西?看源码:
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return methodCache;
}
//动态代理生成MapperProxy代理类。
@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);
}
}
//然后看MapperProxy
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;
}
//动态代理实现方法
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);
}
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
}
通过以上源码我们明白了:是在web容易启动的时候,为每一个mapper生成一个动态代理去拦截,然后调用MapperProxy的invoke方法去执行。
分享到:
相关推荐
源码中可以看到 MapperProxy 和 MapperMethod,它们实现了接口方法的动态代理,将方法调用转换为 SQL 执行。 3. **SqlSessionFactory**: 这是创建 SqlSession 的工厂,通常由 SqlSessionFactoryBuilder 创建。源码...
通过MapperProxy和MapperRegistry,MyBatis能够动态地生成Mapper接口的实现类,从而实现SQL的执行。 4. **XML配置文件/注解映射**: MyBatis允许通过XML或注解的方式定义SQL语句。XML配置文件包含SQL映射信息,包括...
- **Mapper接口**:这是MyBatis的核心组件之一,它允许开发者定义SQL操作,并将这些操作方法与SQL语句关联起来。 - **XML映射文件/注解**:用于描述SQL语句及其结果集映射,使得Java对象与数据库记录之间可以进行...
* MapperProxy 中 * SqlSessionFacotry 中 第四节:条件构造器 * EntityWrapper 简介 * 测试查询 * 测试修改 * 测试删除 第五节:活动记录 * 需要让实体类继承 Model 类且实现主键指定方法 * 新增、修改、查询、...
通过MapperProxy,MyBatis将调用这些接口的方法转换为实际的SQL执行,并返回结果。 5. **Mapper XML文件**: 这是MyBatis配置的另一部分,它包含了SQL语句和结果映射。在XML文件中,你可以编写动态SQL,实现复杂的...
Mybatis通过MapperProxy实现了接口方法调用到具体SQL执行的转换。 2. Mapper XML:每个Mapper接口都有对应的XML配置文件,其中包含了具体的SQL语句和结果映射。Mybatis通过MapperRegistry找到对应的XML配置,实现...
MapperRegistry维护了Mapper接口和MapperProxy之间的映射关系。 5. **Executor**:执行器是MyBatis执行SQL的核心组件,分为SimpleExecutor、ReusedExecutor和BatchExecutor三种类型,分别对应不同的执行策略。 6. ...
MyBatis的Mapper接口与XML映射文件中的namespace对应,接口方法与SQL语句对应,通过MapperProxy实现了接口调用与SQL执行的绑定。 9. **参数和结果处理** - `@Param`:用于指定方法参数的别名,方便在XML映射文件...
1. SQL动态生成:MyBatis的核心之一是SQL动态语句。在XML配置文件或注解中,我们可以编写动态SQL,例如`<if>`、`<choose>`、`<when>`、`<otherwise>`等标签,这些在编译时会被MyBatis解析为Java代码,动态生成SQL...
重点研究的类包括SqlSessionManager、SqlSessionFactory、Executor和MapperProxy等。 2. **MyBatis jar包**: 提供的jar包包含MyBatis运行所需的所有依赖,主要用于在项目中引入MyBatis功能。主要的jar文件有...
通过MapperProxy和MapperRegistry,MyBatis实现了接口方法调用到实际SQL执行的映射。 动态SQL是MyBatis的一大亮点,它允许在XML映射文件中编写条件语句,使得SQL语句可以根据传入参数的变化而变化。例如,if、...
通过MyBatis-Spring,我们可以将MyBatis的数据访问层(DAO)对象纳入到Spring的管理之中,从而实现事务控制、DAO对象的自动装配等高级功能。 在1.2.1版本中,MyBatis-Spring提供了以下核心功能: 1. **...
它会自动创建并配置所需的 SqlSession 和 MapperProxy,以便在应用中使用。 5. **注解支持**: MyBatis-Spring 支持在 Service 层方法上直接使用 @Transactional 注解来开启事务,简化了事务管理。同时,还可以在 ...
此外,还有`MapperProxy`和`MapperMethod`,它们负责将Java方法调用转换为SQL执行。 MyBatis3.4.6的更新可能包括对JDBC驱动的兼容性提升,错误修复,性能优化,以及可能的新特性。例如,可能会引入更友好的API设计...
《手写Mybatis》第4章深入探讨了Mapper XML的解析和注册使用,这是Mybatis框架的核心部分,它涉及到如何将XML配置文件转换为可执行的数据库操作。本章主要目标是实现对Mapper XML文件的解析,提取SQL信息,并创建...
- `getMapper`方法的调用会导致MyBatis去`Configuration`对象中获取`Mapper`对象,这个过程依赖于`MapperRegistry`对象,它是`Configuration`对象的属性之一。 - `MapperRegistry`使用一个`HashMap`属性`...
- 映射器工厂和Mapper代理:了解Mapper接口和XML映射文件之间的关联,以及MapperFactoryBean和MapperProxy的工作原理。 - 高级特性:探索MyBatis的缓存机制、结果集映射、自定义插件等功能。 - 整合Spring:将...
MyBatis通过MapperRegistry和MapperProxy实现接口方法到SQL的映射。 9. **事务管理**:MyBatis允许开发者自定义事务边界,可以结合Spring等框架实现全局事务管理。 10. **插件支持**:MyBatis提供插件机制,允许...
2. **Executor.java**:执行器是MyBatis的核心接口之一,它定义了数据库操作的基本行为,如查询、插入、更新和删除。执行器根据不同的执行策略,可以有SimpleExecutor、ReuseExecutor和BatchExecutor等实现,分别...
1. 源码解析:可以学习MyBatis的内部实现,比如SqlSession是如何工作的,MapperProxy是如何动态生成的,以及动态SQL是如何编译和执行的。 2. 执行流程:通过源码分析,理解MyBatis执行SQL的完整步骤,包括SQL语句的...