springboot 注解学习之——@SpringBootApplication

发布时间 2023-11-14 21:32:14作者: 繁星TT

springboot 注解学习之——@SpringBootApplication

springboot 版本3.1.5

@Inherited //不认识的注解,顺便学习,字面意思:继承
@SpringBootConfiguration  //字面意思:SpringBoot配置
@EnableAutoConfiguration  //字面意思:可以自动配置

@Inherited

它是一个元注解(就是用来声明注解类型时需要使用到的注解。也叫标记注解),Inherited作用是,使用此注解声明出来的自定义注解,在使用此自定义注解时,如果注解在类上面时,子类会自动继承此注解,否则的话,子类不会继承此注解。这里一定要记住,使用Inherited声明出来的注解,只有在类上使用时才会有效,对方法,属性等其他无效。

简单来说就是@SpringBootApplication这个注解被@Inherited修饰,那么SpringbootXXXApplication这个类的子类,就会自动继承@SpringBootApplication这个注解。

@SpringBootConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration         //没什么特殊的,它是spring配置注解,也就是可以SpringbootXXXApplication这个类里面配置bean。
@Indexed
public @interface SpringBootConfiguration {
	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;

}

@EnableAutoConfiguration

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage   //自动配置包
@Import({AutoConfigurationImportSelector.class})  //引入一个类(自动配置引入选择器类)
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

到这儿可以看出springboot的核心功能自动装配和这个注解有很大关系,上面的注解没啥东西。

@AutoConfigurationPackage

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({AutoConfigurationPackages.Registrar.class})  //这里引入了一个类,自动配置包的内部类,注册。所需要的包都是Registrar注册的?
public @interface AutoConfigurationPackage {
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};
}

看下Registrar

//ImportBeanDefinitionRegistrar to store the base package from the importing configuration.	
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
		// 注册bean的定义,就是自己注册bean,通过注解元数据
		@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
			register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
		}
	    // 确认一下?
		@Override
		public Set<Object> determineImports(AnnotationMetadata metadata) {
			return Collections.singleton(new PackageImports(metadata));
		}

	}

看看怎么注册

	/**
	 * Programmatically registers the auto-configuration package names. Subsequent
	 * invocations will add the given package names to those that have already been
	 * registered. You can use this method to manually define the base packages that will
	 * be used for a given {@link BeanDefinitionRegistry}. Generally it's recommended that
	 * you don't call this method directly, but instead rely on the default convention
	 * where the package name is set from your {@code @EnableAutoConfiguration}
	 * configuration class or classes.
	 * @param registry the bean definition registry
	 * @param packageNames the package names to set
	 */
	//看翻译是把给定的包名注册到spring
	public static void register(BeanDefinitionRegistry registry, String... packageNames) {
         // BEAN = AutoConfigurationPackages.class.getName();
         // 已经有了 BEAN DefinitionRegistry 就直接添加到基础包
		if (registry.containsBeanDefinition(BEAN)) {
            //加到基础包不深究了,应该是都加进去,才能扫描
			addBasePackages(registry.getBeanDefinition(BEAN), packageNames);
		}
        //没有的话,注册BEAN 的定义(真是绕口)
		else {
			RootBeanDefinition beanDefinition = new RootBeanDefinition(BasePackages.class);
			beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
			addBasePackages(beanDefinition, packageNames);
			registry.registerBeanDefinition(BEAN, beanDefinition);
		}
	}

@AutoConfigurationPackage 简单来说,就是用AutoConfigurationPackages类的Registrar这个类,把需要的包注册进基础包,spring就能扫描到

AutoConfigurationImportSelector.class

看字面意思,是选择需要的对象引入。里面很多方法。

有个核心的方法

//获取自动配置入口,通过注解元数据
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
   }
   AnnotationAttributes attributes = getAttributes(annotationMetadata);
    //这一步,找到候选配置,进去看看
   List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
   configurations = removeDuplicates(configurations);
   Set<String> exclusions = getExclusions(annotationMetadata, attributes);
   checkExcludedClasses(configurations, exclusions);
   configurations.removeAll(exclusions);
   configurations = getConfigurationClassFilter().filter(configurations);
   fireAutoConfigurationImportEvents(configurations, exclusions);
   return new AutoConfigurationEntry(configurations, exclusions);
}
	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())
			.getCandidates();
        //这个断言提示 说明需要的配置 默认是从META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports这里读取的
		Assert.notEmpty(configurations,
				"No auto configuration classes found in "
						+ "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
						+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

可以看到org.springframework.boot.autoconfigure.AutoConfiguration.imports这个文件里面很多spring内置好的自动配置类。上面的Selector就是通过这个文件去选择配置类。

这些配置类负责注册自己的bean,到spring当中。当然并不是所有的都会成功注入到spring。每个配置类里面还有判断,需要导入starter。

结构图

总结

springboot的自动装配也就那么回事,只不过把我们之前要自己写的配置,全部写好放着了,需要用的时候,直接拿来。

springboot所有自动配置都是在启动的时候扫描并加载:org.springframework.boot.autoconfigure.AutoConfiguration.imports所有的自动配置类都在这里面,但不一定生效,要判断是否成立,只要导入对应的starter,就有对应的启动器,有了启动器,我们自动装配就会生效。

  • spingboot在启动的时候,从配置文件org.springframework.boot.autoconfigure.AutoConfiguration.imports获取指定的配置类。
  • 将这些自动配置类导入容器,自动配置就会生效,帮我们进行自动配置!
  • 以前我们需要自己配置的东西,现在springboot帮我们做了。
  • 整合javaEE,解决方案和自动配置的东西都在spring-boot-autoconfigure-3.1.5.jar这个包下。
  • 它会会把所有需要导入的组件,一类名的方式返回,这些组件会被添加到容器。
  • 容器中也会有很多的XXXAutoConfiguration的Bean,就是这些类注册了这个场景所需要的组件。@Configguration
  • 有了自动装配,免去了我们手动编配置文件的工作