您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關springboot中怎么配置AutoConfiguration,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
在啟動類上增加注解@EnableAutoConfiguration或者@SpringBootApplication,注意:如果使用@SpringBootApplication同時會默認開啟@ComponentScan。
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; /** * Exclude specific auto-configuration classes such that they will never be applied. * @return the classes to exclude */ Class<?>[] exclude() default {}; /** * Exclude specific auto-configuration class names such that they will never be * applied. * @return the class names to exclude * @since 1.3.0 */ String[] excludeName() default {};}
從源碼上看,@EnableAutoConfiguration 引入了 1)@AutoConfigurationPackage注解 2)AutoConfigurationImportSelector.class
我們先看看AutoConfigurationImportSelector.class類的實現,@AutoConfigurationPackage注解稍后再解讀。
AutoConfigurationImportSelector是繼承的DeferredImportSelector,并且使用@Import注解導入的(具體可以查看springboot之@Import注解)。所以,我們主要看 selectImports 方法的實現。
@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { //判斷是否開啟自動配置,默認開啟,可以使用spring.boot.enableautoconfiguration=false關閉自動配置 return NO_IMPORTS; } AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}
從源碼可以看出,先檢查了一下是否開啟自動配置,然后獲取所有自動配置的類路徑,并返回。進一步查看getAutoConfigurationEntry方法。
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { //1)再次判斷是否開啟自動配置 return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); //2)獲取注解信息 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); //3)獲取所有自動配置的類 configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); //4)獲取需要排除掉的自動配置類 checkExcludedClasses(configurations, exclusions); //5)校驗需要排除的類是否存在,如果不存在,拋出異常 configurations.removeAll(exclusions); //6)過濾掉需要排除的類 configurations = getConfigurationClassFilter().filter(configurations); //7)通過配置的filter過濾掉需要排除的類 fireAutoConfigurationImportEvents(configurations, exclusions); //8) 通知自動配置listener,AutoConfigurationImportListener return new AutoConfigurationEntry(configurations, exclusions); //9)返回最終需要自動配置的類}
主要看一下getCandidateConfigurations方法實現:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); //使用spring通用工廠加載 Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations;}
最終返回給DeferredImportSelector的自動配置類列表,是通過SpringFactoriesLoader通用工廠加載的,SpringFactoriesLoader會掃描classpath下的所有 META-INF/spring.factories 文件,并通過key-value鍵值對的方式獲取配置。而我們autoconfig功能使用的key=org.springframework.boot.autoconfigure.EnableAutoConfiguration。如下圖:
所以,如果我們自己需要實現autoconfig,只需要在classpath路徑下新建一個文件META-INF/spring.factories,并加上org.springframework.boot.autoconfigure.EnableAutoConfiguration=實現類,即可。
現在,回過頭來,我們看下@EnableAutoConfiguration上的@AutoConfigurationPackage注解的作用。
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Import(AutoConfigurationPackages.Registrar.class)public @interface AutoConfigurationPackage { String[] basePackages() default {}; Class<?>[] basePackageClasses() default {};}
查看源碼可以看到,@AutoConfigurationPackage注解上import了AutoConfigurationPackages.Registrar.class。
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0])); // 1)初始化 PackageImports 2)注冊bean } @Override public Set<Object> determineImports(AnnotationMetadata metadata) { return Collections.singleton(new PackageImports(metadata)); } }
源碼可以看出,實現了ImportBeanDefinitionRegistrar,并注冊了一個PackageImports。
PackageImports(AnnotationMetadata metadata) { AnnotationAttributes attributes = AnnotationAttributes .fromMap(metadata.getAnnotationAttributes(AutoConfigurationPackage.class.getName(), false)); // 獲取注解屬性 List<String> packageNames = new ArrayList<>(); for (String basePackage : attributes.getStringArray("basePackages")) { packageNames.add(basePackage); // basePackages屬性不為空時,設置配置的包路徑 } for (Class<?> basePackageClass : attributes.getClassArray("basePackageClasses")) { packageNames.add(basePackageClass.getPackage().getName()); // basePackageClasses屬性不為空時,設置該類的包路徑 } if (packageNames.isEmpty()) { packageNames.add(ClassUtils.getPackageName(metadata.getClassName())); // 默認設置啟動類的包路徑 } this.packageNames = Collections.unmodifiableList(packageNames);}
從源碼可以看出,在初始化PackageImports時,默認會設置啟動類路徑。
我們繼續看下regsiter注冊的方法。
public static void register(BeanDefinitionRegistry registry, String... packageNames) { if (registry.containsBeanDefinition(BEAN)) { BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN); ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues(); constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames)); } else { GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(BasePackages.class); beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(BEAN, beanDefinition); } }
入參packageNames是剛剛創建的PackageImports對象里面設置的包路徑,regsiter方法主要內容是,將獲取到的包路徑,初始化為BasePackages.class類的對象,并注冊到容器中。
那么問題來了,BasePackages注冊到容器中之后,到底有什么用呢?
查看AutoConfigurationPackages類源碼,能發現以下方法:
public static List<String> get(BeanFactory beanFactory) { try { return beanFactory.getBean(BEAN, BasePackages.class).get(); } catch (NoSuchBeanDefinitionException ex) { throw new IllegalStateException("Unable to retrieve @EnableAutoConfiguration base packages"); } }
這個靜態方法就是獲取剛剛注冊的BasePackages對象,里面保存了獲取到的類路徑。
根據方法引用可以看出,在MybatisAutoConfiguration、Neo4jDataAutoConfiguration、CassandraDataAutoConfiguration等自動配置類有使用。
查看具體源碼可以看出,使用場景為:當某些組件需要自動掃描時,可以使用該包路徑為掃描的根路徑。MybatisAutoConfiguration示例如下:
1)AutoConfig功能是通過SpringFactoriesLoader通用工廠加載實現的,配置文件為META-INF/spring.factories
2)@AutoConfigurationPackage注解是向容器中注冊需要掃描的根目錄信息(默認啟動類包路徑,可配置),當某些組件需要自動掃描時,可以使用該包路徑為掃描的根路徑。
上述就是小編為大家分享的springboot中怎么配置AutoConfiguration了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。