经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
SpringBoot快速通关自动配置应用
来源:jb51  时间:2022/7/4 12:09:11  对本文有异议

@EnableAutoConfiguration

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @AutoConfigurationPackage
  6. @Import(AutoConfigurationImportSelector.class)
  7. public @interface EnableAutoConfiguration {
  8. String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
  9. Class<?>[] exclude() default {};
  10. String[] excludeName() default {};
  11. }

标注了@AutoConfigurationPackage,并且导入了AutoConfigurationImportSelector

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @Import(AutoConfigurationPackages.Registrar.class)
  6. public @interface AutoConfigurationPackage {
  7. }

@AutoConfigurationPackage注解导入了AutoConfigurationPackages.Registrar。

下面来看看这两个导入类

AutoConfigurationPackages.Registrar

这是一个内部类,外部类AutoConfigurationPackages是一个抽象类

  1. static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
  2. @Override
  3. public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
  4. //注册
  5. register(registry, new PackageImport(metadata).getPackageName());
  6. }
  7. //这个方法没有地方调用,暂不分析
  8. @Override
  9. public Set<Object> determineImports(AnnotationMetadata metadata) {
  10. return Collections.singleton(new PackageImport(metadata));
  11. }
  12. }

注册

  1. private final String packageName;
  2. PackageImport(AnnotationMetadata metadata) {
  3. this.packageName = ClassUtils.getPackageName(metadata.getClassName());
  4. }

PackageImport也是一个内部类,构造方法中赋值了一个成员变量packageName。

  1. public static String getPackageName(String fqClassName) {
  2. Assert.notNull(fqClassName, "Class name must not be null");
  3. int lastDotIndex = fqClassName.lastIndexOf(PACKAGE_SEPARATOR);
  4. return (lastDotIndex != -1 ? fqClassName.substring(0, lastDotIndex) : "");
  5. }

getPackageName方法中会根据@AutoConfigurationPackage标注类的全限定名,获取@AutoConfigurationPackage标注类的包名。

然后将@AutoConfigurationPackage标注类的包名赋值给PackageImport的成员变量packageName。

  1. String getPackageName() {
  2. return this.packageName;
  3. }

getPackageName方法只是简单的将PackageImport#packageName返回。

然后调用外部类AutoConfigurationPackages的静态方法register

  1. private static final String BEAN = AutoConfigurationPackages.class.getName();
  2. public static void register(BeanDefinitionRegistry registry, String... packageNames) {
  3. //已经注册过 BEAN 了,代表不是第一次调用AutoConfigurationPackages.Registrar
  4. if (registry.containsBeanDefinition(BEAN)) {
  5. BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
  6. ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
  7. //将这次调用AutoConfigurationPackages.Registrar,将标注@AutoConfigurationPackage 注解的类的包名添加到 BEAN 的参数中
  8. constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
  9. }
  10. else {
  11. //第一次调用AutoConfigurationPackages.Registrar,注册 BEAN
  12. GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
  13. beanDefinition.setBeanClass(BasePackages.class);
  14. //获取BasePackages构造器的参数,是个 String... ,将packageNames放到数组第一个位置
  15. beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
  16. beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
  17. registry.registerBeanDefinition(BEAN, beanDefinition);
  18. }
  19. }

注册AutoConfigurationPackages

  1. static final class BasePackages {
  2. private final List<String> packages;
  3. private boolean loggedBasePackageInfo;
  4. BasePackages(String... names) {
  5. List<String> packages = new ArrayList<>();
  6. for (String name : names) {
  7. if (StringUtils.hasText(name)) {
  8. packages.add(name);
  9. }
  10. }
  11. this.packages = packages;
  12. }
  13. List<String> get() {
  14. if (!this.loggedBasePackageInfo) {
  15. if (this.packages.isEmpty()) {
  16. if (logger.isWarnEnabled()) {
  17. ...//只是输出日志
  18. }
  19. }
  20. else {
  21. if (logger.isDebugEnabled()) {
  22. String packageNames = StringUtils.collectionToCommaDelimitedString(this.packages);
  23. ...//输出日志
  24. }
  25. }
  26. this.loggedBasePackageInfo = true;
  27. }
  28. return this.packages;
  29. }
  30. }

注册时bean的名称是上面的 BEAN,bean的类为BasePackages。

