温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

springboot中怎么配置AutoConfiguration

发布时间:2021-08-03 14:58:25 来源:亿速云 阅读:170 作者:Leah 栏目:编程语言

这期内容当中小编将会给大家带来有关springboot中怎么配置AutoConfiguration,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

1.如何开启自动配置

在启动类上增加注解@EnableAutoConfiguration或者@SpringBootApplication,注意:如果使用@SpringBootApplication同时会默认开启@ComponentScan。

2.@EnableAutoConfiguration注解

@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注解稍后再解读。

3.AutoConfigurationImportSelector.class类实现

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。如下图:

springboot中怎么配置AutoConfiguration

所以,如果我们自己需要实现autoconfig,只需要在classpath路径下新建一个文件META-INF/spring.factories,并加上org.springframework.boot.autoconfigure.EnableAutoConfiguration=实现类,即可。

4.@AutoConfigurationPackage注解

现在,回过头来,我们看下@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。

5.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。

1)初始化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时,默认会设置启动类路径。

2)注册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注册到容器中之后,到底有什么用呢?

3)使用场景

查看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示例如下:

springboot中怎么配置AutoConfiguration

6.总结

1)AutoConfig功能是通过SpringFactoriesLoader通用工厂加载实现的,配置文件为META-INF/spring.factories

2)@AutoConfigurationPackage注解是向容器中注册需要扫描的根目录信息(默认启动类包路径,可配置),当某些组件需要自动扫描时,可以使用该包路径为扫描的根路径。

上述就是小编为大家分享的springboot中怎么配置AutoConfiguration了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI