如果有成百上千個dao接口呢,那我們豈不是要配置添加成百上千個bean,當然不是這樣,spring還為MyBatis添加了拓展的功能,可以通過掃描包目錄的方式,添加dao,讓我看看具體使用和實作。
我們屏蔽掉了最原始的代碼(userMapper 的建立)而增加了MapperScannerConfigurer的配置,basePackage屬性是讓你為映射器接口檔案設定基本的包路徑。你可以使用分号或逗号作為分隔符設定多于一個的包路徑。每個映射器将會在指定的包路徑中遞歸地被搜尋到。被發現的映射器将會使用Spring對自動偵測元件預設的命名政策來命名。也就是說,如果沒有發現注解,它就會使用映射器的非大寫的非完全限定類名。但是如果發現了@Component或JSR-330@Named注解,它會擷取名稱。
afterPropertiesSet()方法除了一句對basePackage屬性的驗證代碼外并沒有太多的邏輯實作。
MapperScannerConfigurer實作了BeanDefinitionRegistryPostProcessor接口,如果MapperScannerConfigurer實作了該接口,那麼說明在application初始化的時候該接口會被調用,具體實作,讓我先看看:
這裡我們重點關注三個主要的方法,分别是
processPropertyPlaceHolders();
scanner.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
執行屬性的處理,簡單的說,就是把xml中${XXX}中的XXX替換成屬性檔案中的相應的值
BeanDefinitionRegistries會在應用啟動的時候調用,并且會早于BeanFactoryPostProcessors的調用,這就意味着PropertyResourceConfigurers還沒有被加載所有對于屬性檔案的引用将會失效。為避免此種情況發生,此方法手動地找出定義的PropertyResourceConfigurers并進行提前調用以保證對于屬性的引用可以正常工作。
scanner.registerFilters();方法會根據配置的屬性生成對應的過濾器,然後這些過濾器在掃描的時候會起作用。
代碼中得知,根據之前屬性的配置生成了對應的過濾器。
(1)annotationClass屬性處理。
如果annotationClass不為空,表示使用者設定了此屬性,那麼就要根據此屬性生成過濾器以保證達到使用者想要的效果,而封裝此屬性的過濾器就是AnnotationTypeFilter。AnnotationTypeFilter保證在掃描對應Java檔案時隻接受标記有注解為annotationClass的接口。
(2)markerInterface屬性處理。
如果markerInterface不為空,表示使用者設定了此屬性,那麼就要根據此屬性生成過濾器以保證達到使用者想要的效果,而封裝此屬性的過濾器就是實作AssignableTypeFilter接口的局部類。表示掃描過程中隻有實作markerInterface接口的接口才會被接受。
(3)全局預設處理。
在上面兩個屬性中如果存在其中任何屬性,acceptAllInterfaces的值将會改變,但是如果使用者沒有設定以上兩個屬性,那麼,Spring會為我們增加一個預設的過濾器實作TypeFilter接口的局部類,旨在接受所有接口檔案。
(4)package-info.java處理。
對于命名為package-info的Java檔案,預設不作為邏輯實作接口,将其排除掉,使用TypeFilter接口的局部類實作match方法。
從上面的函數我們看出,控制掃描檔案Spring通過不同的過濾器完成,這些定義的過濾器記錄在了includeFilters和excludeFilters屬性中。
該方法主要做了以下操作:
1)掃描basePackage下面的java檔案
2)解析掃描到的java檔案
3)調用各個在上一步驟注冊的過濾器,執行相應的方法。
4)為解析後的java注冊bean,注冊方式采用編碼的動态注冊實作。
5)構造MapperFactoryBean的屬性,mapperInterface,sqlSessionFactory等等,填充到BeanDefinition裡面去。
做完這些,MapperFactoryBean對象也就構造完成了,掃描方式添加dao的工作也完成了。
其實了解了Spring整合MyBatis的流程,我們也就大體知道Spring整合一些架構所使用的擴充方法,不過大多是都是通過繼承接口的方式,然後通過spring回調該接口的方式,實作我們自己想要的擴充邏輯,是以了解spring提供的一些擴充的接口以及抽象類是擴充的關鍵,就像InitializingBean,BeanDefinitionRegistryPostProcessor這些接口,知道了這些接口調用的方式,以及上面時候會調用,我們就可以知道,我們需要擴充的功能應該實作哪個接口,或者內建哪個抽象類。