# Spring Boot Starter 原理
# @Enable* 注解的工作原理
# @EnableAsync
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
Class<? extends Annotation> annotation() default Annotation.class;
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# @EnableScheduling
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SchedulingConfiguration.class)
@Documented
public @interface EnableScheduling {
}
2
3
4
5
6
7
# @EnableWebMvc
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
2
3
4
5
6
# @EnableConfigurationProperties
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableConfigurationPropertiesImportSelector.class)
public @interface EnableConfigurationProperties {
Class<?>[] value() default {};
}
2
3
4
5
6
7
8
9
# @EnableTransactionManagement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
2
3
4
5
6
7
8
9
10
11
12
13
# @EnableCaching
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
2
3
4
5
6
7
8
9
10
11
12
13
以上所有的注解都有一个@Import
注解,@Import
是用来导入配置类的,这也意味着这些自动开启的实现其实是导入一些自动配置的bean
。这些导入的配置方式主要分为以下三种类型:
- 直接导入配置类,被
@Configuration
修饰的类。 ImportSelector
接口的实现类,返回一个配置类名称的数组,然后再导入这些配置类。ImportBeanDefinitionRegistrar
接口的实现类,直接在接口方法中注册Bean
。
ImportSelector
接口的一个实现类AutoConfigurationImportSelector
完成了从ClassPath
下各个starter
中的META-INF/spring.factories
文件中读取需要导入的自动配置类。
@SpringBootApplication
注解则间接继承了AutoConfigurationImportSelector
的功能。
# 什么是 SpringBoot 自动装配?
我们现在提到自动装配的时候,一般会和Spring Boot
联系在一起。但是,实际上Spring Framework
早就实现了这个功能。Spring Boot
只是在其基础上,通过SPI
的方式,做了进一步优化。
SpringBoot
定义了一套接口规范,这套规范规定:SpringBoot
在启动时会扫描外部引用jar
包中的META-INF/spring.factories
文件,将文件中配置的类型信息加载到Spring
容器(此处涉及到JVM
类加载机制与Spring
的容器知识),
并执行类中定义的各种操作。对于外部jar
来说,只需要按照SpringBoot
定义的标准,就能将自己的功能装置进SpringBoot
。
没有Spring Boot
的情况下,如果我们需要引入第三方依赖,需要手动配置,非常麻烦。但是,Spring Boot
中,我们直接引入一个starter
即可。
比如你想要在项目中使用redis
的话,直接在项目中引入对应的starter
即可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2
3
4
引入starter
之后,我们通过少量注解和一些简单的配置就能使用第三方组件提供的功能了。
在我看来,自动装配可以简单理解为:通过注解或者一些简单的配置就能在Spring Boot
的帮助下实现某块功能。
# SpringBoot 是如何实现自动装配的?
先看一下SpringBoot
的核心注解SpringBootApplication
/**
* Indicates a {@link Configuration configuration} class that declares one or more
* {@link 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 {
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
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
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
/**
* Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
* for a type-safe alternative to String-based package names.
* <p>
* <strong>Note:</strong> this setting is an alias for
* {@link ComponentScan @ComponentScan} only. It has no effect on {@code @Entity}
* scanning or Spring Data {@link Repository} scanning. For those you should add
* {@link org.springframework.boot.autoconfigure.domain.EntityScan @EntityScan} and
* {@code @Enable...Repositories} annotations.
* @return base packages to scan
* @since 1.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
/**
* Type-safe alternative to {@link #scanBasePackages} 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.
* <p>
* <strong>Note:</strong> this setting is an alias for
* {@link ComponentScan @ComponentScan} only. It has no effect on {@code @Entity}
* scanning or Spring Data {@link Repository} scanning. For those you should add
* {@link org.springframework.boot.autoconfigure.domain.EntityScan @EntityScan} and
* {@code @Enable...Repositories} annotations.
* @return base packages to scan
* @since 1.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
大概可以把@SpringBootApplication
看作是@Configuration
、@EnableAutoConfiguration
、@ComponentScan
注解的集合。
根据SpringBoot
官网,这三个注解的作用分别是:
@EnableAutoConfiguration
:启用SpringBoot
的自动配置机制@Configuration
:允许在上下文中注册额外的bean
或导入其他配置类@ComponentScan
: 扫描被@Component
(@Service
,@Controller
)注解的bean
,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些bean
。如上面的源码所示,容器中将排除TypeExcludeFilter
和AutoConfigurationExcludeFilter
。
参考文档