mybatis explore the source notes 2 (build SqlSession and get proxy mapper)

Foreword

  Part of our success notes loaded Configuration, and writes the information of all we need. According to this Configuration created DefaultSqlSessionFactory. This article, we realize build a sql session SqlSession That mybatis and get into our usual proxy mapper interface class. Before the first piece of code placed before the body

  

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @GetMapping("/get")
    public List<AssetInfo> get(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        AssetInfoMapper mapper = sqlSession.getMapper(AssetInfoMapper.class);
        List<AssetInfo> test = mapper.get("测试删除" , "123123123");
        System.out.println(test);
        return test;
    }
public interface AssetInfoMapper {
    List<AssetInfo> get(@Param("name") String name, @Param("id")String id);
}
<?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="com.mapper.AssetInfoMapper">
    <select id="get" resultType="com.entity.AssetInfo">
        select  * from asset_info where id =#{id} and `name` = #{name}
    </select>
</mapper>

  This is considered a more classic case of mybatis execution, according to SqlSessionFactory get to SqlSession, and then build a proxy class specifies the mapper interface, and end up calling execute the corresponding xml sql, packaging and return the results to return. This article is based on this case to illustrate. Note that this SqlSessionFactory That is our first step in the final build DefaultSqlSessionFactory

 

text

1.sqlSessionFactory.openSession();

  According to the code map can get to know that we are SqlSession According to this method, we look at the main contents of the method. Conducted a number of overloaded methods, we look directly at the final approach

/ * 
 * ExecType Actuator Type Default passed the ExecutorType.SIMPLE; 
 * default isolation level level things pass null 
 * autoCommit things to submit it automatically defaults to false 
 * * / 
Private SqlSession openSessionFromDataSource (ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { 
  tx Transaction = null ;
   the try {
     // obtain the current environment configuration settings database which contains environmental information and things id information
     // when we have constructed a building of environment 
    Final environment environment = configuration.getEnvironment ();
     / / environment get their things level according to the environment if it is empty or is empty things level default ManagedTransactionFactory return,
     //So we will use the integrated use of SPring Spring things Manager SpringManagedTransactionFactory 
    Final TransactionFactory TransactionFactory = getTransactionFactoryFromEnvironment (Environment);
     // According to the data source, the isolation level things, submit it automatically generates thing manager here will generate Spring things SpringManagedTransaction 
    tx = TransactionFactory. newTransaction (environment.getDataSource (), Level, the autoCommit);
     // category generating the actuator and actuator in accordance things
     // Since the secondary cache turned on by default so SimpleExecutor here will be packaged as CacheExecutor 
    Final the executor executor = configuration.newExecutor (TX , execType);
     // returns DefaultSqlSession 
    return  new new DefaultSqlSession (Configuration, Executor, the autoCommit); 
  } the catch(Exception E) {
       // capture the exception of the closing things 
    closeTransaction (TX); // On May SO lets have have fetched A Call Connection Close () 
    the throw ExceptionFactory.wrapException ( "Error Opening the session the Cause:." + E, E); 
  } the finally { 
    ErrorContext.instance () RESET ();. 
  } 

}

  Important operations of the method has two steps, the first step is to obtain according to Environment we set the corresponding things, a second step is to construct things and executor Executor according to the type. Two steps of the code we have a look.

  The first step  method to get things in the factory to see if we can not set Environment, or Environment is not something the factory, will produce a default, in this case using a Spring thing factory. Finally, of course, also have a SpringManagedTransaction

  private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
    if (environment == null || environment.getTransactionFactory() == null) {
      return new ManagedTransactionFactory();
    }
    return environment.getTransactionFactory();
  }
public class SpringManagedTransactionFactory implements TransactionFactory {
    ...
    public Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) {
        return new SpringManagedTransaction(dataSource);
    }
    ...
}

   The second step is configured the Executor, here, that is, whether empty, then select the corresponding processor, here selected common actuator, and the package is about CacheExecutor , here will remember the last executed once all plugin method interceptors can interceptor in Executor to do their own processing

public Executor newExecutor (Transaction Transaction, ExecutorType ExecutorType) {
   // if null is set as the default type that is ExecutorType.SIMPLE 
  ExecutorType = ExecutorType == null ? defaultExecutorType: ExecutorType;
   // if the default or is null (config the default type is modified) is then manually set ExecutorType.SIMPLE 
  ExecutorType = ExecutorType == null ? ExecutorType.SIMPLE: ExecutorType; 
  the Executor Executor; 
  // batch mode of operation 
  IF (ExecutorType.BATCH == ExecutorType) { 
    Executor = new new BatchExecutor ( the this , Transaction); 
  } 
  // reuse PreparedStatements
  the else  if (ExecutorType.REUSE == ExecutorType) { 
    Executor = new new ReuseExecutor ( the this , Transaction); 
  } 
  // Common actuators 
  the else { 
    Executor = new new SimpleExecutor ( the this , Transaction); 
  } 
  // if the two cache turned on by default 
  if (cacheEnabled) {
     // once packaging CachingExecutor 
    Executor = new new CachingExecutor (Executor); 
  } 
  // Note that the method here will be executed once all plugin interceptor 
  Executor = (the Executor) interceptorChain.pluginAll (Executor);
  return executor;
}

  After a two-step operation is complete we need to get to the Executor, and have passed through the reference structure, constructed and return to the default DefaultSqlSession

 

