Spring Boot 提供了许多注解来简化开发过程,增强配置能力和提高生产力。以下是一些常用的 Spring Boot 注解及其用途:
核心注解
@EnableAutoConfiguration
@EnableAutoConfiguration 是 Spring Boot 中的一个核心注解,它的主要作用是启用 Spring Boot 的自动配置机制。这个注解告诉 Spring Boot 基于应用程序的类路径设置、其他 bean 和各种属性设置来自动配置 Spring 应用上下文。
详细作用
自动配置 Bean:根据项目依赖的库自动配置相应的 Spring Bean。例如,如果项目依赖中包含 spring-boot-starter-web,@EnableAutoConfiguration 会自动配置 Spring MVC 相关的 bean。
简化配置:通过自动配置,开发者不再需要手动编写大量的配置类,只需要少量的自定义配置即可实现复杂的功能。
条件配置:自动配置是有条件的,依赖于特定的条件注解(如 @ConditionalOnClass、@ConditionalOnMissingBean 等),只有在满足这些条件时才会生效。例如,只有在类路径中存在 DataSource 类时,才会配置数据源相关的 bean。
配置覆盖:开发者可以通过在应用中定义相同类型的 bean 来覆盖自动配置的 bean,从而实现自定义的行为。
使用方法
通常情况下,不需要直接使用 @EnableAutoConfiguration,而是通过 @SpringBootApplication 间接启用。@SpringBootApplication 是一个组合注解,包括 @EnableAutoConfiguration、@ComponentScan 和 @Configuration。
@SpringBootApplication
组合注解,包括 @Configuration、@EnableAutoConfiguration 和 @ComponentScan。
用于标注主配置类,启用自动配置和组件扫描。
@SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }
@SpringBootApplication标识的类作为SpringApplication.run的参数运行,SpringApplication.run()方法在运行时,会创建Spring容器,这时@SpringBootApplication由于包含@Configuration注解,所以该类作为配置类给Spring,
Spring在创建容器的时候,解析该类上的所有注解,包括
@EnableAutoConfiguration,开启SpringBoot的自动配置功能,自动配置功能用于扫描SpringBoot组件的相关配置的SpringBean,并自动装载这些Bean。
@ComponentScan,用于扫描本身项目中(自己当前写的项目)需要扫描的Bean的包路径,默认为@SpringBootApplication标注的类的当前包以及子包。
在SpringBootConfigApplication同级目录下创建TestApplication
public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestMainConfig.class,args); } }
在config目录下创建TestMainConfig
@SpringBootApplication(scanBasePackages = "cn.axj.springbootstart") public class TestMainConfig { }
项目结构如下:
打开TestApplication,并运行main方法,项目正常运行。
.__ __ _____ _______ __|__|____ ____ |__|__ __ ____ \__ \ / _ \ \/ / \__ \ / _ \ | | | \/ \ / __ \( <_> > <| |/ __ \( <_> ) | | | / | \ (____ /\____/__/\_ \__(____ /\____/\__| |____/|___| / \/ \/ \/ \______| \/ :: spring boot config :: (2.0) spring-boot-config-test 2024-05-17 10:19:28.709 INFO 12896 --- [ main] cn.axj.springbootstart.TestApplication : Starting TestApplication using Java 1.8.0_261 on DESKTOP-SQBHU59 with PID 12896 (D:\practise\spring-all\spring-boot-config\target\classes started by aoxiaojun in D:\practise\spring-all) 2024-05-17 10:19:28.711 INFO 12896 --- [ main] cn.axj.springbootstart.TestApplication : No active profile set, falling back to 1 default profile: "default" .....
此时项目中有两个入口,分别是TestApplication和SpringBootAnnotationApplication
将SpringBootAnnotationApplication中的@SpringBootApplication注解去掉,并执行mvn clean package,会看到如下报错
Unable to find a single main class from the following candidates [cn.axj.springbootstart.SpringBootAnnotationApplication, cn.axj.springbootstart.TestApplication]
这是因为打包过程中,发现有两个入口,不知道选用哪个。
条件注解
Spring原生Conditional注解
Spring中有一个功能,可以根据条件来决定一个类型的Bean是否作为候选组件加入到容器中,所以Spring定义了一个注解**@Conditional**,用来在定义Bean的时候给他上条件,根据条件来判断是否加入到Spring容器中。 @Conditional注解如下
public @interface Conditional { Class<? extends Condition>[] value(); }
内部有一个Class属性需要继承自Condition。Condition如下
@FunctionalInterface public interface Condition { boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); }
手写Conditional注解
现在来手写实现一个自己的@MyConditionalOnClass注解功能
- 定义@MyConditionalOnClass的条件判断类MyConditionOnClass
public class MyConditionOnClass implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(MyConditionalOnClass.class.getName()); String clazz = (String) annotationAttributes.get("value"); try { //尝试加载该类,如果能正常加载,则条件返回true,不能则返回false Class.forName(clazz); return true; }catch (Exception e){ return false; } } }
- 定义@MyConditionalOnClass
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional({MyConditionOnClass.class}) public @interface MyConditionalOnClass { String value(); }
- 测试
- 创建空Bean类MyBean
public class MyBean { }
- 创建空条件类ConditionBean
public class ConditionBean { }
- 创建配置类BeanConfiguration,并尝试注入MyBean,加上@MyConditionalOnClass条件注解
@Configuration public class BeanConfiguration { @Bean @MyConditionalOnClass(value = "cn.axj.springbootstart.config.ConditionBean") public MyBean myBean(){ //如果该Bean被创建了,则打印该信息 System.out.println("myBean被创建"); return new MyBean(); } }
启动SpringBootAnnotationApplication项目,观察console控制台,可以看到MyBean被创建
将ConditionBean删除,再次启动SpringBootAnnotationApplication项目,观察console控制台,可以观察MyBean没有被创建,条件注解生效。
@ConditionalOnProperty
根据配置属性的存在或值来条件性地配置 bean。
@ConditionalOnProperty(name = "feature.enabled", havingValue = "true") public class MyFeatureConfig { }
@ConditionalOnMissingBean
- 当容器中缺少指定类型的 bean 时,才创建当前 bean。
@ConditionalOnMissingBean(MyService.class) @Bean public MyService myService() { return new MyService(); }
多个同类型的bean,只需要注入一个的时候,可以将所有的Bean都定义并配置,所有的Bean均加上@ConditionOnMissingBean注解,这样Spring容器在加载完成一个这个类型的Bean后,后续的就不会再创建。
@ConditionalOnBean
当容器中存在指定类型的 bean 时,才创建当前 bean。
@ConditionalOnBean(MyService.class) public class MyBeanConfig { }
@ConditionalOnMissingClass
这个注解用于基于应用程序启动时类路径中的特定类的缺失来有条件地启用 Spring bean 或配置类。当您希望在某些依赖项不可用时提供替代配置或实现时,它特别有用。
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.stereotype.Component; @Component @ConditionalOnMissingClass("com.example.SomeClass") public class MyComponent { // Bean implementation here }
在这个示例中,只有在类路径中缺少 SomeClass 时,MyComponent 才会被注册为一个 Spring bean。如果 SomeClass 存在,MyComponent 就不会被注册。
配置和属性注解
@ConfigurationProperties
用于将属性文件中的配置映射到 Java 对象。
@ConfigurationProperties(prefix = "test.some") public class AppProperties { private String name; private String description; // getters and setters }
测试注解
@SpringBootTest
- 用于 Spring Boot 应用的集成测试。
@SpringBootTest public class MyApplicationTests { @Test public void contextLoads() { } }
@WebMvcTest
- 用于 Spring MVC 测试,仅加载 Web 层。