已经注册过AutoConfigurationPackages

  1. private static String[] addBasePackages(ConstructorArgumentValues constructorArguments, String[] packageNames) {
  2. //取出BasePackages构造器的参数 String...
  3. String[] existing = (String[]) constructorArguments.getIndexedArgumentValue(0, String[].class).getValue();
  4. //创建新的集合,将原有的包名和现有的包名添加进去,用set去重,然后返回
  5. Set<String> merged = new LinkedHashSet<>();
  6. merged.addAll(Arrays.asList(existing));
  7. merged.addAll(Arrays.asList(packageNames));
  8. return StringUtils.toStringArray(merged);
  9. }

AutoConfigurationImportSelector

AutoConfigurationImportSelector实现了DeferredImportSelector,DeferredImportSelector实现了ImportSelector。

  1. public String[] selectImports(AnnotationMetadata annotationMetadata) {
  2. //不起用自动装配
  3. if (!isEnabled(annotationMetadata)) {
  4. return NO_IMPORTS;
  5. }
  6. //获得AutoConfiguration的注解元数据
  7. AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
  8. .loadMetadata(this.beanClassLoader);
  9. AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
  10. annotationMetadata);
  11. return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
  12. }
  1. protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
  2. AnnotationMetadata annotationMetadata) {
  3. if (!isEnabled(annotationMetadata)) {
  4. return EMPTY_ENTRY;
  5. }
  6. //获取注解的属性
  7. AnnotationAttributes attributes = getAttributes(annotationMetadata);
  8. //获取实现EnableAutoConfiguration的类名集合
  9. List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
  10. //去重
  11. configurations = removeDuplicates(configurations);
  12. //获取要排除的类名
  13. Set<String> exclusions = getExclusions(annotationMetadata, attributes);
  14. checkExcludedClasses(configurations, exclusions);
  15. //排除
  16. configurations.removeAll(exclusions);
  17. //过滤
  18. configurations = filter(configurations, autoConfigurationMetadata);
  19. fireAutoConfigurationImportEvents(configurations, exclusions);
  20. return new AutoConfigurationEntry(configurations, exclusions);
  21. }

获取所有EnableAutoConfiguration实现类名

  1. protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
  2. //利用spi获取实现了EnableAutoConfiguration的类名集合
  3. List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
  4. getBeanClassLoader());
  5. Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
  6. + "are using a custom packaging, make sure that file is correct.");
  7. return configurations;
  8. }
  1. protected Class<?> getSpringFactoriesLoaderFactoryClass() {
  2. return EnableAutoConfiguration.class;
  3. }

去重

  1. protected final <T> List<T> removeDuplicates(List<T> list) {
  2. return new ArrayList<>(new LinkedHashSet<>(list));
  3. }

获取要排除的类名

  1. protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
  2. Set<String> excluded = new LinkedHashSet<>();
  3. excluded.addAll(asList(attributes, "exclude"));
  4. excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
  5. excluded.addAll(getExcludeAutoConfigurationsProperty());
  6. return excluded;
  7. }
  1. private List<String> getExcludeAutoConfigurationsProperty() {
  2. if (getEnvironment() instanceof ConfigurableEnvironment) {
  3. Binder binder = Binder.get(getEnvironment());
  4. return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class).map(Arrays::asList)
  5. .orElse(Collections.emptyList());
  6. }
  7. String[] excludes = getEnvironment().getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);
  8. return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList();
  9. }

过滤

  1. private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
  2. long startTime = System.nanoTime();
  3. String[] candidates = StringUtils.toStringArray(configurations);
  4. boolean[] skip = new boolean[candidates.length];
  5. boolean skipped = false;
  6. for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
  7. invokeAwareMethods(filter);
  8. boolean[] match = filter.match(candidates, autoConfigurationMetadata);
  9. for (int i = 0; i < match.length; i++) {
  10. if (!match[i]) {
  11. skip[i] = true;
  12. candidates[i] = null;
  13. skipped = true;
  14. }
  15. }
  16. }
  17. if (!skipped) {
  18. return configurations;
  19. }
  20. List<String> result = new ArrayList<>(candidates.length);
  21. for (int i = 0; i < candidates.length; i++) {
  22. if (!skip[i]) {
  23. result.add(candidates[i]);
  24. }
  25. }
  26. if (logger.isTraceEnabled()) {
  27. int numberFiltered = configurations.size() - result.size();
  28. logger.trace("Filtered " + numberFiltered + " auto configuration class in "
  29. + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
  30. }
  31. return new ArrayList<>(result);
  32. }
  1. protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
  2. return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
  3. }

根据AutoConfigurationImportFilter的实现类过滤自动装配类

到此这篇关于SpringBoot快速通关自动配置应用的文章就介绍到这了,更多相关SpringBoot自动配置内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号