一、引言
在Spring Boot的世界里,有一个超级明星注解,那就是@SpringBootApplication。当你创建一个Spring Boot项目时,它就像一个忠诚的伙伴,默默地守护在主类之上。这个注解看似简单,实则蕴含着巨大的能量,它就像是一个神秘的百宝箱,里面藏着好几个关键的注解。今天,咱们就一起来揭开@SpringBootApplication的神秘面纱,把它拆解开来,看看里面到底都有啥。
二、@SpringBootApplication 概述
2.1 基本介绍
@SpringBootApplication是Spring Boot提供的一个复合注解,它位于org.springframework.boot.autoconfigure包下。简单来说,这个注解就像是一个大管家,它把多个常用的注解组合在一起,让我们在开发Spring Boot应用时可以少写很多代码。使用了@SpringBootApplication注解的类,就相当于告诉Spring Boot,这是整个应用的入口。
2.2 源码分析
我们来看看@SpringBootApplication的源码:
package org.springframework.boot.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAutoConfiguration;
/**
* Indicates a {@link Configuration configuration} class that declares one or more
* {@link org.springframework.context.annotation.Bean @Bean} methods and also triggers
* {@link EnableAutoConfiguration auto-configuration} and {@link ComponentScan component scanning}.
* This is a convenience annotation that is equivalent to declaring {@code @Configuration},
* {@code @EnableAutoConfiguration} and {@code @ComponentScan}.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @since 1.2.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
// ... 其他属性方法
}
从源码中可以看出,@SpringBootApplication主要组合了三个关键注解:@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan。接下来,我们就分别对这三个注解进行详细拆解。
三、拆解 @SpringBootConfiguration
3.1 基本介绍
@SpringBootConfiguration是Spring Boot提供的一个特殊的配置注解,它本质上是@Configuration注解的一个扩展。@Configuration注解用于定义配置类,被该注解标注的类相当于一个Spring的XML配置文件。
3.2 源码分析
package org.springframework.boot;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
/**
* Indicates that a class provides Spring Boot application
* {@link Configuration @Configuration}. Can be used as an alternative to the Spring's
* standard {@code @Configuration} annotation so that configuration can be found
* automatically (for example in tests).
*
* <p>
* Application should only ever include <em>one</em> {@code @SpringBootConfiguration} and
* most idiomatic Spring Boot applications will inherit it from
* {@code @SpringBootApplication}.
*
* @author Phillip Webb
* @since 1.4.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
从源码可以看出,@SpringBootConfiguration只是在@Configuration的基础上做了一些扩展,它的主要作用是告诉Spring Boot这是一个配置类。
3.3 示例演示
下面是一个简单的示例:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
// 使用 @SpringBootConfiguration 注解标注配置类
@SpringBootConfiguration
public class MyConfig {
// 定义一个Bean
@Bean
public String myBean() {
return "Hello, Spring Boot!";
}
public static void main(String[] args) {
SpringApplication.run(MyConfig.class, args);
}
}
在这个示例中,MyConfig类被@SpringBootConfiguration注解标注,成为了一个配置类。其中,myBean方法使用@Bean注解定义了一个字符串类型的Bean。
四、拆解 @EnableAutoConfiguration
4.1 基本介绍
@EnableAutoConfiguration是Spring Boot自动配置的核心注解,它的作用是开启Spring Boot的自动配置机制。当我们使用这个注解时,Spring Boot会根据项目中引入的依赖,自动为我们配置一些常用的组件,比如数据库连接池、Web服务器等。
4.2 源码分析
package org.springframework.boot.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
/**
* Enable auto-configuration of the Spring Application Context, attempting to guess and
* configure beans that you are likely to need. Auto-configuration classes are usually
* applied based on your classpath and what beans you have defined. For example, if you
* have {@code tomcat-embedded.jar} on your classpath, you are likely to want a
* {@link org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
* TomcatServletWebServerFactory}.
*
* <p>
* When using {@link SpringBootApplication @SpringBootApplication}, the auto-configuration
* of the context is automatically enabled and adding this annotation has therefore no
* additional effect.
*
* <p>
* Auto-configuration tries to be as intelligent as possible and will back-away as you
* define more of your own configuration. You can always manually {@link #exclude()} any
* configuration that you never want to apply (use {@link #excludeName()} if you don't
* have access to them). You can also exclude them via the
* {@code spring.autoconfigure.exclude} property. Auto-configuration is always applied
* after user-defined beans have been registered.
*
* <p>
* The package of the class that is annotated with {@code @EnableAutoConfiguration} has
* specific significance and is often used as a 'default'. For example, it will be used
* when scanning for {@link org.springframework.stereotype.Controller @Controller} classes.
* It is generally recommended that you place {@code @EnableAutoConfiguration} (if you're
* not using {@link SpringBootApplication @SpringBootApplication}) in a root package so
* that all sub-packages and classes can be searched.
*
* <p>
* Auto-configuration classes are regular Spring {@link org.springframework.context.annotation.Configuration @Configuration}
* beans. They are located using the {@link SpringFactoriesLoader} mechanism (keyed
* against this class). Generally auto-configuration beans are
* {@link org.springframework.context.annotation.Conditional @Conditional} beans (most
* often using {@link org.springframework.boot.autoconfigure.condition.OnClassCondition
* OnClassCondition}) so that they can back-away when their conditions are not met.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @since 1.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationImportSelector.class)
public @interface 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通过@Import注解导入了AutoConfigurationImportSelector类。AutoConfigurationImportSelector类会根据项目的类路径和配置文件,选择合适的自动配置类进行加载。
4.3 示例演示
假设我们要创建一个简单的Spring Boot Web应用,只需要引入Spring Boot Web的依赖,然后使用@EnableAutoConfiguration注解,Spring Boot就会自动为我们配置好嵌入式Tomcat服务器和Spring MVC。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
// 使用 @EnableAutoConfiguration 注解开启自动配置
@EnableAutoConfiguration
@RestController
public class WebApp {
@GetMapping("/")
public String hello() {
return "Hello, Spring Boot Web!";
}
public static void main(String[] args) {
SpringApplication.run(WebApp.class, args);
}
}
在这个示例中,我们使用@EnableAutoConfiguration注解开启了自动配置,同时使用@RestController注解创建了一个RESTful控制器。当我们启动应用后,Spring Boot会自动配置好Tomcat服务器,我们可以通过访问http://localhost:8080来看到返回的Hello, Spring Boot Web!。
4.4 排除自动配置
有时候,我们可能不需要某些自动配置,这时候可以使用exclude属性来排除特定的自动配置类。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
// 排除 DataSourceAutoConfiguration 自动配置类
@EnableAutoConfiguration(exclude = DataSourceAutoConfiguration.class)
@RestController
public class ExcludeApp {
@GetMapping("/")
public String hello() {
return "Exclude DataSource Auto Configuration!";
}
public static void main(String[] args) {
SpringApplication.run(ExcludeApp.class, args);
}
}
在这个示例中,我们使用exclude属性排除了DataSourceAutoConfiguration类,这样Spring Boot就不会自动配置数据源了。
五、拆解 @ComponentScan
5.1 基本介绍
@ComponentScan注解用于指定Spring在哪些包下扫描组件。Spring会自动扫描指定包及其子包下的所有带有@Component、@Service、@Repository、@Controller等注解的类,并将它们注册为Spring Bean。
5.2 源码分析
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
/**
* Configures component scanning directives for use with @{@link Configuration} classes.
* Provides support parallel with Spring XML's {@code <context:component-scan>} element.
*
* <p>Either {@link #basePackageClasses} or {@link #basePackages} (or its alias
* {@link #value}) may be specified to define specific packages to scan. If specific
* packages are not defined, scanning will occur from the package of the class that
* declares this annotation.
*
* <p>Note that the {@code <context:component-scan>} element has an
* {@code annotation-config} attribute; however, this annotation does not. This is because
* in almost all cases when using {@code @ComponentScan}, default annotation config
* processing (e.g. processing {@code @Autowired} and friends) is assumed. Furthermore,
* when using {@link AnnotationConfigApplicationContext}, annotation config processors are
* always registered, meaning that any attempt to disable them at the
* {@code @ComponentScan} level would be ignored.
*
* <p>See {@link Configuration @Configuration}'s Javadoc for usage examples.
*
* @author Chris Beams
* @author Juergen Hoeller
* @author Sam Brannen
* @since 3.1
* @see Configuration
* @see org.springframework.context.annotation.FilterType
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
/**
* Alias for {@link #basePackages}.
* <p>Allows for more concise annotation declarations if no other attributes
* are needed — for example, {@code @ComponentScan("org.my.pkg")}
* instead of {@code @ComponentScan(basePackages = "org.my.pkg")}.
*/
@AliasFor("basePackages")
String[] value() default {};
/**
* Base packages to scan for annotated components.
* <p>{@link #value} is an alias for (and mutually exclusive with) this
* attribute.
* <p>Use {@link #basePackageClasses} for a type-safe alternative to
* String-based package names.
*/
@AliasFor("value")
String[] basePackages() default {};
/**
* Type-safe alternative to {@link #basePackages} for specifying the packages
* to scan for annotated components. The package of each class specified will be scanned.
* <p>Consider creating a special no-op marker class or interface in each package
* that serves no purpose other than being referenced by this attribute.
*/
Class<?>[] basePackageClasses() default {};
// ... 其他属性方法
}
从源码中可以看出,@ComponentScan注解有多个属性,比如basePackages、basePackageClasses等,用于指定扫描的包路径。
5.3 示例演示
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
// 定义一个服务类
@Service
public class MyService {
public String doSomething() {
return "Doing something...";
}
}
// 使用 @ComponentScan 注解指定扫描的包
@Configuration
@ComponentScan(basePackages = "com.example.demo")
public class AppConfig {
}
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
// 创建 Spring 上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 获取 MyService Bean
MyService myService = context.getBean(MyService.class);
System.out.println(myService.doSomething());
// 关闭上下文
context.close();
}
}
在这个示例中,我们使用@ComponentScan注解指定了要扫描的包为com.example.demo,Spring会自动扫描该包下的MyService类,并将其注册为Spring Bean。在Main类中,我们通过AnnotationConfigApplicationContext获取了MyService Bean,并调用了其doSomething方法。
六、应用场景
6.1 快速搭建项目
@SpringBootApplication注解最常见的应用场景就是快速搭建Spring Boot项目。我们只需要在主类上添加这个注解,就可以开启自动配置和组件扫描,大大减少了配置的工作量。比如,我们要创建一个简单的Web应用,只需要引入Spring Boot Web的依赖,然后在主类上添加@SpringBootApplication注解,就可以快速启动一个Web服务器。
6.2 微服务开发
在微服务开发中,每个微服务都可以使用@SpringBootApplication注解来简化配置。每个微服务可能会有不同的依赖,Spring Boot的自动配置机制可以根据这些依赖自动配置相应的组件,比如数据库连接、消息队列等。
6.3 测试环境搭建
在测试环境中,我们可以使用@SpringBootApplication注解来快速搭建测试环境。通过自动配置,我们可以模拟生产环境的配置,方便进行单元测试和集成测试。
七、技术优缺点
7.1 优点
- 简化配置:
@SpringBootApplication注解将多个常用的注解组合在一起,避免了我们手动配置多个注解,大大简化了开发过程。 - 自动配置:
@EnableAutoConfiguration注解开启了自动配置机制,Spring Boot会根据项目的依赖自动配置常用的组件,提高了开发效率。 - 组件扫描:
@ComponentScan注解可以自动扫描指定包下的组件,将它们注册为Spring Bean,减少了手动注册的工作量。
7.2 缺点
- 过度依赖自动配置:由于自动配置机制比较强大,可能会导致开发者对Spring Boot的内部配置不够了解。当出现问题时,可能会难以定位和解决。
- 性能问题:自动配置会加载一些可能不需要的组件,可能会导致应用的
评论