1.前言
这一章节从题目中也看出来我们要支持注解版的增删改查,可以在Mapper层的接口类的方法上写Sql语句,如:Insert,Update,Delete,Select的这几个基础Sql,如下图,这样就不用在Xml里去写Sql了,但是这就引申出一个问题,我们怎么解析注解的Sql语句,将方法上的SQL内容取出来并按之前的既定流程去处理执行Sql呢?
我们现在要处理以下几步才能达到目的
1.配置文件中去配置注解类,加上此在解析的时候才能知道什么情况下用XML方式,在什么情况下用注解方式
2.在配置解析时如果是注解类,直接将class值为namespce进行代理注册
3.开始解析注解,找到Mapper类里所有的方法,每一个方法都判断下是不是加了这4种注解
3.1.获取Sql内容,传输到以前就有的流程里得到处理过后的Sql语句,SqlSource
3.2.通过反射获取方法的参数、返回值、参数类型、返回值类型、并将获取到的数据映射到MappedStatement以及ResultMap
4.之后的流程不变
2.Uml类图
看到类图我们知道,这一章节其实也是很简单的,涉及添加的类只有几个,涉及的修改也不多
添加了4个注解类,1个解析注解类MappernnotationBuilder
XmlConfiguration这里修改判断下如果是注解方式直接调用MapperRegistry的addMapper方法将当前的class进行代理注册,
MapperRegistry类的addMapper方法里添加调用MappernnotationBuilder解析注解数据。
MappernnotationBuilder拿到Sql原内容后调用XmlLanguageDriver进行Sql源处理,继续解析参数、返回值、调用MapperBuilderAsisstant的addMappedStatement和addResultMaps方法将所得的数据映射到MappedStatement和ResultMap类中,供后续使用,之后的就还是和之前的流程一样。
3.代码实现
XMLConfigBuilder类:此类解析Mapper时添加从xml中获取Class,如果这个Class不为空,证明是要解析注解类,通过反射将String的class类转换为类对象,并通过configuration添加到mapper映射里。
// 处理mapper的方法,mapper里有多个sql语句,所以需要List
private void mapperElement(Element mappers) throws Exception {
// 得到mybatis-config-datasource.xml的mappers标签里的mapper
List<Element> mapperList = mappers.elements("mapper");
for (Element e : mapperList) {
String resource = e.attributeValue("resource");
String mapperClass = e.attributeValue("class");
// xml解析方式
if (resource != null && mapperClass == null) {
InputStream inputStream = Resources.getResourceAsStream(resource);
// 在for循环里每个mapper都重新new一个XMLMapperBuilder,来解析
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource);
mapperParser.parse();
} else if (resource == null && mapperClass != null) {
// 注解方式
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
}
}
}
MapperRegistry类:此类里就添加了解析注解类的处理调用。
public <T> void addMapper(Class<T> type) {
// 是接口
if (type.isInterface()) {
if (hasMapper(type)) {
// 如果重复添加了报错
throw new RuntimeException("Type " + type + " is already known to the MapperRegistry.");
}
// 注册映射器代理工厂
knownMappers.put(type, new MapperProxyFactory<>(type));
// 解析注解类语句配置
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
}
}
MapperAnnotationBuilder类:此类本节新添加的类,专门处理注解的解析,如sql,参数,返回值等操作,
1.parse方法,拿到class的所有方法,如IuserDao定义的所有方法。
2.循环遍历每一个方法并调用parseStatement(method)方法,
2.1 获取参数类型,调用getParameterType(method);
2.2 获取语言驱动器,目的是为了创造Sql源,调用getLanguageDriver(method) 2.3 获取数据源,通过调用getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver)方法。
2.3.1 通过调用getSqlAnnotationType(method)方法,获取注解类型 2.3.2 根据得到的注解类型获取当前方法上的注解信息,并得到方法上的注解值