1. 什么是配置?
配置就是一个类需要用到另一个类,要通过实例bean来调用(静态成员可以通过类名调用),传统的实现方式是需要手动new类的实例,但是Spring提供了IoC容器,实现了控制反转,即我们不需要手动new实例,交给IoC容器来实现创建实例,以及依赖注入,所以,配置就是将类的实例bean,注入IoC容器。
2. 什么是自动配置?
spring的配置需要写xml配置文件,在xml文件中通过写<Bean>
标签手动配置bean,将bean注入到Spring容器中,SpringBoot通过注解的方式取代了写xml配置文件,实现了自动配置。
自动配置就是将类的实例bean注入到IoC容器中,而这个操作是注解实现的,不用我们手动在xml文件中配置<Bean>
标签。
3. 有两种类型的配置:
配置1:classpath类路径下自定义的类通过注解实现将bean注入容器。
配置2:pom.xml文件中导入的第三方依赖jar的配置。
下面从启动类说起,根据源码追踪,分析注解是如何实现自动配置的。
springboot项目启动类中的注解@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 {
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
}
源码中通过元注解@AliasFor
整合了三个注解的功能,分别是@EnableAutoConfiguration
,@ComponentScan
,@Configuration
。
其中,classpath类路径下的类的配置是通过@ComponentScan
实现的。第三方依赖的配置是通过@EnableAutoConfiguration
实现的。
官方文档中介绍:
意思是:不需要将所有的@Configuration放到一个类中。可以使用@Import注解导入其他配置类。或者,可以使用@ComponentScan自动拾取所有Spring组件,包括@Configuration类。
@ComponentScan
注解的作用是扫描@SpringBootApplication
所在的Application类所在的包下所有的被注解@Component
(或拓展了@Component的注解)标记的bean,并注册到IoC容器中。
@Component
注解作用是把普通pojo就是普通JavaBeans实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>
【@Component注解是元注解,元注解可以注解其他注解,例如@Service, @Controller,@Dao等都是@Component注解的扩展注解,扩展注解作用是将IoC容器中的Bean分类,便于管理。】
在类路径下,被@Component 注释的类,会被ClassPathBeanDefinitionScanner类扫描。
/**
* Indicates that an annotated class is a "component".
* Such classes are considered as candidates for auto-detection
* when using annotation-based configuration and classpath scanning.
* @see org.springframework.context.annotation.ClassPathBeanDefinitionScanner
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
String value() default "";
}
@Configuration
修饰的类的实例会自动注入到bean容器中。@Configuration注解的处理类是AnnotationConfigApplicationContext,源码如下:
AnnotationConfigApplicationContext类内部继承了GenericApplicationContext类。并创建了一个reader和一个scanner。GenericApplicationContext类内部创建了BeanFactory,也就是Bean容器,IoC容器就是在这个时候初始化的。reader和scanner实现了扫描并解析类路径下被@Component修饰的类并自动刷新上下文,最后通过registerBean()注入到初始化好的IoC容器中。
注解@EnableAutoConfiguration的分析见下一篇博文:源码分析pom.xml第三方依赖如何自动配置导入Bean容器SpringFactoriesLoader-spring.factories