springboot 注解学习之——@SpringBootApplication
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,就有对应的启动器,有了启动器,我们自动装配就会生效。
关于是否启动某个配置类,springboot使用@Conditional相关注解判断。
@AutoConfiguration(after = { DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@ImportRuntimeHints(WebResourcesRuntimeHints.class)
public class WebMvcAutoConfiguration {
/**
* The default Spring MVC view prefix.
*/
public static final String DEFAULT_PREFIX = "";
/**
* The default Spring MVC view suffix.
*/
public static final String DEFAULT_SUFFIX = "";
private static final String SERVLET_LOCATION = "/";
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled")
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
@Bean
@ConditionalOnMissingBean(FormContentFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.formcontent.filter", name = "enabled", matchIfMissing = true)
public OrderedFormContentFilter formContentFilter() {
return new OrderedFormContentFilter();
}
...
}
- spingboot在启动的时候,从配置文件org.springframework.boot.autoconfigure.AutoConfiguration.imports获取指定的配置类。
- 将这些自动配置类导入容器,自动配置就会生效,帮我们进行自动配置!
- 以前我们需要自己配置的东西,现在springboot帮我们做了。
- 整合javaEE,解决方案和自动配置的东西都在spring-boot-autoconfigure-3.1.5.jar这个包下。
- 它会会把所有需要导入的组件,一类名的方式返回,这些组件会被添加到容器。
- 容器中也会有很多的XXXAutoConfiguration的Bean,就是这些类注册了这个场景所需要的组件。@Configguration
- 有了自动装配,免去了我们手动编配置文件的工作
springboot自动装配原理
-
Spingboot启动会加载大量的自动配置类
-
我们需要的功能有没有在Springboot默认写好的自动配置类当中
-
再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在其中,我们就不需要再手动配置了)
-
给容器中自动配置类添加组件的时候,会从properties类中回去某些属性。我们只需在配置文件中指定这些属性的值即可。
XXXAutoConfiguration:自动配置类;给容器中添加组件。
xxxProperties:封装配置文件中相关属性;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)