# 启动原理解析

我们开发一个Spring Boot项目,都会用到如下的启动类

@SpringBootApplication
public class Application {
  public static void main(String[] args){
    SpringApplication.run(Application.class, args)
  }
}
1
2
3
4
5
6

从上面代码可以看出,Annotation定义(@SpringBootApplication)和类定义(SpringApplication)最为重要

# @SpringBootApplication

@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 {
...
}
1
2
3
4
5
6
7
8
9
10
11
12

虽然定义了多个注解进行原信息标注,但实际上重要的只有三个:

  • @Configuration
  • @EnableAutoConfiguration
  • @ComponentScan

所以,如果我们使用这三个注解代替SpringBootApplication,整个SpringBoot仍然可以正常运行。

# @Configuration

这里的@Configuration对我们来说并不陌生,它是JavaConfig形式的Spring Ioc容器的配置类使用的@Configuration,SpringBoot社区推荐使用基于JavaConfig的配置形式,所以,这里的启动类标注了@Configuration之后,本身其实也是一个IoC容器的配置类。

  • 表现层形式

基于XML配置的的方式是这样:

<?xml version="1.0" encoding="UTF-8"?>
<beans
  xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
  default-lazy-init="true"
>
<!-- bean定义 -->
</beans>
1
2
3
4
5
6
7
8

而基于JavaConfig的配置方式是这样:

@Configuration
public class MockConfiguration{
  // bean定义
}
1
2
3
4

任何一个标注了@Configuration的Java类定义都是一个JavaConfig配置类

  • 注册bean定义层面 基于XML的配置形式是这样:
<bean id="mockService" class="..MockServiceImpl">
...
</bean>
1
2
3

而基于JavaConfig的配置形式是这样的:

@Configuration
public class MockConfiguration{
  @Bean
  public MockService mockService() {
    return new MockServiceImpl();
  }
}
1
2
3
4
5
6
7

任何一个标注了@Bean的方法,其返回值将作为一个bean定义注册到Spring的IOC容器,方法名将默认成该bean定义的id。

  • 表达依赖注入关系层面

为了表达bean与bean之间的依赖关系,在XML形式中一般是这样:

<bean id="mockService" class="..MockServiceImpl">
  <propery name="dependencyService" ref="dependencyService" />
</bean>
<bean id="dependencyService" class="DependencyServiceImpl"></bean>
1
2
3
4

而基于JavaConfig的配置形式是这样的:

@Configuration
public class MockConfiguration{
  @Bean
  public MockService mockService() {
    return new MockServiceImpl(dependencyService());
  }
  @Bean
  public DependencyService dependencyService() {
    return new DependencyServiceImpl();
  }
}
1
2
3
4
5
6
7
8
9
10
11

如果一个bean的定义依赖其他bean,则直接调用JavaConfig类中依赖bean的创建方法就可以了。

# @CompontentScan

@ComponentScan这个注解在Spring中很重要,他对应XML配置中的元素,@ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository)或者bean定义,最终将这些bean定义加载到IoC容器中。 我们可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描

注:所以SpringBoot的启动类最好还是放在root package下,因为默认不指定basePackages。

# @EnableAutoConfiguration

个人感觉@EnableAutoConfiguration这个注解最为重要,所以放在最后来解释,大家是否还记得Spring框架提供的各种名字为@Enable开头的Annotation定义,比如@EnableScheduling,@EnableCaching、@EnableMBeanExport等,@EnableAutoConfiguration的理念和做事方式其实一脉相承,简单概括,借助@Import的支持,收集和注册特定场景相关的bean定义。