2.sqlSession.getMapper(Class<?> class)

  According to the code, we can see that the system is finally get to our agents mapper based on this method. SqlSession note here is DefaultSqlSession, we probably look at DefaultSqlSession construction

  Look under their inheritance diagram, you can see it implements the interface SqlSession, in fact, the main method we use a method that is its interface. Through the interface method may comprise a process that mainly operate things, changes, omissions and additions database search.

  We also believe that in accordance with the method name can understand the meaning. The specific methods and the like used when later re-analysis

 

   Then look at the member variable DefaultSqlSession contained

  private final Configuration configuration;
  private final Executor executor;

  private final boolean autoCommit;
  private boolean dirty;
  private List<Cursor<?>> cursorList;
  •  a configuration that is we start building the config class, which contains all the configuration information and mapper information mybatis
  • That we are here executor actuator is packed SimpleExecutor of CachingExecutor, in order to support secondary cache
  • Whether autoCommit automatically commit the transaction, the default is false
  • dirty records whether there have been changes to the operation of this process executor execution
  • When using the new features in batches reading cursorList  

  Once you understand the general structure SqlSession, we began analysis getMapper ie get mapper interfaces proxy class

2.getMapper

   Acting in accordance with 2.1 to get our build configuration

@Override
  public <T> T getMapper(Class<T> type) {
    return configuration.getMapper(type, this);
  }

     2.2 configuration acquired according to mapperRegistry.getMapper

  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }

    2.3 mapperRegistry last acquisition logic

  Private  Final the Configuration config; // initialize namely mybatis config
   Private  Final the Map <Class <>, MapperProxyFactory <>> knownMappers =?? new new HashMap <> (); // memory mapper interface and its proxy factories in the Map 
  
  @SuppressWarnings ( " an unchecked " )
   public <T> T getMapper (Class <T> type, the SqlSession SQLSESSION) {
     // storage interface which acquires MapperProxyFactory The 
    Final MapperProxyFactory <T> = mapperProxyFactory (MapperProxyFactory <T> ) knownMappers.get (type);
     IF ( == mapperProxyFactory null ) {
       the throw  new new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
        //根据MapperProxyFactory获取代理类并返回
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

    We can see, the final acquisition operation of the proxy class or use the config MapperRegistry we build in to get. The above process is the key knownMappers mapper.xml reflected in nameSpace interfaces generated class attribute, value proxy factory is constructed in accordance with the current interface. SqlSessionFactory resolve in building methods in mapper.xml file will be cached all the xml information in this knownMappers. This is the first article analysis have been analyzed, not repeat them here. This method is the final call newInstance method MapperProxyFactory, we then look

 

3.MapperProxyFactory.newInstance

 

public  class MapperProxyFactory <T> {
   // proxy factory interface corresponding 
  Private  Final Class <T> mapperInterface;
   // method corresponding cache 
  Private  Final the Map <Method,, MapperMethod> = methodCache new new of ConcurrentHashMap <> (); 

  public MapperProxyFactory (Class < T> mapperInterface) {
     the this .mapperInterface = mapperInterface; 
  } 

  public Class <T> getMapperInterface () {
     return mapperInterface; 
  } 

  public the Map <Method,, MapperMethod> getMethodCache () {
    return methodCache; 
  } 
  // The proxy class construct and return MapperProxy 
  @SuppressWarnings ( "an unchecked" )
   protected T the newInstance (MapperProxy <T> mapperProxy) {
     return (T) the Proxy.newProxyInstance (mapperInterface.getClassLoader (), new new Class [] { } mapperInterface, mapperProxy); 
  } 
  // this method is mainly constructed according to a mapperProxy passed the SqlSession 
  public T the newInstance (the SqlSession SQLSESSION) {
     Final mapperProxy <T> = mapperProxy new new mapperProxy <> (SQLSESSION, mapperInterface, methodCache);
     return the newInstance ( mapperProxy); 
  } 

}

  This class of agents that is each mapper class factory interface. Note methodCache of them, this in order to support mybatis cache created. This class has two newInstance method, according to the above it is to create a proxy incoming mapperProxy, we all know jdk create proxy need InvocationHandler a class that implements the interface as a parameter, and the following newInstance is mainly to create an implementation of the interface MapperProxy InvocationHandler instance , passed a note SqlSession, on behalf of this mapper interface, as well as caching method

 

4.MapperProxy

  We all know jdk dynamic proxy class final execution is to achieve a method of a class InvocationHandler interface. Therefore, the final inlet mapper method performed according to the type considered. Let's look at a few more core properties

  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;
  • SqlSession that is a conversation that we created
  • mapperInterface that we would interface agent
  • methodCache i.e., the cache method MethodProxyFactory

  We look at its construction method, that is, do a simple assignment

  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

  InvocationHandler this interface implementation class is created, and then return to step 3 in as a parameter passed to the method jdk dynamic proxy, the final configuration of the mapper proxy class and return to our main method.

    Below with reference to a flowchart as

 

end

  You can see, we construct through before initialization SqlSessionFactory created in addition to SqlSession, contains internal actuator Executor, and based on this we initialization to create a proxy class for the proxy class factory proxyFactory each interface created by and returned SqlSession, we mapper final the method of execution is also invoke the method mapperProxy.

  About mapper way to do that is to perform the process of mapperProxy invoke method involves the sql execution of content mybatis, this will be resolved in the next chapter

 

Guess you like

Origin www.cnblogs.com/hetutu-5238/p/12015743.html