`

MyBatis原理(1)-启动流程2

 
阅读更多
1.XMLConfigBuilder.parse

  public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

2.调用XPathParser.evalNode返回代码configuration根节点的XNode对象,并将之前设置的dom对象传入
 public XNode evalNode(String expression) {
    return evalNode(document, expression);
  }

3.XPathParser调用xpath对象的evaluate方法构造返回org.w3c.dom.Node对象,evalNode的重载方法构造返回XNode对象,XNode是mybatis对Node节点的封装:
  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);
    } catch (Exception e) {
      throw new BuilderException("Error evaluating XPath.  Cause: " + e, e);
    }
  }

Xnode在构造方法会对Node中的属性调用parseAttributes再调用PropertyParser进行解析,对“${}”表达式进行解析,使用XpathParser中的variables对当前节点的attributes进行设值,此处的node是Configuration ,attributeNodes.getLength()长度为0直接跳出。
parseAttributes后再对parseBody进行对当前节点的所有的CDDATA节点或者文本节点中的表达式进行赋值,设置为当前节点的body。到此configuration作为根节点XNode返回。
4.parseConfiguration
 private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

4.1      propertiesElement(root.evalNode("properties"));
和上面的流程一样,不同的是根节点自身持有对XPathParser的引用,随后XPathParser调用evalNode,最后由XPathParser,xpath对象调用xpath.evaluate(expression, root, returnType)方法返回原生dom对象,再对XNode进行初始化
4.1.1 获取resource或者url属性对应的外部属性文件并加加载到configuration的variables和当前XpathParser的variables中。准备给后续的表达式进行赋值,这一步需要最先进行解析,值得注意的是url和resource属性只能设置一个。
 private void propertiesElement(XNode context) throws Exception {
    if (context != null) {
      Properties defaults = context.getChildrenAsProperties();
      String resource = context.getStringAttribute("resource");
      String url = context.getStringAttribute("url");
      if (resource != null && url != null) {
        throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other.");
      }
      if (resource != null) {
        defaults.putAll(Resources.getResourceAsProperties(resource));
      } else if (url != null) {
        defaults.putAll(Resources.getUrlAsProperties(url));
      }
      Properties vars = configuration.getVariables();
      if (vars != null) {
        defaults.putAll(vars);
      }
      parser.setVariables(defaults);
      configuration.setVariables(defaults);
    }
  }


4.2 解析 <setting>节点
流程和解析properties一样,可以看出来 evalNode的作用就是在构造XNode,在构造XNode的过程中,调用parseAttributes对节点attribute进行解析并放入Node的attribute属性备用,接着调用parseBody对Node节点body进行解析,如果第一次getBodyData返回不为空即是文本或者CDATA节点,如果其中包含表达式使用PropertyParser.pase解析并赋值。
解析节点之后调用settingsAsProperties方法将settings中的setting节点,name和value解析为properties对象,然后调用MetaClass对Configuration进行属性检查,如果在Configuration中没有的属性,则抛出异常。在解析的过程中第一步调用getChildren()和getChildrenAsProperties方法将所有子节点返回。然后调用MetaClass.forClass工厂方法构造指定Configuration类型的Reflector和reflectorFactory,reflectorFactory是Reflector的缓存,Reflector则包含了对getter setter field 的封装,初始化这两个对象后作为MetaClass的私有属性,MetaClass则对reflector进行进一步的封装。下面在Metaclass中对setting节点进行检查是否有对应的 setter方法
 public boolean hasSetter(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      if (reflector.hasSetter(prop.getName())) {
        MetaClass metaProp = metaClassForProperty(prop.getName());
        return metaProp.hasSetter(prop.getChildren());
      } else {
        return false;
      }
    } else {
      return reflector.hasSetter(prop.getName());
    }
  }

4.3加载定义VFS
loadCustomVfs(settings);

private void loadCustomVfs(Properties props) throws ClassNotFoundException {
    String value = props.getProperty("vfsImpl");
    if (value != null) {
      String[] clazzes = value.split(",");
      for (String clazz : clazzes) {
        if (!clazz.isEmpty()) {
          @SuppressWarnings("unchecked")
          Class<? extends VFS> vfsImpl = (Class<? extends VFS>)Resources.classForName(clazz);
          configuration.setVfsImpl(vfsImpl);
        }
      }
    }
  }

//TODO 等后面用到VFS在进行添加
4.4 加载 类型别名typeAliases
   typeAliasesElement(root.evalNode("typeAliases"));

扫描该节点下的子节点如果子节点名称是package则扫描这个包下面所有的类,每一个在包 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。如果不是package则默认对每个
  <typeAlias alias="Author" type="domain.blog.Author"/>
进行添加。
 private void typeAliasesElement(XNode parent) {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          String typeAliasPackage = child.getStringAttribute("name");
          configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
        } else {
          String alias = child.getStringAttribute("alias");
          String type = child.getStringAttribute("type");
          try {
            Class<?> clazz = Resources.classForName(type);
            if (alias == null) {
              typeAliasRegistry.registerAlias(clazz);
            } else {
              typeAliasRegistry.registerAlias(alias, clazz);
            }
          } catch (ClassNotFoundException e) {
            throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
          }
        }
      }
    }
  }

在进行扫描包的过程中
  public void registerAliases(String packageName){
    registerAliases(packageName, Object.class);
  }

  public void registerAliases(String packageName, Class<?> superType){
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
    resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
    Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
    for(Class<?> type : typeSet){
      // Ignore inner classes and interfaces (including package-info.java)
      // Skip also inner classes. See issue #6
      if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
        registerAlias(type);
      }
    }
  }

ResolverUtil能根据相应的条件(某个类的超类,子类,注解等)在指定路径下查找对应满足条件的所有类加载到matches这个set中。
public class ResolverUtil<T> {
  /*
   * An instance of Log to use for logging in this class.
   */
  private static final Log log = LogFactory.getLog(ResolverUtil.class);

  /**
   * A simple interface that specifies how to test classes to determine if they
   * are to be included in the results produced by the ResolverUtil.
   */
  public interface Test {
    /**
     * Will be called repeatedly with candidate classes. Must return True if a class
     * is to be included in the results, false otherwise.
     */
    boolean matches(Class<?> type);
  }

  /**
   * A Test that checks to see if each class is assignable to the provided class. Note
   * that this test will match the parent type itself if it is presented for matching.
   */
  public static class IsA implements Test {
    private Class<?> parent;

    /** Constructs an IsA test using the supplied Class as the parent class/interface. */
    public IsA(Class<?> parentType) {
      this.parent = parentType;
    }

    /** Returns true if type is assignable to the parent type supplied in the constructor. */
    @Override
    public boolean matches(Class<?> type) {
      return type != null && parent.isAssignableFrom(type);
    }

    @Override
    public String toString() {
      return "is assignable to " + parent.getSimpleName();
    }
  }

  /**
   * A Test that checks to see if each class is annotated with a specific annotation. If it
   * is, then the test returns true, otherwise false.
   */
  public static class AnnotatedWith implements Test {
    private Class<? extends Annotation> annotation;

    /** Constructs an AnnotatedWith test for the specified annotation type. */
    public AnnotatedWith(Class<? extends Annotation> annotation) {
      this.annotation = annotation;
    }

    /** Returns true if the type is annotated with the class provided to the constructor. */
    @Override
    public boolean matches(Class<?> type) {
      return type != null && type.isAnnotationPresent(annotation);
    }

    @Override
    public String toString() {
      return "annotated with @" + annotation.getSimpleName();
    }
  }

  /** The set of matches being accumulated. */
  private Set<Class<? extends T>> matches = new HashSet<Class<? extends T>>();

  /**
   * The ClassLoader to use when looking for classes. If null then the ClassLoader returned
   * by Thread.currentThread().getContextClassLoader() will be used.
   */
  private ClassLoader classloader;

  /**
   * Provides access to the classes discovered so far. If no calls have been made to
   * any of the {@code find()} methods, this set will be empty.
   *
   * @return the set of classes that have been discovered.
   */
  public Set<Class<? extends T>> getClasses() {
    return matches;
  }

  /**
   * Returns the classloader that will be used for scanning for classes. If no explicit
   * ClassLoader has been set by the calling, the context class loader will be used.
   *
   * @return the ClassLoader that will be used to scan for classes
   */
  public ClassLoader getClassLoader() {
    return classloader == null ? Thread.currentThread().getContextClassLoader() : classloader;
  }

  /**
   * Sets an explicit ClassLoader that should be used when scanning for classes. If none
   * is set then the context classloader will be used.
   *
   * @param classloader a ClassLoader to use when scanning for classes
   */
  public void setClassLoader(ClassLoader classloader) {
    this.classloader = classloader;
  }

  /**
   * Attempts to discover classes that are assignable to the type provided. In the case
   * that an interface is provided this method will collect implementations. In the case
   * of a non-interface class, subclasses will be collected.  Accumulated classes can be
   * accessed by calling {@link #getClasses()}.
   *
   * @param parent the class of interface to find subclasses or implementations of
   * @param packageNames one or more package names to scan (including subpackages) for classes
   */
  public ResolverUtil<T> findImplementations(Class<?> parent, String... packageNames) {
    if (packageNames == null) {
      return this;
    }

    Test test = new IsA(parent);
    for (String pkg : packageNames) {
      find(test, pkg);
    }

    return this;
  }

  /**
   * Attempts to discover classes that are annotated with the annotation. Accumulated
   * classes can be accessed by calling {@link #getClasses()}.
   *
   * @param annotation the annotation that should be present on matching classes
   * @param packageNames one or more package names to scan (including subpackages) for classes
   */
  public ResolverUtil<T> findAnnotated(Class<? extends Annotation> annotation, String... packageNames) {
    if (packageNames == null) {
      return this;
    }

    Test test = new AnnotatedWith(annotation);
    for (String pkg : packageNames) {
      find(test, pkg);
    }

    return this;
  }

  /**
   * Scans for classes starting at the package provided and descending into subpackages.
   * Each class is offered up to the Test as it is discovered, and if the Test returns
   * true the class is retained.  Accumulated classes can be fetched by calling
   * {@link #getClasses()}.
   *
   * @param test an instance of {@link Test} that will be used to filter classes
   * @param packageName the name of the package from which to start scanning for
   *        classes, e.g. {@code net.sourceforge.stripes}
   */
  public ResolverUtil<T> find(Test test, String packageName) {
    String path = getPackagePath(packageName);

    try {
      List<String> children = VFS.getInstance().list(path);
      for (String child : children) {
        if (child.endsWith(".class")) {
          addIfMatching(test, child);
        }
      }
    } catch (IOException ioe) {
      log.error("Could not read package: " + packageName, ioe);
    }

    return this;
  }

  /**
   * Converts a Java package name to a path that can be looked up with a call to
   * {@link ClassLoader#getResources(String)}.
   * 
   * @param packageName The Java package name to convert to a path
   */
  protected String getPackagePath(String packageName) {
    return packageName == null ? null : packageName.replace('.', '/');
  }

  /**
   * Add the class designated by the fully qualified class name provided to the set of
   * resolved classes if and only if it is approved by the Test supplied.
   *
   * @param test the test used to determine if the class matches
   * @param fqn the fully qualified name of a class
   */
  @SuppressWarnings("unchecked")
  protected void addIfMatching(Test test, String fqn) {
    try {
      String externalName = fqn.substring(0, fqn.indexOf('.')).replace('/', '.');
      ClassLoader loader = getClassLoader();
      if (log.isDebugEnabled()) {
        log.debug("Checking to see if class " + externalName + " matches criteria [" + test + "]");
      }

      Class<?> type = loader.loadClass(externalName);
      if (test.matches(type)) {
        matches.add((Class<T>) type);
      }
    } catch (Throwable t) {
      log.warn("Could not examine class '" + fqn + "'" + " due to a " +
          t.getClass().getName() + " with message: " + t.getMessage());
    }
  }
}

ResolverUtil有一个接口Test 以及IsA、AnnotatedWith两个实现类,IsA的matches表示当前类是传入类的父亲,AnnotatedWith的matches表示当前是否标注指定注解,classloader属性是一个单独的属性,用来加载查找到后的类,没有设置则默认为
Thread.currentThread().getContextClassLoader()

 
public ResolverUtil<T> findImplementations(Class<?> parent, String... packageNames) 
  public ResolverUtil<T> findAnnotated(Class<? extends Annotation> annotation, String... packageNames) 
  public ResolverUtil<T> find(Test test, String packageName) 



findImplementations和findAnnotated都会调用find进行类的加载和查找,其中find方法调用VFS查询指定包下面的所有子路径,找出class结尾的路径后调用addIfMatching方法,addIfMatching负责对类进行加载校验并添加到matches集合后,供getClasses方法返回。
4.5 加载插件
      pluginElement(root.evalNode("plugins"));

注:从4.3开始不在对evalNode方法进行跟踪
首先遍历子节点,获取interceptor属性,即包名resolveClass方法最终会调用BaseBuilder的typeAliasRegistry的resolveAlias方法,这个方法会对先检查是否已经存在此别名,不存在则使用Resources进行加载。继续读取interceptor节点的property子节点,并设置到Inteceptor中,在最后添加到Configuration中的拦截器链中。
 private void pluginElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        String interceptor = child.getStringAttribute("interceptor");
        Properties properties = child.getChildrenAsProperties();
        Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
        interceptorInstance.setProperties(properties);
        configuration.addInterceptor(interceptorInstance);
      }
    }
  }

4.6 加载objectFactory
      objectFactoryElement(root.evalNode("objectFactory"));

这部分逻辑和加载plugin类似

  private void objectFactoryElement(XNode context) throws Exception {
    if (context != null) {
      String type = context.getStringAttribute("type");
      Properties properties = context.getChildrenAsProperties();
      ObjectFactory factory = (ObjectFactory) resolveClass(type).newInstance();
      factory.setProperties(properties);
      configuration.setObjectFactory(factory);
    }
  }
值得注意的是如果配置了对象工厂会覆盖Configuration中默认配置的DefaultObjectFactory
4.7 加载objectWrapperFactory和上面类似
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));

 private void objectWrapperFactoryElement(XNode context) throws Exception {
    if (context != null) {
      String type = context.getStringAttribute("type");
      ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).newInstance();
      configuration.setObjectWrapperFactory(factory);
    }
  }

4.8 加载reflectorFactory 反射工厂,和上面类似
      reflectorFactoryElement(root.evalNode("reflectorFactory"));

 private void reflectorFactoryElement(XNode context) throws Exception {
    if (context != null) {
       String type = context.getStringAttribute("type");
       ReflectorFactory factory = (ReflectorFactory) resolveClass(type).newInstance();
       configuration.setReflectorFactory(factory);
    }
  }

4.9 加载settings
  settingsElement(settings);

这部分就是对settings下面的子节点进行解析写入到Configuration中
4.10 加载environments,事务工厂和数据源的初始化

 
environmentsElement(root.evalNode("environments"));

 private void environmentsElement(XNode context) throws Exception {
    if (context != null) {
      if (environment == null) {
        environment = context.getStringAttribute("default");
      }
      for (XNode child : context.getChildren()) {
        String id = child.getStringAttribute("id");
        if (isSpecifiedEnvironment(id)) {
          TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
          DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
          DataSource dataSource = dsFactory.getDataSource();
          Environment.Builder environmentBuilder = new Environment.Builder(id)
              .transactionFactory(txFactory)
              .dataSource(dataSource);
          configuration.setEnvironment(environmentBuilder.build());
        }
      }
    }
  }

4.11 解析databaseIdProvider,根据不同的数据库标识使用不同的映射语句
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));

如果配置了 type=VENDOR(英文释义:厂商)当前只有这一个值,首先获取节点的properties,再构造DatabaseProvider的实例,在
    typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
Configuration初始化的时候就已经默认注册了此别名,前面也说道resolveClass最终会调用typeAliasRegistry的resolveAlias方法查找和创建实例,VendorDatabaseIdProvider是DatabaseIdProvider接口的唯一实例,可自定义覆盖掉configuration中的配置,VendorDatabaseIdProvider的实现很简单,传入数据源获取Connection获取connection元数据信息,如果getDatabaseProductName返回的数据和在<property>子节点定义的name一致则返回property对应的value,例如:如果配置 <property name="Oracle" value="oracle" /> ,如果 getDatabaseProductName() 返回“Oracle (DataDirect)”,databaseId 将被设置为“oracle”。
最后将configuration中的databaseId设置为这个时候获取到的"oracle"或是mysql 就可以在update,delete 等语句中进行指定。
 private void databaseIdProviderElement(XNode context) throws Exception {
    DatabaseIdProvider databaseIdProvider = null;
    if (context != null) {
      String type = context.getStringAttribute("type");
      // awful patch to keep backward compatibility
      if ("VENDOR".equals(type)) {
          type = "DB_VENDOR";
      }
      Properties properties = context.getChildrenAsProperties();
      databaseIdProvider = (DatabaseIdProvider) resolveClass(type).newInstance();
      databaseIdProvider.setProperties(properties);
    }
    Environment environment = configuration.getEnvironment();
    if (environment != null && databaseIdProvider != null) {
      String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
      configuration.setDatabaseId(databaseId);
    }
  }

public class VendorDatabaseIdProvider implements DatabaseIdProvider {
  
  private static final Log log = LogFactory.getLog(VendorDatabaseIdProvider.class);

  private Properties properties;

  @Override
  public String getDatabaseId(DataSource dataSource) {
    if (dataSource == null) {
      throw new NullPointerException("dataSource cannot be null");
    }
    try {
      return getDatabaseName(dataSource);
    } catch (Exception e) {
      log.error("Could not get a databaseId from dataSource", e);
    }
    return null;
  }

  @Override
  public void setProperties(Properties p) {
    this.properties = p;
  }

  private String getDatabaseName(DataSource dataSource) throws SQLException {
    String productName = getDatabaseProductName(dataSource);
    if (this.properties != null) {
      for (Map.Entry<Object, Object> property : properties.entrySet()) {
        if (productName.contains((String) property.getKey())) {
          return (String) property.getValue();
        }
      }
      // no match, return null
      return null;
    }
    return productName;
  }

  private String getDatabaseProductName(DataSource dataSource) throws SQLException {
    Connection con = null;
    try {
      con = dataSource.getConnection();
      DatabaseMetaData metaData = con.getMetaData();
      return metaData.getDatabaseProductName();
    } finally {
      if (con != null) {
        try {
          con.close();
        } catch (SQLException e) {
          // ignored
        }
      }
    }
  }
  
}

  <select id="SelectTime"   resultType="String" databaseId="mysql">
   SELECT  NOW() FROM dual 
  </select>

  <select id="SelectTime"   resultType="String" databaseId="oracle">
   SELECT  'oralce'||to_char(sysdate,'yyyy-mm-dd hh24:mi:ss')  FROM dual 
  </select>


4.12  加载typeHandlers
private void typeHandlerElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          String typeHandlerPackage = child.getStringAttribute("name");
          typeHandlerRegistry.register(typeHandlerPackage);
        } else {
          String javaTypeName = child.getStringAttribute("javaType");
          String jdbcTypeName = child.getStringAttribute("jdbcType");
          String handlerTypeName = child.getStringAttribute("handler");
          Class<?> javaTypeClass = resolveClass(javaTypeName);
          JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
          Class<?> typeHandlerClass = resolveClass(handlerTypeName);
          if (javaTypeClass != null) {
            if (jdbcType == null) {
              typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
            } else {
              typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
            }
          } else {
            typeHandlerRegistry.register(typeHandlerClass);
          }
        }
      }
    }
  }


如果typehandlers子节点有package获取名称属性调用
 public void register(String packageName) {
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
    resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
    Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();
    for (Class<?> type : handlerSet) {
      //Ignore inner classes and interfaces (including package-info.java) and abstract classes
      if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
        register(type);
      }
    }
  }

进行扫描resolverUtil上面有讲到,否则挨个的进行注册。
分享到:
评论

相关推荐

    mybatis代码自动生成工具mybatis-generator-core-1.3.2

    1. **mybatis-generator-core.jar**:这是Mybatis Generator的主要实现,包含了所有生成代码所需的核心类和资源。运行时,你需要这个JAR文件在类路径中。 2. **Mysql数据库驱动**:压缩包内预装了Mysql的JDBC驱动,...

    spring-boot-starter-mybatis-spring-boot-1.2.2.tar.gz

    综上所述,Spring Boot 1.2.2集成MyBatis是一个相对简单的流程,通过引入起步依赖、配置数据源和MyBatis,以及创建Mapper接口,开发者可以快速构建起数据库操作的基础设施。虽然随着版本的更新,Spring Boot的集成...

    跑通的Mybatis后端源码-WhenToMint

    总之,"跑通的Mybatis后端源码-WhenToMint"项目提供了一个实际运行的Mybatis应用示例,通过学习和分析这个项目,你可以深入理解Mybatis的工作原理,以及如何在实际项目中使用Mybatis进行数据库操作。同时,良好的...

    mybatis-generator-core-1.3.2.zip

    MyBatis Generator的主要工作原理是通过读取数据库元数据,然后根据预设的模板生成相应的Java源代码和XML配置文件。这样,开发者就可以避免手动编写重复性的代码,从而节省大量时间,提高开发效率。 **主要组件和...

    lijie_study-mybatis-3-master.zip

    在"lijie_study-mybatis-3-master.zip"这个压缩包中,包含了MyBatis 3项目的源码,这为我们深入理解MyBatis的工作原理提供了宝贵的资料。以下是关于MyBatis核心知识点的详细解析: 1. **配置文件**: - `mybatis-...

    Mybatis源码分析-上课笔记1

    1. **Configuration**:这是MyBatis的核心配置对象,它包含了全局配置信息,如数据源、事务管理器、Mappers等。XMLConfigBuilder类负责解析`mybatis-config.xml`文件,构建Configuration实例。 2. **...

    Mybatis专栏代码

    在mybatis-springboot-demo中,我们将学习如何配置Spring Boot的启动器、添加Mybatis依赖、配置Mybatis的主配置文件(mybatis-config.xml)、Mapper接口以及XML映射文件。此外,还会涉及到实体类、Service层、...

    Mybatis-Generator工程源代码

    1. **添加依赖**:在项目的pom.xml文件中,我们需要引入Mybatis-Generator的Maven依赖。这确保了在构建过程中,可以调用到相应的库来执行代码生成。 2. **创建配置文件**:创建一个XML配置文件,如generatorConfig....

    深入浅出Mybatis原理与实战

    总结来说,深入理解MyBatis原理与实战,意味着你需要掌握其核心组件的工作机制、XML映射文件的编写、注解的应用、执行流程、缓存机制以及插件的使用。这将帮助你在实际项目中更高效、更灵活地管理数据库操作,提升...

    Spring Mybatis Sharding-JDBC demo

    1. **简化开发流程**:Spring 框架本身提供了丰富的功能支持,如事务管理、依赖注入等,集成 Sharding-JDBC 后可以进一步简化数据分片逻辑的实现。 2. **提高代码可维护性**:通过 Spring 的管理机制,能够更方便地...

    02-02-02-MyBatis体系结构与工作原理1

    在深入理解 MyBatis 的工作原理和体系结构之前,我们需要先回顾一下其基本工作流程。 1. **启动与配置解析**: 当 MyBatis 启动时,首要任务是解析配置文件,包括全局配置文件(mybatis-config.xml)和映射器配置...

    SpringBoot+Mybatis demo源码学习

    1. 添加Mybatis和相关依赖:在`pom.xml`文件中,我们需要添加Mybatis、Mybatis-Spring-Boot-Starter以及数据库驱动的依赖。 2. 配置Mybatis:在`application.properties`或`application.yml`文件中,配置数据源(如...

    springboot+shiro+mybatis-plus.7z

    在IT行业中,SpringBoot、Shiro和MyBatis-Plus是三个非常重要的开源框架,它们分别专注于应用开发的快速启动、权限管理和数据操作。在这个"springboot+shiro+mybatis-plus.7z"的压缩包中,提供了一个集成这三个框架...

    mybatis原理demo

    在深入理解MyBatis的原理之前,我们先来看一下MyBatis的主要组成部分: 1. SQL Mapper XML 文件:这是MyBatis的核心配置文件,它包含了SQL语句的定义、参数映射和结果映射。通过XML配置,我们可以灵活地定制SQL,...

    springBoot_Mybatis.zip

    SpringBoot以其简洁的配置和快速的启动能力深受开发者喜爱,而Mybatis作为轻量级的持久层框架,提供了灵活的SQL操作,使得数据库访问更为便捷。将两者进行整合,能够构建出高效、易维护的Web应用。本篇文章将深入...

    MyBatis 的执行流程.pdf

    MyBatis是一款优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动...了解这一流程有助于更好地掌握MyBatis的工作原理,从而在实际开发中更加高效地使用MyBatis框架。

    springboot+mybatis 整合Demo下载

    2. **MyBatis简介**: MyBatis是一个轻量级的ORM(对象关系映射)框架,它允许开发者编写SQL语句并与Java对象进行绑定,避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis提供了动态SQL的功能,使得...

    Mybatis系列教程Mybatis架构原理共4页.pdf

    【标题】:Mybatis系列教程Mybatis架构原理共4页.pdf 【描述】:这个压缩文件包含了一份关于Mybatis架构原理的系列教程,总计四页的内容。Mybatis是一款优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。...

    ssm-mybatis.zip )

    通过"ssm-mybatis.zip"这个项目,你可以快速地学习和理解SSM框架的工作原理,以及如何在实际开发中整合和运用这三个组件。这个项目可以作为初学者的入门示例,也可以作为资深开发者快速启动新项目的模板。

    MyBatis-MapperScannerConfigurer配合

    本文将深入探讨MapperScannerConfigurer的工作原理、使用方法及其与MyBatis的配合。 首先,理解MapperScannerConfigurer的基本概念。MapperScannerConfigurer是MyBatis-Spring扩展中的一个类,它的主要功能是在应用...

Global site tag (gtag.js) - Google Analytics