spring mybatis2
与spring集成,入口:
SqlSessionFactoryBean实现InitializingBean接口,InitializingBean接口有afterPropertiesSet()方法,(spring的getBean方法里面调进去的)
SpringApplication.run(MybatisApplication.class, args); refreshContext(context); super.refresh(); finishBeanFactoryInitialization(beanFactory); beanFactory.preInstantiateSingletons(); getBean(beanName); //userController Object beanInstance = doCreateBean(beanName, mbdToUse, args); //userController populateBean(beanName, mbd, instanceWrapper); //userController pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); //userService
getBean(String name) //userService beanFactory.getBean(beanName); //userMapper populateBean(beanName, mbd, instanceWrapper); //userMapper Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); //'sqlSessionTemplate' getBean(String name) //funSqlSessionTemplate getBean(String name) //funSqlSessionFactory
SqlSessionFactoryBean类: public void setDataSource(DataSource dataSource) { if (dataSource instanceof TransactionAwareDataSourceProxy) { } else { this.dataSource = dataSource; // } } public SqlSessionFactory getObject() throws Exception { if (this.sqlSessionFactory == null) { afterPropertiesSet(); } return this.sqlSessionFactory; } public void afterPropertiesSet() throws Exception { this.sqlSessionFactory = buildSqlSessionFactory(); }
protected SqlSessionFactory buildSqlSessionFactory() throws IOException { Configuration configuration; XMLConfigBuilder xmlConfigBuilder = null; if (this.configuration != null) { } else if (this.configLocation != null) { } else { configuration = new Configuration(); //注册别名 } if (hasLength(this.typeAliasesPackage)) { //包的别名 String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); //typeAliasesPackage = org.study.mybatis.dao.entity, for (String packageToScan : typeAliasPackageArray) { configuration.getTypeAliasRegistry().registerAliases(packageToScan, typeAliasesSuperType == null ? Object.class : typeAliasesSuperType); //注册Entity的别名 } } if (!isEmpty(this.typeAliases)) { //类型别名 for (Class<?> typeAlias : this.typeAliases) { configuration.getTypeAliasRegistry().registerAlias(typeAlias); } } if (!isEmpty(this.plugins)) { //插件 for (Interceptor plugin : this.plugins) { configuration.addInterceptor(plugin); } } if (hasLength(this.typeHandlersPackage)) { String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); for (String packageToScan : typeHandlersPackageArray) { configuration.getTypeHandlerRegistry().register(packageToScan); } } if (!isEmpty(this.typeHandlers)) { for (TypeHandler<?> typeHandler : this.typeHandlers) { configuration.getTypeHandlerRegistry().register(typeHandler); } } if (this.databaseIdProvider != null) { //多数据源支持 try { configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource)); } } if (this.cache != null) { configuration.addCache(this.cache); } if (xmlConfigBuilder != null) { try { xmlConfigBuilder.parse(); } finally { ErrorContext.instance().reset(); } } if (this.transactionFactory == null) { this.transactionFactory = new SpringManagedTransactionFactory(); } configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource)); if (!isEmpty(this.mapperLocations)) { //file [D:\acticityvideo\mybatis-demo-master\mybatis-demo-master\target\classes\mapping\UserMapper.xml] for (Resource mapperLocation : this.mapperLocations) { try { XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), configuration, mapperLocation.toString(), configuration.getSqlFragments()); xmlMapperBuilder.parse(); } finally { ErrorContext.instance().reset(); } } } else { } return this.sqlSessionFactoryBuilder.build(configuration); }
public void parse() { if (!configuration.isResourceLoaded(resource)) { //resource = file [D:\acticityvideo\mybatis-demo-master\mybatis-demo-master\target\classes\mapping\UserMapper.xml] configurationElement(parser.evalNode("/mapper")); //解析XML文件 configuration.addLoadedResource(resource); bindMapperForNamespace(); //Annotation的支持 } parsePendingResultMaps(); parsePendingCacheRefs(); parsePendingStatements(); }
UserMapper.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="org.study.mybatis.dao.mapper.UserMapper" > <resultMap id="BaseResultMap" type="org.study.mybatis.dao.entity.Money" > <id column="id" property="id" jdbcType="INTEGER" /> <result column="name" property="name" jdbcType="VARCHAR" /> <result column="money" property="money" jdbcType="DOUBLE" /> </resultMap> <sql id="Base_Column_List" > id, name, money </sql> <select id="list" resultMap="BaseResultMap"> select <include refid="Base_Column_List"/> from money </select> </mapper>
configurationElement(parser.evalNode("/mapper"))
public XNode evalNode(String expression) { return evalNode(document, expression); } public XNode evalNode(Object root, String expression) { Node node = (Node) evaluate(expression, root, XPathConstants.NODE); if (node == null) { return null; } return new XNode(this, node, variables); } private Object evaluate(String expression, Object root, QName returnType) { try { return xpath.evaluate(expression, root, returnType); } } private void configurationElement(XNode context) { try { String namespace = context.getStringAttribute("namespace"); //org.study.mybatis.dao.mapper.UserMapper builderAssistant.setCurrentNamespace(namespace); //null cacheRefElement(context.evalNode("cache-ref")); //null cacheElement(context.evalNode("cache")); //null parameterMapElement(context.evalNodes("/mapper/parameterMap")); //null resultMapElements(context.evalNodes("/mapper/resultMap")); sqlElement(context.evalNodes("/mapper/sql")); buildStatementFromContext(context.evalNodes("select|insert|update|delete")); } }
context.evalNodes("/mapper/resultMap")
//返回<resultMap type="org.study.mybatis.dao.entity.Money" id="BaseResultMap">
<id jdbcType="INTEGER" column="id" property="id"/>
<result jdbcType="VARCHAR" column="name" property="name"/>
<result jdbcType="DOUBLE" column="money" property="money"/>
</resultMap>
resultMapElements(context.evalNodes("/mapper/resultMap"));
private void resultMapElements(List<XNode> list) throws Exception { for (XNode resultMapNode : list) { try { resultMapElement(resultMapNode); } } } private ResultMap resultMapElement(XNode resultMapNode) throws Exception { return resultMapElement(resultMapNode, Collections.<ResultMapping> emptyList()); } private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings) throws Exception { ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier()); String id = resultMapNode.getStringAttribute("id", resultMapNode.getValueBasedIdentifier()); //BaseResultMap String type = resultMapNode.getStringAttribute("type", resultMapNode.getStringAttribute("ofType", resultMapNode.getStringAttribute("resultType", resultMapNode.getStringAttribute("javaType")))); //org.study.mybatis.dao.entity.Money String extend = resultMapNode.getStringAttribute("extends"); //null Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping"); //null Class<?> typeClass = resolveClass(type); //class org.study.mybatis.dao.entity.Money Discriminator discriminator = null; List<ResultMapping> resultMappings = new ArrayList<ResultMapping>(); resultMappings.addAll(additionalResultMappings); List<XNode> resultChildren = resultMapNode.getChildren(); //[<id jdbcType="INTEGER" column="id" property="id"/> , <result jdbcType="VARCHAR" column="name" property="name"/> , <result jdbcType="DOUBLE" column="money" property="money"/> ] for (XNode resultChild : resultChildren) { if ("constructor".equals(resultChild.getName())) { } else if ("discriminator".equals(resultChild.getName())) { } else { List<ResultFlag> flags = new ArrayList<ResultFlag>(); if ("id".equals(resultChild.getName())) { flags.add(ResultFlag.ID); } resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags)); //resultMappings = [ResultMapping{property='id', column='id', javaType=class java.lang.Integer, jdbcType=INTEGER,flags=[ID],lazy=false}, ResultMapping{property='name', column='name', javaType=class java.lang.String, jdbcType=VARCHAR, flags=[], lazy=false}, ResultMapping{property='money', column='money', javaType=double, jdbcType=DOUBLE, flags=[]lazy=false}] } } ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping); // try { return resultMapResolver.resolve(); } } public List<XNode> getChildren() { List<XNode> children = new ArrayList<XNode>(); NodeList nodeList = node.getChildNodes(); //resultMap节点 if (nodeList != null) { for (int i = 0, n = nodeList.getLength(); i < n; i++) { Node node = nodeList.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { children.add(new XNode(xpathParser, node, variables)); } } } return children; //[<id jdbcType="INTEGER" column="id" property="id"/> , <result jdbcType="VARCHAR" column="name" property="name"/> , <result jdbcType="DOUBLE" column="money" property="money"/> ] } public ResultMapResolver(MapperBuilderAssistant assistant, String id, Class<?> type, String extend, Discriminator discriminator, List<ResultMapping> resultMappings, Boolean autoMapping) { this.assistant = assistant; //file [D:\acticityvideo\mybatis-demo-master\mybatis-demo-master\target\classes\mapping\UserMapper.xml],org.study.mybatis.dao.mapper.UserMapper, this.id = id; //BaseResultMap this.type = type; //class org.study.mybatis.dao.entity.Money this.extend = extend; this.discriminator = discriminator; this.resultMappings = resultMappings; //resultMappings = [ResultMapping{property='id', column='id', javaType=class java.lang.Integer, jdbcType=INTEGER,flags=[ID],lazy=false}, ResultMapping{property='name', column='name', javaType=class java.lang.String, jdbcType=VARCHAR, flags=[], lazy=false}, ResultMapping{property='money', column='money', javaType=double, jdbcType=DOUBLE, flags=[]lazy=false}] this.autoMapping = autoMapping; }
resultMapResolver.resolve(); public ResultMap resolve() { return assistant.addResultMap(this.id, this.type, this.extend, this.discriminator, this.resultMappings, this.autoMapping); } public ResultMap addResultMap(String id,Class<?> type,String extend, Discriminator discriminator, List<ResultMapping> resultMappings,Boolean autoMapping) { id = applyCurrentNamespace(id, false); //org.study.mybatis.dao.mapper.UserMapper.BaseResultMap extend = applyCurrentNamespace(extend, true); //null ResultMap resultMap = new ResultMap.Builder(configuration, id, type, resultMappings, autoMapping) .discriminator(discriminator).build(); configuration.addResultMap(resultMap); return resultMap; }
sqlElement(context.evalNodes("/mapper/sql"));
context.evalNodes("/mapper/sql") //返回<sql id="Base_Column_List"> id, name, money </sql> private void sqlElement(List<XNode> list) throws Exception { sqlElement(list, null); } private void sqlElement(List<XNode> list, String requiredDatabaseId) throws Exception { for (XNode context : list) { String databaseId = context.getStringAttribute("databaseId"); String id = context.getStringAttribute("id"); //Base_Column_List id = builderAssistant.applyCurrentNamespace(id, false); //org.study.mybatis.dao.mapper.UserMapper.Base_Column_List if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) { sqlFragments.put(id, context); //{org.study.mybatis.dao.mapper.UserMapper.Base_Column_List=<sql id="Base_Column_List"> id, name, money </sql> , Base_Column_List=<sql id="Base_Column_List"> id, name, money </sql> } } } }
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
public List<XNode> evalNodes(String expression) { //expression = select|insert|update|delete return xpathParser.evalNodes(node, expression); //返回<select resultMap="BaseResultMap" id="list"> <include refid="Base_Column_List"/> </select> } private void buildStatementFromContext(List<XNode> list) { if (configuration.getDatabaseId() != null) { } buildStatementFromContext(list, null); } private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) { for (XNode context : list) { //循环所有增删改查语句 final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId); try { statementParser.parseStatementNode(); } } } public void parseStatementNode() { String id = context.getStringAttribute("id"); //list String databaseId = context.getStringAttribute("databaseId"); //数据库类型 Integer fetchSize = context.getIntAttribute("fetchSize"); Integer timeout = context.getIntAttribute("timeout"); String parameterMap = context.getStringAttribute("parameterMap"); String parameterType = context.getStringAttribute("parameterType"); Class<?> parameterTypeClass = resolveClass(parameterType); String resultMap = context.getStringAttribute("resultMap"); //BaseResultMap String resultType = context.getStringAttribute("resultType"); String lang = context.getStringAttribute("lang"); LanguageDriver langDriver = getLanguageDriver(lang); // Class<?> resultTypeClass = resolveClass(resultType); String resultSetType = context.getStringAttribute("resultSetType"); StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString())); //PREPARED ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType); String nodeName = context.getNode().getNodeName(); //select SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH)); //SELECT boolean isSelect = sqlCommandType == SqlCommandType.SELECT; //true boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect); //false boolean useCache = context.getBooleanAttribute("useCache", isSelect); //true boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false); //false XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant); includeParser.applyIncludes(context.getNode()); processSelectKeyNodes(id, parameterTypeClass, langDriver); SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass); //select id, name, money from money String resultSets = context.getStringAttribute("resultSets"); String keyProperty = context.getStringAttribute("keyProperty"); String keyColumn = context.getStringAttribute("keyColumn"); KeyGenerator keyGenerator; String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX; //list!selectKey keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true); //org.study.mybatis.dao.mapper.UserMapper.list!selectKey, if (configuration.hasKeyGenerator(keyStatementId)) { } else { keyGenerator = context.getBooleanAttribute("useGeneratedKeys", configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType)) ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE; } builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets); //MappedStatement是跟sql增删改查语句一一对应。 }
private void applyIncludes(Node source, final Properties variablesContext, boolean included) { if (source.getNodeName().equals("include")) { } else if (source.getNodeType() == Node.ELEMENT_NODE) { NodeList children = source.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { applyIncludes(children.item(i), variablesContext, included); } } else if (included && source.getNodeType() == Node.TEXT_NODE && !variablesContext.isEmpty()) { source.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext)); } }
public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) { XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script, parameterType); return builder.parseScriptNode(); } public SqlSource parseScriptNode() { List<SqlNode> contents = parseDynamicTags(context); //[select , id, name, money , from money],动态的, MixedSqlNode rootSqlNode = new MixedSqlNode(contents); SqlSource sqlSource = null; if (isDynamic) { sqlSource = new DynamicSqlSource(configuration, rootSqlNode); } else { sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType); } return sqlSource; //select id, name, money from money }
configuration.addLoadedResource(resource); //resource = file [D:\acticityvideo\mybatis-demo-master\mybatis-demo-master\target\classes\mapping\UserMapper.xml]
bindMapperForNamespace(); //Annotation的支持,SQL语句也可以在注解使用。
private void bindMapperForNamespace() { String namespace = builderAssistant.getCurrentNamespace(); //org.study.mybatis.dao.mapper.UserMapper if (namespace != null) { Class<?> boundType = null; try { boundType = Resources.classForName(namespace); //interface org.study.mybatis.dao.mapper.UserMapper,namespace就是DAO的接口。 } if (boundType != null) { if (!configuration.hasMapper(boundType)) { configuration.addLoadedResource("namespace:" + namespace); //file [D:\acticityvideo\mybatis-demo-master\mybatis-demo-master\target\classes\mapping\UserMapper.xml],namespace:org.study.mybatis.dao.mapper.UserMapper configuration.addMapper(boundType); } } } } public <T> void addMapper(Class<T> type) { mapperRegistry.addMapper(type); } public <T> void addMapper(Class<T> type) { if (type.isInterface()) { boolean loadCompleted = false; try { knownMappers.put(type, new MapperProxyFactory<T>(type)); //knownMappers是缓存,表示已经解析过的,MapperProxyFactory是代理工厂,type=interface org.study.mybatis.dao.mapper.UserMapper。下次就不会进来。 MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); //MapperAnnotationBuilder就是对注解的解析。 parser.parse(); loadCompleted = true; } finally { if (!loadCompleted) { knownMappers.remove(type); } } } } public void parse() { String resource = type.toString(); //interface org.study.mybatis.dao.mapper.UserMapper if (!configuration.isResourceLoaded(resource)) { loadXmlResource(); configuration.addLoadedResource(resource); assistant.setCurrentNamespace(type.getName()); parseCache(); parseCacheRef(); Method[] methods = type.getMethods(); //拿到接口的所有方法, for (Method method : methods) { //循环接口的所有方法, try { if (!method.isBridge()) { parseStatement(method); } } } } parsePendingMethods(); }
private void parsePendingResultMaps() { Collection<ResultMapResolver> incompleteResultMaps = configuration.getIncompleteResultMaps(); synchronized (incompleteResultMaps) { Iterator<ResultMapResolver> iter = incompleteResultMaps.iterator(); //空 while (iter.hasNext()) { try { iter.next().resolve(); iter.remove(); } } } } private void parsePendingCacheRefs() { Collection<CacheRefResolver> incompleteCacheRefs = configuration.getIncompleteCacheRefs(); synchronized (incompleteCacheRefs) { Iterator<CacheRefResolver> iter = incompleteCacheRefs.iterator(); //空 while (iter.hasNext()) { try { iter.next().resolveCacheRef(); iter.remove(); } } } } private void parsePendingStatements() { Collection<XMLStatementBuilder> incompleteStatements = configuration.getIncompleteStatements(); synchronized (incompleteStatements) { Iterator<XMLStatementBuilder> iter = incompleteStatements.iterator(); //空 while (iter.hasNext()) { try { iter.next().parseStatementNode(); iter.remove(); } } } }
return this.sqlSessionFactoryBuilder.build(configuration); public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }
上面就是SqlSessionFactoryBean的afterPropertiesSet方法执行, 回退到:SqlSessionFactoryBean类: public void afterPropertiesSet() throws Exception { this.sqlSessionFactory = buildSqlSessionFactory(); //执行到这里完成。 } 回退到:SqlSessionFactoryBean类: public SqlSessionFactory getObject() throws Exception { if (this.sqlSessionFactory == null) { afterPropertiesSet(); } return this.sqlSessionFactory; } 回退到: bw.setBeanInstance(beanInstance); //beanInstance = DefaultSqlSessionFactory, 回退到: public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType()); } 回退到: MapperFactoryBean实例化。调用MapperFactoryBean的getObject(), 回退到: exposedObject = initializeBean(beanName, exposedObject, mbd); //beanName = userMapper 回退到: exposedObject = initializeBean(beanName, exposedObject, mbd); //beanName = userService 回退到: exposedObject = initializeBean(beanName, exposedObject, mbd); //beanName = userController 初始化过程完毕。