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
初始化过程完毕。

 

posted @ 2020-02-23 15:12  无天666  阅读(315)  评论(0编辑  收藏  举报