- 浏览: 981286 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
SqlSessionFactory初始化:http://donald-draper.iteye.com/blog/2331917
Mybatis加载解析Mapper(xml)文件第二讲:http://donald-draper.iteye.com/blog/2333191
在上篇 SqlSessionFactory初始化中,解析全局配置文件mybatisConfig.xml文件时,讲到,properties,typeAliases,plugins,objectFactory,objectWrapperFactory
,settings,environments,databaseIdProvider,typeHandlers的初始化,而mappers的初始化较复杂,
我们放在这一篇来讲。
首先从下面这个方法来看
//加载Mapper xml文件,并解析
//XMLMapperBuilder
//Configuration,添加Mapper xml文件名到Set<String> loadedResources;
//其中key为class完整名,com.mapper.UserMapper
//XPathParser
下面分别来看根据mapper Xnode 配置,namespace,cache,cacheref,parameterMap,resultMap,sql,及select|insert|update|delete子节点
//配置namespace
从上面的方法可以看出,命名空间实际上是配置Mapper对应的MapperBuilderAssistantcurrentNamespace属性
//配置cache-ref
cacheRefElement(context.evalNode("cache-ref"));
//configuration
//CacheRefResolver,缓存参考处理器
//MapperBuilderAssistant,
从分析配置cache-ref,实际上,将cache和cache-ref的命名空间的映射关系添加到configuration中,并从configuration的获取cacheRefNamespace对应的Cache,如果cache-ref的cacheRefNamespace对应的缓存,不存在,则抛出IncompleteElementException,并将对应的CacheRefResolver添加到configuration的IncompleteCacheRef集合中Linklist<CacheRefResolver>;
//配置cache
cacheElement(context.evalNode("cache"));
配置实例
//XNode
//返回Xnode的name属性值,不存在返回默认值
//TypeAliasRegistry 根据type,从TypeAliasRegistry的TYPE_ALIASES中获取对应的Class
// private final HashMap TYPE_ALIASES = new HashMap();
//HashMap<alias,Class> key为Class对应的别名alias
//MapperBuilderAssistant
//将缓存添加到Configuration的二级缓存中
//Configuration
//将缓存添加到Configuration的二级缓存中
//StrictMap<currentNamespace,CacheBuilder>
//caches = new StrictMap("Caches collection");
//BaseBuilder
从上的分析可以看出Cache的节点的解析,实际上是,获取cache节点的type对应的Class,
cache节点的eviction对应的缓存算法Class,以及刷新间隔,读写属性,构造CacheBuilder
,并添加的configuration的二级缓存StrictMap<nameSpace,CacheBuilder>
//CacheBuilder
//MetaObject,设置Class实例属性
这个我们在后面单讲
//配置parameterMap
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
parameterMap配置实例
//MapperBuilderAssistant
//configuration
//ParameterMap的映射关系到configuration的parameterMaps中
//parameterMaps = new StrictMap("Parameter Maps collection");
//Map<nameSpace,ParameterMap>
//ParameterMapping,ParameterMap的参数映射描述
//ParameterMode
//ParameterMap
//从configuration中移除未完成的ChacheRefs
parsePendingChacheRefs();
从上的分析可以看出ParameterMap的解析实际是解析ParameterMap的id,type属性和
parameter子节点;然后解析parameter的property,javaType,jdbcType,typeHalder,
resultMap的属性根据这些属性构建parameterMapping,并添加的parameterMappings(ArrayList<ParameterMapping>)集合中;然后再根据id,type属性和parameterMappings,构造ParameterMap,并添加到configuration的parameterMaps中
。
总结:
解析Mapper对应的xml文件,实际上是解析xml的mapper Xnode,具体到namespace属性,及cache,cache-ref,parameterMap,篇幅有限这一篇我们讲到namespace属性,及cache,cache-ref,parameterMap,这三部分的解析,我们都有小节,实际上就是将这些添加configuration的相应的cache,parameterMap的StrictMap中。
各小节的总结:
namespace:
从上面的方法可以看出,命名空间实际上是配置Mapper对应的MapperBuilderAssistantcurrentNamespace属性;
cache-ref:
从分析配置cache-ref,实际上,将cache和cache-ref的命名空间的映射关系添加到configuration中,并从configuration的获取cacheRefNamespace对应的Cache,如果cache-ref的cacheRefNamespace对应的缓存,不存在,则抛出IncompleteElementException,并将对应的CacheRefResolver添加到configuration的IncompleteCacheRef集合中Linklist<CacheRefResolver>;
cache:
从上的分析可以看出Cache的节点的解析,实际上是,获取cache节点的type对应的Class,
cache节点的eviction对应的缓存算法Class,以及刷新间隔,读写属性,构造CacheBuilder
,并添加的configuration的二级缓存StrictMap<nameSpace,CacheBuilder>;
parameterMap:
从上的分析可以看出ParameterMap的解析实际是解析ParameterMap的id,type属性和
parameter子节点;然后解析parameter的property,javaType,jdbcType,typeHalder,resultMap的属性,根据这些属性构建parameterMapping,并添加的parameterMappings(ArrayList<ParameterMapping>)集合中;
然后再根据id,type属性和parameterMappings,构造ParameterMap,并添加到configuration的parameterMaps中。
下面一片我们再讲resultMap,sql,及select|insert|update|delete子节点
//XMLMapperEntityResolver
Mybatis加载解析Mapper(xml)文件第二讲:http://donald-draper.iteye.com/blog/2333191
在上篇 SqlSessionFactory初始化中,解析全局配置文件mybatisConfig.xml文件时,讲到,properties,typeAliases,plugins,objectFactory,objectWrapperFactory
,settings,environments,databaseIdProvider,typeHandlers的初始化,而mappers的初始化较复杂,
我们放在这一篇来讲。
首先从下面这个方法来看
//加载Mapper xml文件,并解析
private void mapperElement(XNode parent) throws Exception { if(parent != null) { for(Iterator i$ = parent.getChildren().iterator(); i$.hasNext();) { XNode child = (XNode)i$.next(); if("package".equals(child.getName())) { String mapperPackage = child.getStringAttribute("name"); configuration.addMappers(mapperPackage); } else { String resource = child.getStringAttribute("resource"); String url = child.getStringAttribute("url"); String mapperClass = child.getStringAttribute("class"); //根据配置的resource,解析Mapper if(resource != null && url == null && mapperClass == null) { ErrorContext.instance().resource(resource); //加载Mapper的resource文件 InputStream inputStream = Resources.getResourceAsStream(resource); 构建XMLMapperBuilder XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments()); mapperParser.parse(); } else if(resource == null && url != null && mapperClass == null) { ErrorContext.instance().resource(url); InputStream inputStream = Resources.getUrlAsStream(url); XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments()); mapperParser.parse(); } else //这一部分放到下一篇讲 //根据配置的class,解析Mapper if(resource == null && url == null && mapperClass != null) { Class mapperInterface = Resources.classForName(mapperClass); //mapperInterface信息添加到configuration configuration.addMapper(mapperInterface); } else { throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one."); } } } } }
//XMLMapperBuilder
public class XMLMapperBuilder extends BaseBuilder { private XPathParser parser; private MapperBuilderAssistant builderAssistant; private Map sqlFragments; private String resource; //构造XMLMapperBuilder public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map sqlFragments) { this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()), configuration, resource, sqlFragments); } private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map sqlFragments) { super(configuration); //构建MapperBuilderAssistant builderAssistant = new MapperBuilderAssistant(configuration, resource); this.parser = parser; this.sqlFragments = sqlFragments; this.resource = resource; } public void parse() { if(!configuration.isResourceLoaded(resource)) { //如果configuration没有加载文件,则解析Mapper xml文件, <mapper namespace="test.Dao.UserMapper"> configurationElement(parser.evalNode("/mapper")); //将资源添加到configuration的Set<class.name> resource configuration.addLoadedResource(resource); //绑定Mapper的命名空间 bindMapperForNamespace(); } //从configuration中移除未完成的ResultMaps parsePendingResultMaps(); //从configuration中移除未完成的ChacheRefs parsePendingChacheRefs(); //从configuration中移除未完成的Statements parsePendingStatements(); } //根据mapper Xnode 配置,namespace,cache,cache-ref,parameterMap,resultMap, //sql,及select|insert|update|delete子节点 private void configurationElement(XNode context) { try { //这部分我们在下面分别去分析 String namespace = context.getStringAttribute("namespace"); builderAssistant.setCurrentNamespace(namespace); cacheRefElement(context.evalNode("cache-ref")); cacheElement(context.evalNode("cache")); parameterMapElement(context.evalNodes("/mapper/parameterMap")); resultMapElements(context.evalNodes("/mapper/resultMap")); sqlElement(context.evalNodes("/mapper/sql")); buildStatementFromContext(context.evalNodes("select|insert|update|delete")); } catch(Exception e) { throw new RuntimeException((new StringBuilder()).append("Error parsing Mapper XML. Cause: ").append(e).toString(), e); } } }
//Configuration,添加Mapper xml文件名到Set<String> loadedResources;
//其中key为class完整名,com.mapper.UserMapper
public void addLoadedResource(String resource) { loadedResources.add(resource); }
//XPathParser
public class XPathParser { private Document document; private boolean validation; private EntityResolver entityResolver; private Properties variables; private XPath xpath; //构造XPathParser public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) { commonConstructor(validation, variables, entityResolver); document = createDocument(new InputSource(inputStream)); } //初始化属性 private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) { this.validation = validation; this.entityResolver = entityResolver; this.variables = variables; XPathFactory factory = XPathFactory.newInstance(); xpath = factory.newXPath(); } //创建createDocument private Document createDocument(InputSource inputSource) { DocumentBuilder builder; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(validation); factory.setNamespaceAware(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(false); factory.setCoalescing(false); factory.setExpandEntityReferences(true); builder = factory.newDocumentBuilder(); builder.setEntityResolver(entityResolver); builder.setErrorHandler(new ErrorHandler() { public void error(SAXParseException exception) throws SAXException { throw exception; } public void fatalError(SAXParseException exception) throws SAXException { throw exception; } public void warning(SAXParseException saxparseexception) throws SAXException { } final XPathParser this$0; { this$0 = XPathParser.this; super(); } }); return builder.parse(inputSource); Exception e; e; throw new BuilderException((new StringBuilder()).append("Error creating document instance. Cause: ").append(e).toString(), e); } public XNode evalNode(String expression) { return evalNode(document, expression); } public Integer evalInteger(String expression) { return evalInteger(document, expression); } }
下面分别来看根据mapper Xnode 配置,namespace,cache,cacheref,parameterMap,resultMap,sql,及select|insert|update|delete子节点
//配置namespace
String namespace = context.getStringAttribute("namespace"); builderAssistant.setCurrentNamespace(namespace);
public class MapperBuilderAssistant extends BaseBuilder { private String currentNamespace;//命名空间 private String resource;//Mapper xml的url private Cache currentCache; private boolean unresolvedCacheRef; public MapperBuilderAssistant(Configuration configuration, String resource) { super(configuration); ErrorContext.instance().resource(resource); this.resource = resource; } //设置命名空间 public void setCurrentNamespace(String currentNamespace) { if(currentNamespace == null) throw new BuilderException("The mapper element requires a namespace attribute to be specified."); if(this.currentNamespace != null && !this.currentNamespace.equals(currentNamespace)) { throw new BuilderException((new StringBuilder()).append("Wrong namespace. Expected '").append(this.currentNamespace).append("' but found '").append(currentNamespace).append("'.").toString()); } else { this.currentNamespace = currentNamespace; return; } } }
从上面的方法可以看出,命名空间实际上是配置Mapper对应的MapperBuilderAssistantcurrentNamespace属性
//配置cache-ref
cacheRefElement(context.evalNode("cache-ref"));
private void cacheRefElement(XNode context) { if(context != null) { //添加cacheRef的命名空间映射关系 configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace")); CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant, context.getStringAttribute("namespace")); try { //确定configuration中是否存在参考缓存 cacheRefResolver.resolveCacheRef(); } catch(IncompleteElementException e) { //如果参考缓存不存在,则将cacheRefResolver,添加到configuration //IncompleteCacheRef集合中Linklist<CacheRefResolver> configuration.addIncompleteCacheRef(cacheRefResolver); } } }
//configuration
public void addCacheRef(String namespace, String referencedNamespace) { //将CacheRef的namespace引用的referencedNamespace的映射关系,添加到 //configuration的缓存参考引用中cacheRefMap cacheRefMap.put(namespace, referencedNamespace); }
//CacheRefResolver,缓存参考处理器
public class CacheRefResolver { public CacheRefResolver(MapperBuilderAssistant assistant, String cacheRefNamespace) { this.assistant = assistant; this.cacheRefNamespace = cacheRefNamespace; } public Cache resolveCacheRef() { return assistant.useCacheRef(cacheRefNamespace); } private final MapperBuilderAssistant assistant; private final String cacheRefNamespace;//参考缓存命名空间 }
//MapperBuilderAssistant,
public Cache useCacheRef(String namespace) { if(namespace == null) throw new BuilderException("cache-ref element requires a namespace attribute."); Cache cache; unresolvedCacheRef = true; //根据命名空间,从configuration而级缓存中,获取缓存 cache = configuration.getCache(namespace); if(cache == null) throw new IncompleteElementException((new StringBuilder()).append("No cache for namespace '").append(namespace).append("' could be found.").toString()); //从这里可以看出,参考命名的缓存必须存在,否则抛出异常 currentCache = cache; unresolvedCacheRef = false; return cache; IllegalArgumentException e; e; throw new IncompleteElementException((new StringBuilder()).append("No cache for namespace '").append(namespace).append("' could be found.").toString(), e); }
从分析配置cache-ref,实际上,将cache和cache-ref的命名空间的映射关系添加到configuration中,并从configuration的获取cacheRefNamespace对应的Cache,如果cache-ref的cacheRefNamespace对应的缓存,不存在,则抛出IncompleteElementException,并将对应的CacheRefResolver添加到configuration的IncompleteCacheRef集合中Linklist<CacheRefResolver>;
//配置cache
cacheElement(context.evalNode("cache"));
配置实例
<!-- <cache eviction="LRU" flushInterval="60000" size="1024" readOnly="true" /> eviction是缓存的淘汰算法,可选值有"LRU"、"FIFO"、"SOFT"、"WEAK",缺省值是LRU flashInterval指缓存过期时间,单位为毫秒,60000即为60秒,缺省值为空,即只要容量足够,永不过期 size指缓存多少个对象,默认值为1024 readOnly是否只读,如果为true,则所有相同的sql语句返回的是同一个对象 (有助于提高性能,但并发操作同一条数据时,可能不安全), 如果设置为false,则相同的sql,后面访问的是cache的clone副本。 -->
private void cacheElement(XNode context) throws Exception { if(context != null) { //返回cache节点的type属性,不存在,则返回PERPETUAL String type = context.getStringAttribute("type", "PERPETUAL"); //根据type,从TypeAliasRegistry的TYPE_ALIASES中获取对应的Class Class typeClass = typeAliasRegistry.resolveAlias(type); //返回cache节点的eviction属性,不存在,则返回LRU, //eviction是缓存的淘汰算法,可选值有"LRU"、"FIFO"、"SOFT"、"WEAK",缺省值是LRU String eviction = context.getStringAttribute("eviction", "LRU"); //根据eviction,从TypeAliasRegistry的TYPE_ALIASES中获取对应的Class Class evictionClass = typeAliasRegistry.resolveAlias(eviction); Long flushInterval = context.getLongAttribute("flushInterval"); Integer size = context.getIntAttribute("size"); //返回cache节点的readOnly属性,不存在,则返回false, boolean readWrite = !context.getBooleanAttribute("readOnly", Boolean.valueOf(false)).booleanValue(); //获取缓存的child属性配置 java.util.Properties props = context.getChildrenAsProperties(); // builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, props); } }
//XNode
//返回Xnode的name属性值,不存在返回默认值
public String getStringAttribute(String name, String def) { String value = attributes.getProperty(name); if(value == null) return def; else return value; }
//TypeAliasRegistry 根据type,从TypeAliasRegistry的TYPE_ALIASES中获取对应的Class
// private final HashMap TYPE_ALIASES = new HashMap();
//HashMap<alias,Class> key为Class对应的别名alias
public Class resolveAlias(String string) { if(string == null) return null; Class value; String key = string.toLowerCase(Locale.ENGLISH); if(TYPE_ALIASES.containsKey(key)) value = (Class)TYPE_ALIASES.get(key); else value = Resources.classForName(string); return value; ClassNotFoundException e; e; throw new TypeException((new StringBuilder()).append("Could not resolve type alias '").append(string).append("'. Cause: ").append(e).toString(), e); }
//MapperBuilderAssistant
//将缓存添加到Configuration的二级缓存中
public Cache useNewCache(Class typeClass, Class evictionClass, Long flushInterval, Integer size, boolean readWrite, Properties props) { //获取缓存类型 typeClass = (Class)valueOrDefault(typeClass, org/apache/ibatis/cache/impl/PerpetualCache); //获取缓存算法类型 evictionClass = (Class)valueOrDefault(evictionClass, org/apache/ibatis/cache/decorators/LruCache); //构建缓存 Cache cache = (new CacheBuilder(currentNamespace)).implementation(typeClass).addDecorator(evictionClass).clearInterval(flushInterval).size(size).readWrite(readWrite).properties(props).build(); //将缓存添加到Configuration的二级缓存中 configuration.addCache(cache); currentCache = cache; return cache; }
//Configuration
//将缓存添加到Configuration的二级缓存中
//StrictMap<currentNamespace,CacheBuilder>
//caches = new StrictMap("Caches collection");
public void addCache(Cache cache) { caches.put(cache.getId(), cache); }
public class MapperBuilderAssistant extends BaseBuilder
//BaseBuilder
public abstract class BaseBuilder { protected final Configuration configuration; protected final TypeAliasRegistry typeAliasRegistry; protected final TypeHandlerRegistry typeHandlerRegistry; public BaseBuilder(Configuration configuration) { this.configuration = configuration; typeAliasRegistry = this.configuration.getTypeAliasRegistry(); typeHandlerRegistry = this.configuration.getTypeHandlerRegistry(); } //返回别名对应的Class类型 protected Class resolveAlias(String alias) { return typeAliasRegistry.resolveAlias(alias); } //返回别名对应的Class类型 protected Class resolveClass(String alias) { if(alias == null) return null; return resolveAlias(alias); Exception e; e; throw new BuilderException((new StringBuilder()).append("Error resolving class. Cause: ").append(e).toString(), e); } //根据别名创建实例 protected Object createInstance(String alias) { Class clazz = resolveClass(alias); if(clazz == null) return null; return resolveClass(alias).newInstance(); Exception e; e; throw new BuilderException((new StringBuilder()).append("Error creating instance. Cause: ").append(e).toString(), e); } protected Boolean booleanValueOf(String value, Boolean defaultValue) { return value != null ? Boolean.valueOf(value) : defaultValue; } protected Integer integerValueOf(String value, Integer defaultValue) { return value != null ? Integer.valueOf(value) : defaultValue; } protected Set stringSetValueOf(String value, String defaultValue) { value = value != null ? value : defaultValue; return new HashSet(Arrays.asList(value.split(","))); } //获取别名对应的JdbcType protected JdbcType resolveJdbcType(String alias) { if(alias == null) return null; return JdbcType.valueOf(alias); IllegalArgumentException e; e; throw new BuilderException((new StringBuilder()).append("Error resolving JdbcType. Cause: ").append(e).toString(), e); } }
从上的分析可以看出Cache的节点的解析,实际上是,获取cache节点的type对应的Class,
cache节点的eviction对应的缓存算法Class,以及刷新间隔,读写属性,构造CacheBuilder
,并添加的configuration的二级缓存StrictMap<nameSpace,CacheBuilder>
//CacheBuilder
public class CacheBuilder { private String id;//缓存命名空间 private Class implementation;//缓存实现类 private List decorators;//缓存算法,缓存解决集合 private Integer size; private Long clearInterval;//刷新间隔 private boolean readWrite;//读写属性 private Properties properties; public CacheBuilder(String id) { this.id = id; decorators = new ArrayList(); } //设置缓存属性 private void setCacheProperties(Cache cache) { if(properties != null) { MetaObject metaCache = SystemMetaObject.forObject(cache); Iterator i$ = properties.entrySet().iterator(); do { if(!i$.hasNext()) break; java.util.Map.Entry entry = (java.util.Map.Entry)i$.next(); String name = (String)entry.getKey(); String value = (String)entry.getValue(); if(metaCache.hasSetter(name)) { Class type = metaCache.getSetterType(name); if(java/lang/String == type) metaCache.setValue(name, value); else if(Integer.TYPE == type || java/lang/Integer == type) metaCache.setValue(name, Integer.valueOf(value)); else if(Long.TYPE == type || java/lang/Long == type) metaCache.setValue(name, Long.valueOf(value)); else if(Short.TYPE == type || java/lang/Short == type) metaCache.setValue(name, Short.valueOf(value)); else if(Byte.TYPE == type || java/lang/Byte == type) metaCache.setValue(name, Byte.valueOf(value)); else if(Float.TYPE == type || java/lang/Float == type) metaCache.setValue(name, Float.valueOf(value)); else if(Boolean.TYPE == type || java/lang/Boolean == type) metaCache.setValue(name, Boolean.valueOf(value)); else if(Double.TYPE == type || java/lang/Double == type) metaCache.setValue(name, Double.valueOf(value)); else throw new CacheException((new StringBuilder()).append("Unsupported property type for cache: '").append(name).append("' of type ").append(type).toString()); } } while(true); } } }
//MetaObject,设置Class实例属性
public class MetaObject { private Object originalObject;//原始Obeject private ObjectWrapper objectWrapper;//包装后的Object private ObjectFactory objectFactory; private ObjectWrapperFactory objectWrapperFactory; private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) { originalObject = object; this.objectFactory = objectFactory; this.objectWrapperFactory = objectWrapperFactory; if(object instanceof ObjectWrapper) objectWrapper = (ObjectWrapper)object; else //如果对应objectWrapperFactory中存在,则返回object if(objectWrapperFactory.hasWrapperFor(object)) objectWrapper = objectWrapperFactory.getWrapperFor(this, object); else if(object instanceof Map) //Map objectWrapper = new MapWrapper(this, (Map)object); else if(object instanceof Collection) //List objectWrapper = new CollectionWrapper(this, (Collection)object); else //bean objectWrapper = new BeanWrapper(this, object); } //构造MetaObject public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) { if(object == null) return SystemMetaObject.NULL_META_OBJECT; else return new MetaObject(object, objectFactory, objectWrapperFactory); } public String findProperty(String propName, boolean useCamelCaseMapping) { return objectWrapper.findProperty(propName, useCamelCaseMapping); } public String[] getGetterNames() { return objectWrapper.getGetterNames(); } public String[] getSetterNames() { return objectWrapper.getSetterNames(); } }
这个我们在后面单讲
//配置parameterMap
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
parameterMap配置实例
<!-- <parameterMap id="course_param" type="java.util.Map"> <parameter property="subjectCode" javaType="java.lang.String"/> <parameter property="courseNumber" javaType="java.lang.String"/> <parameter property="termCode" javaType="java.lang.String"/> <parameter property="pidm" javaType="int"/> </parameterMap> -->
private void parameterMapElement(List list) throws Exception { String id; //parameterMap的id Class parameterClass;//parameterMap的type List parameterMappings; //遍历所有的,parameterMap,并解析构造parameterMappings,在添加到configuration的ParameterMap中 for(Iterator i$ = list.iterator(); i$.hasNext(); builderAssistant.addParameterMap(id, parameterClass, parameterMappings)) { XNode parameterMapNode = (XNode)i$.next(); //获取parameterMap的id,type id = parameterMapNode.getStringAttribute("id"); String type = parameterMapNode.getStringAttribute("type"); parameterClass = resolveClass(type); //获取parameterMap的所有parameter子节点 List parameterNodes = parameterMapNode.evalNodes("parameter"); //parameterMappings,ArrayList<ParameterMapping> parameterMappings = new ArrayList(); org.apache.ibatis.mapping.ParameterMapping parameterMapping; //遍历所有的parameter节点,根据parameter节点属性构建ParameterMapping,并添加到parameterMappings for(Iterator i$ = parameterNodes.iterator(); i$.hasNext(); parameterMappings.add(parameterMapping)) { XNode parameterNode = (XNode)i$.next(); //获取parameter的property,javaType,jdbcType,resultMap,mode,typeHandler,numericScale属性 String property = parameterNode.getStringAttribute("property"); String javaType = parameterNode.getStringAttribute("javaType"); String jdbcType = parameterNode.getStringAttribute("jdbcType"); String resultMap = parameterNode.getStringAttribute("resultMap"); String mode = parameterNode.getStringAttribute("mode"); String typeHandler = parameterNode.getStringAttribute("typeHandler"); Integer numericScale = parameterNode.getIntAttribute("numericScale", null); // 获取mode的ParameterMode类型 org.apache.ibatis.mapping.ParameterMode modeEnum = resolveParameterMode(mode); // 获取javaTypeClass类型 Class javaTypeClass = resolveClass(javaType); // 获取jdbcType类型 JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType); // 获取typeHandler类型 Class typeHandlerClass = resolveClass(typeHandler); //构建ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale); } } }
//MapperBuilderAssistant
public class MapperBuilderAssistant extends BaseBuilder { private String currentNamespace; private String resource; private Cache currentCache; private boolean unresolvedCacheRef; //ParameterMap添加到configuration中 public ParameterMap addParameterMap(String id, Class parameterClass, List parameterMappings) { //获取全局唯一的命名空间 id = applyCurrentNamespace(id, false); org.apache.ibatis.mapping.ParameterMap.Builder parameterMapBuilder = new org.apache.ibatis.mapping.ParameterMap.Builder(configuration, id, parameterClass, parameterMappings); ParameterMap parameterMap = parameterMapBuilder.build(); //ParameterMap添加到configuration中 configuration.addParameterMap(parameterMap); return parameterMap; } //ParameterMapping构建 public ParameterMapping buildParameterMapping(Class parameterType, String property, Class javaType, JdbcType jdbcType, String resultMap, ParameterMode parameterMode, Class typeHandler, Integer numericScale) { resultMap = applyCurrentNamespace(resultMap, true); Class javaTypeClass = resolveParameterJavaType(parameterType, property, javaType, jdbcType); TypeHandler typeHandlerInstance = resolveTypeHandler(javaTypeClass, typeHandler); org.apache.ibatis.mapping.ParameterMapping.Builder builder = new org.apache.ibatis.mapping.ParameterMapping.Builder(configuration, property, javaTypeClass); builder.jdbcType(jdbcType); builder.resultMapId(resultMap); builder.mode(parameterMode); builder.numericScale(numericScale); builder.typeHandler(typeHandlerInstance); return builder.build(); } }
//configuration
//ParameterMap的映射关系到configuration的parameterMaps中
//parameterMaps = new StrictMap("Parameter Maps collection");
//Map<nameSpace,ParameterMap>
public void addParameterMap(ParameterMap pm) { parameterMaps.put(pm.getId(), pm); }
//ParameterMapping,ParameterMap的参数映射描述
public class ParameterMapping { private Configuration configuration; private String property; private ParameterMode mode; private Class javaType; private JdbcType jdbcType; private Integer numericScale; private TypeHandler typeHandler; private String resultMapId; private String jdbcTypeName; private String expression; public static class Builder { public Builder mode(ParameterMode mode) { parameterMapping.mode = mode; return this; } public Builder javaType(Class javaType) { parameterMapping.javaType = javaType; return this; } public Builder jdbcType(JdbcType jdbcType) { parameterMapping.jdbcType = jdbcType; return this; } public Builder numericScale(Integer numericScale) { parameterMapping.numericScale = numericScale; return this; } public Builder resultMapId(String resultMapId) { parameterMapping.resultMapId = resultMapId; return this; } public Builder typeHandler(TypeHandler typeHandler) { parameterMapping.typeHandler = typeHandler; return this; } public Builder jdbcTypeName(String jdbcTypeName) { parameterMapping.jdbcTypeName = jdbcTypeName; return this; } public ParameterMapping build() { resolveTypeHandler(); return parameterMapping; } private void resolveTypeHandler() { if(parameterMapping.typeHandler == null && parameterMapping.javaType != null) { Configuration configuration = parameterMapping.configuration; //从configuration的typeHandlerRegistry获取TypeHandler TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); parameterMapping.typeHandler = typeHandlerRegistry.getTypeHandler(parameterMapping.javaType, parameterMapping.jdbcType); } } private ParameterMapping parameterMapping; public Builder(Configuration configuration, String property, TypeHandler typeHandler) { parameterMapping = new ParameterMapping(); parameterMapping.configuration = configuration; parameterMapping.property = property; parameterMapping.typeHandler = typeHandler; parameterMapping.mode = ParameterMode.IN; } public Builder(Configuration configuration, String property, Class javaType) { parameterMapping = new ParameterMapping(); parameterMapping.configuration = configuration; parameterMapping.property = property; parameterMapping.javaType = javaType; parameterMapping.mode = ParameterMode.IN; } } }
//ParameterMode
public final class ParameterMode extends Enum { public static ParameterMode[] values() { return (ParameterMode[])$VALUES.clone(); } public static ParameterMode valueOf(String name) { return (ParameterMode)Enum.valueOf(org/apache/ibatis/mapping/ParameterMode, name); } private ParameterMode(String s, int i) { super(s, i); } public static final ParameterMode IN; public static final ParameterMode OUT; public static final ParameterMode INOUT; private static final ParameterMode $VALUES[]; static { IN = new ParameterMode("IN", 0); OUT = new ParameterMode("OUT", 1); INOUT = new ParameterMode("INOUT", 2); $VALUES = (new ParameterMode[] { IN, OUT, INOUT }); } }
//ParameterMap
public class ParameterMap { private String id; private Class type; private List parameterMappings; public static class Builder { public Class type() { return parameterMap.type; } public ParameterMap build() { parameterMap.parameterMappings = Collections.unmodifiableList(parameterMap.parameterMappings); return parameterMap; } private ParameterMap parameterMap; public Builder(Configuration configuration, String id, Class type, List parameterMappings) { parameterMap = new ParameterMap(); parameterMap.id = id; parameterMap.type = type; parameterMap.parameterMappings = parameterMappings; } } }
//从configuration中移除未完成的ChacheRefs
parsePendingChacheRefs();
private void parsePendingChacheRefs() { Collection incompleteCacheRefs = configuration.getIncompleteCacheRefs(); synchronized(incompleteCacheRefs) { for(Iterator iter = incompleteCacheRefs.iterator(); iter.hasNext();) try { //CacheRefResolver的参考缓存可以在configuration的缓存中找到, //则从IncompleteCacheRefs,LinkedList<CacheRefResolver>中移除CacheRefResolver ((CacheRefResolver)iter.next()).resolveCacheRef(); iter.remove(); } catch(IncompleteElementException e) { } } }
从上的分析可以看出ParameterMap的解析实际是解析ParameterMap的id,type属性和
parameter子节点;然后解析parameter的property,javaType,jdbcType,typeHalder,
resultMap的属性根据这些属性构建parameterMapping,并添加的parameterMappings(ArrayList<ParameterMapping>)集合中;然后再根据id,type属性和parameterMappings,构造ParameterMap,并添加到configuration的parameterMaps中
。
总结:
解析Mapper对应的xml文件,实际上是解析xml的mapper Xnode,具体到namespace属性,及cache,cache-ref,parameterMap,篇幅有限这一篇我们讲到namespace属性,及cache,cache-ref,parameterMap,这三部分的解析,我们都有小节,实际上就是将这些添加configuration的相应的cache,parameterMap的StrictMap中。
各小节的总结:
namespace:
从上面的方法可以看出,命名空间实际上是配置Mapper对应的MapperBuilderAssistantcurrentNamespace属性;
cache-ref:
从分析配置cache-ref,实际上,将cache和cache-ref的命名空间的映射关系添加到configuration中,并从configuration的获取cacheRefNamespace对应的Cache,如果cache-ref的cacheRefNamespace对应的缓存,不存在,则抛出IncompleteElementException,并将对应的CacheRefResolver添加到configuration的IncompleteCacheRef集合中Linklist<CacheRefResolver>;
cache:
从上的分析可以看出Cache的节点的解析,实际上是,获取cache节点的type对应的Class,
cache节点的eviction对应的缓存算法Class,以及刷新间隔,读写属性,构造CacheBuilder
,并添加的configuration的二级缓存StrictMap<nameSpace,CacheBuilder>;
parameterMap:
从上的分析可以看出ParameterMap的解析实际是解析ParameterMap的id,type属性和
parameter子节点;然后解析parameter的property,javaType,jdbcType,typeHalder,resultMap的属性,根据这些属性构建parameterMapping,并添加的parameterMappings(ArrayList<ParameterMapping>)集合中;
然后再根据id,type属性和parameterMappings,构造ParameterMap,并添加到configuration的parameterMaps中。
下面一片我们再讲resultMap,sql,及select|insert|update|delete子节点
//XMLMapperEntityResolver
public class XMLMapperEntityResolver implements EntityResolver { public XMLMapperEntityResolver() { } public InputSource resolveEntity(String publicId, String systemId) throws SAXException { if(publicId != null) publicId = publicId.toUpperCase(Locale.ENGLISH); if(systemId != null) systemId = systemId.toUpperCase(Locale.ENGLISH); InputSource source = null; try { String path = (String)doctypeMap.get(publicId); source = getInputSource(path, source); if(source == null) { path = (String)doctypeMap.get(systemId); source = getInputSource(path, source); } } catch(Exception e) { throw new SAXException(e.toString()); } return source; } private InputSource getInputSource(String path, InputSource source) { if(path != null) try { java.io.InputStream in = Resources.getResourceAsStream(path); source = new InputSource(in); } catch(IOException e) { } return source; } private static final Map doctypeMap; private static final String IBATIS_CONFIG_DOCTYPE; private static final String IBATIS_CONFIG_URL; private static final String IBATIS_MAPPER_DOCTYPE; private static final String IBATIS_MAPPER_URL; private static final String MYBATIS_CONFIG_DOCTYPE; private static final String MYBATIS_CONFIG_URL; private static final String MYBATIS_MAPPER_DOCTYPE; private static final String MYBATIS_MAPPER_URL; private static final String IBATIS_CONFIG_DTD = "org/apache/ibatis/builder/xml/mybatis-3-config.dtd"; private static final String IBATIS_MAPPER_DTD = "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd"; static { doctypeMap = new HashMap(); IBATIS_CONFIG_DOCTYPE = "-//ibatis.apache.org//DTD Config 3.0//EN".toUpperCase(Locale.ENGLISH); IBATIS_CONFIG_URL = "http://ibatis.apache.org/dtd/ibatis-3-config.dtd".toUpperCase(Locale.ENGLISH); IBATIS_MAPPER_DOCTYPE = "-//ibatis.apache.org//DTD Mapper 3.0//EN".toUpperCase(Locale.ENGLISH); IBATIS_MAPPER_URL = "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd".toUpperCase(Locale.ENGLISH); MYBATIS_CONFIG_DOCTYPE = "-//mybatis.org//DTD Config 3.0//EN".toUpperCase(Locale.ENGLISH); MYBATIS_CONFIG_URL = "http://mybatis.org/dtd/mybatis-3-config.dtd".toUpperCase(Locale.ENGLISH); MYBATIS_MAPPER_DOCTYPE = "-//mybatis.org//DTD Mapper 3.0//EN".toUpperCase(Locale.ENGLISH); MYBATIS_MAPPER_URL = "http://mybatis.org/dtd/mybatis-3-mapper.dtd".toUpperCase(Locale.ENGLISH); doctypeMap.put(IBATIS_CONFIG_URL, "org/apache/ibatis/builder/xml/mybatis-3-config.dtd"); doctypeMap.put(IBATIS_CONFIG_DOCTYPE, "org/apache/ibatis/builder/xml/mybatis-3-config.dtd"); doctypeMap.put(IBATIS_MAPPER_URL, "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd"); doctypeMap.put(IBATIS_MAPPER_DOCTYPE, "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd"); doctypeMap.put(MYBATIS_CONFIG_URL, "org/apache/ibatis/builder/xml/mybatis-3-config.dtd"); doctypeMap.put(MYBATIS_CONFIG_DOCTYPE, "org/apache/ibatis/builder/xml/mybatis-3-config.dtd"); doctypeMap.put(MYBATIS_MAPPER_URL, "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd"); doctypeMap.put(MYBATIS_MAPPER_DOCTYPE, "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd"); } }
发表评论
-
Mybatis缓存实现
2016-12-07 10:36 979SqlSessionFactory初始化:http://don ... -
DefaultSqlSession第三讲-事务提交,回滚,关闭SqlSession,清除缓存
2016-11-20 11:07 5699上面两篇讲过query和update及flushStateme ... -
DefaultSqlSession第二讲-更新,刷新Statement
2016-11-20 11:06 628上一篇文章中,我们讲到DefaultSqlSession的查询 ... -
DefaultSqlSession第一讲query解析
2016-11-20 11:06 1622上一篇文章:我们说过DefaultSqlSession,Def ... -
Mybatis的SqlSession解析
2016-11-20 11:02 2545在前文中,Mybatis使用教程中,有下面一段代码: Sql ... -
Mybatis的Reflector解析
2016-11-18 12:53 2160Mybatis的MetaObject解析:http://don ... -
Mybatis的MetaObject解析
2016-11-18 11:40 9577SqlSessionFactory初始化:http://don ... -
mybatis 动态标签语句的解析(BoundSql)
2016-10-30 09:48 5755SqlSessionFactory初始化:http://don ... -
Mybatis的Environment解析详解
2016-10-29 18:28 1992SqlSessionFactory初始化:http://don ... -
Mybatis 解析Mapper(class)
2016-10-26 11:44 3347SqlSessionFactory初始化:http://don ... -
Mybatis加载解析Mapper(xml)文件第二讲
2016-10-25 21:30 4784SqlSessionFactory初始化:http://don ... -
SqlSessionFactory初始化
2016-10-20 15:38 2454mybatis 使用教程:http://donald-drap ... -
mybatis 使用教程
2016-10-14 09:03 908Myeclispe下mybatis generator的使 ... -
Spring+Mybatis多数据源的实现
2016-09-21 18:15 3094浅谈Spring事务隔离级别:http://www.cnblo ... -
mybaitis CDATA 防止字符被解析
2016-08-17 18:45 724在使用mybatis 时我们sql是写在xml 映射文件中,如 ... -
Myeclispe下mybatis generator的使用
2016-07-05 18:05 1376准备:下载附件包解压到myeclispe的dropins文件夹 ...
相关推荐
创建MyBatis的第一个实例通常涉及以下步骤: 1. 创建数据库表。 2. 创建项目,导入MyBatis所需的jar包。 3. 编写实体类,比如User类。 4. 编写映射文件UserMapper.xml和UserMapper接口,声明需要的方法。 5. 配置...
2. **MyBatis-SQLMapClient**:这部分提供了对XML配置文件的处理,用于读取和解析Mapper配置。 3. **MyBatis-Plus**(可选):这是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高...
1. 加载XML文件:使用Java的`javax.xml.parsers.DocumentBuilderFactory`创建一个DocumentBuilder,并通过它加载XML文件。 2. 解析XML:通过`DocumentBuilder`的parse()方法解析XML文档,得到一个Document对象。 3...
1. **加载配置文件**:配置文件通常为XML格式,包含数据库连接信息、表名、生成的Java包路径等。 2. **解析数据库元数据**:获取表结构、字段信息等,这是生成代码的基础。 3. **生成Java代码**:基于解析出的数据库...
"01-Mybatis10-第一个mybatis程序"涵盖了Mybatis的基本使用步骤,包括配置Mybatis的主配置文件(mybatis-config.xml)、创建Mapper接口、编写Mapper XML文件以及实体类。在实际运行时,Mybatis会加载配置文件,根据...
创建 `SqlSessionFactory` 是 MyBatis 使用的第一步,它是线程安全的,可以在应用程序中被共享和复用。 - **读取配置文件**:可以通过 `InputStream` 或者 `Reader` 来读取 MyBatis 的配置文件。 - **构建 `...
- **where 子句**:自动添加 where 关键字,并处理第一个 where 后面的 and/or 问题。 - **foreach 循环**:循环遍历集合或数组。 - **SQL 片段**:重用 SQL 代码块。 #### 六、高级映射案例 - **一对一查询**:...
4. Mapper配置:通过在Java类路径下的mybatis目录下放置Mapper XML文件,或者使用注解式Mapper,可以方便地定义SQL语句。 五、实战演练 1. 创建Spring Boot项目:首先创建一个基于Spring Boot的新项目,并在pom.xml...
为了自动化生成MyBatis的实体类、Mapper接口和XML映射文件,我们可以使用MyBatis Generator。在`generatorConfig.xml`配置文件中指定数据库连接信息、生成的目标包路径等。然后通过命令行或IDE插件运行Generator。...
3. **Mapper接口与XML配置**:解析Mapper接口和对应的XML配置文件,理解SQL语句如何在XML中编写,以及如何通过注解方式实现映射。 4. **基本 CRUD 操作**:展示如何使用MyBatis执行增删改查操作,包括动态SQL和结果...
MyBatis将SQL语句分离到mapper.xml文件中,使得SQL和Java代码解耦,方便修改。 - **参数传递**:JDBC传递参数繁琐,MyBatis通过动态SQL和参数映射简化这一过程,能够自动将Java对象转化为SQL语句的参数。 - **结果...
根据提供的文件信息,本次将对MyBatis框架的相关知识点进行深入解析。MyBatis是一款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集,通过...
MyBatis 是一个基于 Java 的持久层框架,它致力于简化 SQL 查询的处理,提供了灵活的 SQL 和 XML 或注解的映射方式,使得开发者能够专注于 SQL 本身,而无需关注 JDBC 的繁琐操作。MyBatis 从前身为 Apache 的 ...
MyBatis作为一个轻量级的持久层框架,提供了强大的SQL映射和数据访问能力,但在处理大量数据时,一次性加载所有结果可能会导致内存溢出,因此分页查询显得尤为重要。本文将详细介绍如何在MyBatis中实现定时任务列表...
首先,"mybatis教案-day01-2.0.docx" 和 "mybatis教案-day01-2.0.pdf" 可能是针对 MyBatis 入门课程的第一天教学内容,可能包含了基本概念介绍、环境搭建、XML 配置文件解析、Mapper 接口定义以及动态 SQL 等内容。...
#### 第一章 什么是MyBatis **MyBatis** 是一款非常流行的 SQL 映射框架,最初由 Clinton Begin 在 2002 年创建。随后,该框架被捐献给 Apache 基金会,并在此基础上成立了 iBatis 项目。到了 2010 年 5 月,项目的...
- **XML映射文件配置**:在Mapper XML文件中,使用`<association>`和`<collection>`元素来定义多对多关系。`<collection>`元素用于表示一对多或多对多关系,而`<association>`则表示一对一或多对一关系。 - **注解...
- **第一步**:生成mapper配置文件。 - **第二步**:使用Java类生成mapper文件。 - **第三步**:拷贝生成的mapper文件到工程中指定的目录中。 - **Mapper.xml**:生成的映射文件。 - **Mapper.java**:生成的接口...
4. 整合MyBatis与Spring:使用Spring的SqlSessionFactoryBean加载MyBatis的配置,将Mapper接口与XML映射文件关联。 5. 测试:编写JUnit测试用例,确保SSM框架整合成功,各个组件能正常工作。 在实际开发中,我们...
MyBatis 的动态 SQL 是通过 XML 映射文件中的特定标签实现的,如 trim、where、set、foreach、if、choose、when、otherwise、bind 等。这些标签能够帮助我们在运行时根据条件动态地拼接 SQL 语句,其执行原理是利用 ...