目的java
MyBatis的XML配置文件解析成JAVA類並在內存中存儲,可是在程序運行時須要對應的類去調用,而相應的調用類尚未實例化,如今流行的都是使用Spring去管理須要的對象,Spring提供2種方式,分別爲XML與註解。下面來分析調用類的實例化及與配置綁定。spring
1 XML方式sql
<bean id="menuMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> <property name="mapperInterface" value="cn.vansky.schedule.time.menu.dao.MenuMapper" /> </bean>
這裏相等於實例一個id爲menuMapper的對象,這個對象實際類是MapperFactoryBean,裏面包含2個屬性。當須要使用此對象時,直接使用id注入便可。下面來看看類裏面作了哪些操做?mybatis
protected void checkDaoConfig() { super.checkDaoConfig(); notNull(this.mapperInterface, "Property 'mapperInterface' is required"); Configuration configuration = getSqlSession().getConfiguration(); if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) { try { configuration.addMapper(this.mapperInterface); } catch (Throwable t) { logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", t); throw new IllegalArgumentException(t); } finally { ErrorContext.instance().reset(); } } } protected void checkDaoConfig() { notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required"); } @Autowired(required = false) public final void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { if (!this.externalSqlSession) { this.sqlSession = new SqlSessionTemplate(sqlSessionFactory); } } @Autowired(required = false) public final void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) { this.sqlSession = sqlSessionTemplate; this.externalSqlSession = true; }
自身校驗接口類不能爲空,父類校驗SqlSession不能爲空,說明SqlSessionFactory與SqlSessionTemplate必須存在一個。app
在MyBatis整合Spring的實現(17)中分析已經知道,SQL對應的Mapper文件已經解析並添加到Configuration(全局配置類)中,爲何這裏還會添加Mapper呢?由於前面分析的是對XML的解析,若是咱們的配置使用的註解方式,那麼這裏,個人Mapper是沒有解析的,當沒有解析時,這裏就會去解析註解並添加到Configuration(全局配置類)中。post
2 註解方式ui
<bean name="mapperScannerConfigurer_one" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> <property name="basePackage" value="cn.vansky.schedule.time" /> <property name="annotationClass" value="cn.vansky.framework.core.orm.mybatis.annotation.SqlMapper" /> <property name="markerInterface" value="org.mybatis.spring.mapper.MapperFactoryBean" /> </bean>
這裏使用註解方式,把包cn.vansky.schedule.time下面的全部JAVA類所有實例化,可是這樣實例的話,那麼實際類型就是對應JAVA類的類型,也就至關於下面的配置。this
<bean id="menuMapper" class="cn.vansky.schedule.time.menu.dao.MenuMapper"> </bean>
這裏若是要是直接使用id注入,那麼就調用不到MyBatis的配置,因此分析MapperScannerConfigurer類作了哪些操做?spa
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException { if (this.processPropertyPlaceHolders) { processPropertyPlaceHolders(); } Scanner scanner = new Scanner(beanDefinitionRegistry); scanner.setResourceLoader(this.applicationContext); scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); }
MapperScannerConfigurer類實現BeanDefinitionRegistryPostProcessor,須要執行postProcessBeanDefinitionRegistry方法。上圖紅框中,Spring把接口MenuMapper類的屬性修改了,使此類的實例化最終的Bean變成MapperFactoryBean並注入MapperFactoryBean類的屬性mapperInterface。也就至關於XML的配置(查看本章節1)。.net
3 BEAN注入
JAVA代碼裏面注入使用註解@Autowired,此註解默認使用類型獲取對應的對象。
這裏類型MenuMapper,而實際類型爲MapperFactoryBean,應該會出現類型轉換異常呀!
MyBatis作了進一步處理,MapperFactoryBean實現FactoryBean,必須實現getObject方法。
這裏是獲取最終的對象,mapperInterface屬性就是實際的類型MenuMapper。
SqlSession是SqlSessionTemplate,SqlSessionTemplate的getMapper方法。
經過代理工廠,實際的對象就經過代理實例化完成。最終的代理類就是MapperProxy。
總結
註解方式就是對XML的整合,把多個Bean實例化整合成一個XML配置,這樣省去多餘的配置信息,並且還提供了註解方式來配置SQL的Mapper信息。