Spring-ImportSelector接口功能使用案例
ImportSelector接口是至spring中導(dǎo)入內(nèi)部類或者外部類的核心接口,只需要其定義的方法內(nèi)返回需要?jiǎng)?chuàng)建bean的class字符串就好了,比如:當(dāng)我們引入一個(gè)外部share包,我們拿到里面的Class返回出去,就能得到這個(gè)bean,是多么神奇的事情,前提是這個(gè)類不是接口哦。
ImportSelector往往結(jié)合@Import注解一起使用,可以參考我的這篇文章@Import注解介紹
public interface ImportSelector { //返回類的字符串?dāng)?shù)組,也就是要?jiǎng)?chuàng)建的bean的className,比如userService.class.getName() //被創(chuàng)建的bean是在其他bean(@Component、@Service等注解修飾的Bean)創(chuàng)建之前創(chuàng)建的 String[] selectImports(AnnotationMetadata importingClassMetadata); }
二、使用案例
通過返回Class的字符串來創(chuàng)建bean
//定義一個(gè)業(yè)務(wù)類 public class UserServiceTest { public String getUserName(){ return "測(cè)試"; } } //實(shí)現(xiàn)ImportSelector接口 public class MyImportSelect implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { //返回要注冊(cè)到Spring容器的Class集合 return new String[]{UserServiceTest.class.getName()}; } } //配置類 @Configuration @Import(MyImportSelect.class) //導(dǎo)入我們實(shí)現(xiàn)ImportSelector的類。 public class AppConfigClassTest { }
測(cè)試
public class MainTest { public static void main(String[] args) { AnnotationConfigApplicationContext AnnotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfigClassTest.class); //這里我們不能通過“userServiceTest”來獲取bean,因?yàn)檫@個(gè)bean的name不是userServiceTest,而是userServiceTest.getClass().getName() //因?yàn)閎ean的別名成功器,只是針對(duì)像注解@Service等注解,會(huì)生成一個(gè)首字母小寫的BeanName UserServiceTest userServiceTest = AnnotationConfigApplicationContext.getBean(UserServiceTest.class); System.out.println(((UserServiceTest)userServiceTest).getUserName()); } }
下面說下源碼是怎么實(shí)現(xiàn)的,可以跳轉(zhuǎn)到@Import注解介紹
//這里就直接跳到ConfigurationClassPostProcessor處理@Import注解的邏輯上 private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) { //如果importCandidates為空直接return,為什么會(huì)有這個(gè),因?yàn)橄旅娲a可能會(huì)遞歸調(diào)用processImports,就比如Import一個(gè)類,這個(gè)類也帶了@Import注解,那就會(huì)在調(diào)用一次processImports方法 if (importCandidates.isEmpty()) { return; } for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(ImportSelector.class)) { //1、import的類,實(shí)現(xiàn)了ImportSelector接口 Class<?> candidateClass = candidate.loadClass(); //利用反射Class實(shí)例化對(duì)象,這個(gè)對(duì)象不是代理對(duì)象不要搞混了。 ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry); Predicate<String> selectorFilter = selector.getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter.or(selectorFilter); } if (selector instanceof DeferredImportSelector) { this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else { //調(diào)用ImportSelector接口里面的selectImports方法,拿到返回值Class集合。在通過遞歸的方式嗲用processImports挨個(gè)解析每一個(gè)Class String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); //轉(zhuǎn)成SourceClass集合 Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); //再次調(diào)用processImports方法 processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { 。。。。。。 } else { //3、ImportSelector和ImportBeanDefinitionRegistrar都沒有實(shí)現(xiàn) this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); //進(jìn)一步解析其他注解,比如@Component @Import等最后會(huì)把configClass注冊(cè)到Spring容器中。 processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter); } } }
看下instantiateClass方法做了什么
//創(chuàng)建實(shí)例對(duì)象 static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo, Environment environment, ResourceLoader resourceLoader, BeanDefinitionRegistry registry) { ClassLoader classLoader = (registry instanceof ConfigurableBeanFactory ? ((ConfigurableBeanFactory) registry).getBeanClassLoader() : resourceLoader.getClassLoader()); T instance = (T) createInstance(clazz, environment, resourceLoader, registry, classLoader); ParserStrategyUtils.invokeAwareMethods(instance, environment, resourceLoader, registry, classLoader); return instance; } //調(diào)用createInstance方法創(chuàng)建實(shí)例對(duì)象 private static Object createInstance(Class<?> clazz, Environment environment, ResourceLoader resourceLoader, BeanDefinitionRegistry registry, @Nullable ClassLoader classLoader) { Constructor<?>[] constructors = clazz.getDeclaredConstructors(); 。。。。。。。 return BeanUtils.instantiateClass(clazz);//通過Bean的工具類生成實(shí)例對(duì)象 }
到此這篇關(guān)于Spring-ImportSelector接口功能介紹的文章就介紹到這了,更多相關(guān)Spring ImportSelector接口內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
[Spring MVC] -簡(jiǎn)單表單提交實(shí)例
本篇文章主要介紹了[Spring MVC] -簡(jiǎn)單表單提交實(shí)例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。2016-12-12一篇文章帶你搞定 springsecurity基于數(shù)據(jù)庫的認(rèn)證(springsecurity整合mybatis)
這篇文章主要介紹了一篇文章帶你搞定 springsecurity基于數(shù)據(jù)庫的認(rèn)證(springsecurity整合mybatis),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10詳解如何將已有項(xiàng)目改造為Spring Boot項(xiàng)目
本篇文章主要介紹了如何將已有項(xiàng)目改造為Spring Boot項(xiàng)目,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11Mybatis Plus查詢時(shí)sql字段名大小寫報(bào)錯(cuò)的解決
這篇文章主要介紹了Mybatis Plus查詢時(shí)sql字段名大小寫報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12SpringBoot實(shí)現(xiàn)Logback輸出日志到Kafka方式
本文介紹了如何在SpringBoot應(yīng)用中通過自定義Appender實(shí)現(xiàn)Logback輸出日志到Kafka,包括配置maven依賴、Kafka工具類和logback.xml配置2025-02-02springboot接口多實(shí)現(xiàn)類選擇性注入解決方案
這篇文章主要為大家介紹了springboot接口多實(shí)現(xiàn)類選擇性注入解決方案的四種方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03基于Spring AOP proxyTargetClass的行為表現(xiàn)總結(jié)
這篇文章主要介紹了Spring AOP proxyTargetClass的行為表現(xiàn)總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08