前文跟你們過了一遍Mybatis的執行過程,可是仍然有很多疑問點未解釋清楚,例如具體sql到底何時生成,mapper接口是如何實例化,爲什麼executor用的是SimpleExecutor等等。此次和你們一塊兒看看Mybatis是如何初始化,相信以上問題將會一一解開。java
先回顧SqlSessionFactory的初始化過程:spring
TransactionFactory transactionFactory = new JdbcTransactionFactory(); Environment environment = new Environment("dev", transactionFactory, dataSource); Configuration configuration = new Configuration(environment); configuration.addMapper(StudentMapper.class); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
public Configuration() { typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class); typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class); typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class); typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class); typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class); typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class); typeAliasRegistry.registerAlias("FIFO", FifoCache.class); typeAliasRegistry.registerAlias("LRU", LruCache.class); typeAliasRegistry.registerAlias("SOFT", SoftCache.class); typeAliasRegistry.registerAlias("WEAK", WeakCache.class); typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class); typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class); typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class); typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class); typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class); typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class); typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class); typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class); typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class); typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class); typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class); typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class); languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class); languageRegistry.register(RawLanguageDriver.class); }
先來看看TypeAliasRegistry,它在初始化的時候其實已經註冊了很多類型別名:sql
public TypeAliasRegistry() { //字符串類型 registerAlias("string", String.class); //基本包裝類型 registerAlias("byte", Byte.class); registerAlias("long", Long.class); registerAlias("short", Short.class); registerAlias("int", Integer.class); registerAlias("integer", Integer.class); registerAlias("double", Double.class); registerAlias("float", Float.class); registerAlias("boolean", Boolean.class); //基本數組包裝類型 registerAlias("byte[]", Byte[].class); registerAlias("long[]", Long[].class); registerAlias("short[]", Short[].class); registerAlias("int[]", Integer[].class); registerAlias("integer[]", Integer[].class); registerAlias("double[]", Double[].class); registerAlias("float[]", Float[].class); registerAlias("boolean[]", Boolean[].class); //基本類型 registerAlias("_byte", byte.class); registerAlias("_long", long.class); registerAlias("_short", short.class); registerAlias("_int", int.class); registerAlias("_integer", int.class); registerAlias("_double", double.class); registerAlias("_float", float.class); registerAlias("_boolean", boolean.class); //基本數組類型 registerAlias("_byte[]", byte[].class); registerAlias("_long[]", long[].class); registerAlias("_short[]", short[].class); registerAlias("_int[]", int[].class); registerAlias("_integer[]", int[].class); registerAlias("_double[]", double[].class); registerAlias("_float[]", float[].class); registerAlias("_boolean[]", boolean[].class); //日期數字型 registerAlias("date", Date.class); registerAlias("decimal", BigDecimal.class); registerAlias("bigdecimal", BigDecimal.class); registerAlias("biginteger", BigInteger.class); registerAlias("object", Object.class); registerAlias("date[]", Date[].class); registerAlias("decimal[]", BigDecimal[].class); registerAlias("bigdecimal[]", BigDecimal[].class); registerAlias("biginteger[]", BigInteger[].class); registerAlias("object[]", Object[].class); //集合型 registerAlias("map", Map.class); registerAlias("hashmap", HashMap.class); registerAlias("list", List.class); registerAlias("arraylist", ArrayList.class); registerAlias("collection", Collection.class); registerAlias("iterator", Iterator.class); //結果集型 registerAlias("ResultSet", ResultSet.class); }
registerAlias方法最終是保存在HashMap裏,key=別名,value=類對象。數組
從註冊的內容中能夠看出,類型別名主要用於取代複雜的類型全限定名,因爲Mybatis支持xml和註解配置,配置通常以字符串形式鍵入,使用類型別名能夠更加方便地進入配置,其用途或用於映射器配置文件中進行參數類型與返回結果類型的設置,或用於其它特定字符的類解析例如JDBC=JdbcTransactionFactory等等。緩存
4. 註冊具體Mapper,利用MapperRegistry對Mapper進行解析:app
knownMappers.put(type, new MapperProxyFactory<>(type)); MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); parser.parse();
首先建立Mapper代理工廠類,用於實例化Mapper;而後parser.parse()進行Mapper解析:ide
public void parse() { String resource = type.toString(); if (!configuration.isResourceLoaded(resource)) { //讀取並解析namespace的xml配置文件 loadXmlResource(); configuration.addLoadedResource(resource); assistant.setCurrentNamespace(type.getName()); //解析二級緩存註解,下同,Ref用於多個mapper之間共享緩存 parseCache(); parseCacheRef(); Method[] methods = type.getMethods(); for (Method method : methods) { try { // issue #237 if (!method.isBridge()) { //解析方法,生成MappedStatement parseStatement(method); } } catch (IncompleteElementException e) { configuration.addIncompleteMethod(new MethodResolver(this, method)); } } } //解析在parseStatement拋異常的方法 parsePendingMethods(); }
前文說過MappedStatement主要是記錄sql、輸入參數、輸出結果類型等信息,所以sql確定在parseStatement內生成:ui
void parseStatement(Method method) { //獲取參數類型,有多個時爲ParamMap(HashMap子類) Class<?> parameterTypeClass = getParameterType(method); //獲取動態語言驅動,默認使用XMLLanguageDriver LanguageDriver languageDriver = getLanguageDriver(method); //sql生成源,四種實現 SqlSource sqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver); // …… }
根據method的註解內容,生成對應的SqlSource實現類對象:this
至此,sql的生成已完成,具體的sql解析請自行查看源碼,主要仍是字符串的解析。spa