自动装配

@SpringBootApplication: 行这个类的main方法来启动SpringBoot应用

原理:

  1. //设置当前注解可以标记在哪
  2. @Target(ElementType.TYPE)
  3. @Retention(RetentionPolicy.RUNTIME)
  4. @Documented
  5. @Inherited
  6. //标注在某个类上,表示这是一个Spring Boot的配置类
  7. @SpringBootConfiguration
  8. @EnableAutoConfiguration
  9. @ComponentScan(excludeFilters = {
  10. @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
  11. @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
  12. public @interface SpringBootApplication {
  1. @SpringBootConguration:Spring Boot的配置类;
  2. 标注在某个类上,表示这是一个Spring Boot的配置类;
  3. @Conguration:配置类上来标注这个注解;
  4. 配置类 ----- 配置文件;配置类也是容器中的一个组件;@Component
  5. @EnableAutoConguration:开启自动配置功能;
  6. 以前我们需要配置的东西,Spring Boot帮我们自动配置;@EnableAutoConguration告诉SpringBoot开启自动配置,会帮我们自动去加载 自动配置类
  7. @ComponentScan 扫描包
  8. 相当于在spring.xml 配置中<context:component-scan> 但是并没有指定basepackage,如果没有指定spring底层会自动扫描当前配置类所有在的包
  9. TypeExcludeFilter
  10. springboot对外提供的扩展类, 可以供我们去按照我们的方式进行排除
  11. AutoConfigurationExcludeFilter
  12. 排除所有配置类并且是自动配置类中里面的其中一个

EnableAutoConfiguration

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @AutoConfigurationPackage
  6. @Import(AutoConfigurationImportSelector.class)
  7. public @interface EnableAutoConfiguration {
  8. // 略
  9. }

@AutoConfigurationPackage

@Import(AutoConfigurationImportSelector.class) 关键点!

使用import完成的注册,自动配置,
AutoConfigurationImportSelector实现了DeferredImportSelectorSpring,
getAutoConfigurationEntry扫描,META-INFO/spring-factories文件中jar

  1. protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
  2. if (!isEnabled(annotationMetadata)) {
  3. return EMPTY_ENTRY;
  4. }
  5. AnnotationAttributes attributes = getAttributes(annotationMetadata);
  6. // 从META-INF/spring.factories中获得候选的自动配置类
  7. List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
  8. // 排重
  9. configurations = removeDuplicates(configurations);
  10. //根据EnableAutoConfiguration注解中属性,获取不需要自动装配的类名单
  11. Set<String> exclusions = getExclusions(annotationMetadata, attributes);
  12. // 根据:@EnableAutoConfiguration.exclude
  13. // @EnableAutoConfiguration.excludeName
  14. // spring.autoconfigure.exclude 进行排除
  15. checkExcludedClasses(configurations, exclusions);
  16. // exclusions 也排除
  17. configurations.removeAll(exclusions);
  18. // 通过读取spring.factories 中的OnBeanCondition\OnClassCondition\OnWebApplicationCondition进行过滤
  19. configurations = getConfigurationClassFilter().filter(configurations);
  20. // 这个方法是调用实现了AutoConfigurationImportListener 的bean.. 分别把候选的配置名单,和排除的配置名单传进去做扩展
  21. fireAutoConfigurationImportEvents(configurations, exclusions);
  22. return new AutoConfigurationEntry(configurations, exclusions);
  23. }

spring.factories文件格式key-value格式

  1. # Initializers
  2. org.springframework.context.ApplicationContextInitializer=\
  3. org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
  4. org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
  5. # Application Listeners
  6. org.springframework.context.ApplicationListener=\
  7. org.springframework.boot.autoconfigure.BackgroundPreinitializer
  8. # Auto Configuration Import Listeners
  9. org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
  10. org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
  11. # Auto Configuration Import Filters
  12. org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
  13. org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
  14. org.springframework.boot.autoconfigure.condition.OnClassCondition,\
  15. org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

获取对应的这个文件,加载对应的bean到BeanDefinitionMap接下来就是加载进容器了


所有自动配置类表:
https://docs.spring.io/spring-boot/docs/current/reference/html/auto-configuration-classes.html#appendix.auto-configuration-classes

@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(…)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中
@Configuration(proxyBeanMethods = false) 判断是jdk代理还是cglib

@Conditional扩展注解作用 (判断是否满足当前指定条件)
@ConditionalOnJava 系统的java版本是否符合要求
@ConditionalOnBean 容器中存在指定Bean;
@ConditionalOnMissingBean 容器中不存在指定Bean;
@ConditionalOnExpression 满足SpEL表达式指定
@ConditionalOnClass 系统中有指定的类
@ConditionalOnMissingClass 系统中没有指定的类
@ConditionalOnSingleCandidate 容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty 系统中指定的属性是否有指定的值
@ConditionalOnResource 类路径下是否存在指定资源文件
@ConditionalOnWebApplication 当前是web环境
@ConditionalOnNotWebApplication 当前不是web环境
@ConditionalOnJndi JNDI存在指定项

启用 debug=true属性,控制台打印那些自动配置会生效

image.png

总结

就是如何加载不在scan包下的其他类

自定义starter

  1. @Configuration
  2. @ConditionalOnWebApplication
  3. @ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurerAdapter.class})
  4. @ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
  5. @AutoConfigureOrder(-2147483638)
  6. @AutoConfigureAfter({DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class})
  7. public class WebMvcAutoConfiguration {
  8. @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
  9. @EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
  10. public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {
  11. @Bean
  12. @ConditionalOnBean({View.class})
  13. @ConditionalOnMissingBean
  14. public BeanNameViewResolver beanNameViewResolver() {
  15. BeanNameViewResolver resolver = new BeanNameViewResolver();
  16. resolver.setOrder(2147483637);
  17. return resolver;
  18. }
  19. }
  20. }
  1. @Configuration //指定这个类是一个配置类
  2. @ConditionalOnXXX //指定条件成立的情况下自动配置类生效
  3. @AutoConfigureOrder //指定自动配置类的顺序
  4. @Bean //向容器中添加组件
  5. @ConfigurationProperties //结合相关xxxProperties来绑定相关的配置
  6. @EnableConfigurationProperties //让xxxProperties生效加入到容器中
  7. 自动配置类要能加载需要将自动配置类,配置在META-INF/spring.factories
  8. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  9. org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
  10. org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

启动器

  • 启动器(starter)是一个空的jar文件,仅仅提供辅助性依赖管理,这些依赖可能用于自动装配或其他类库。
  • 需要专门写一个类似spring-boot-autoconfigure的配置模块
  • 用的时候只需要引入启动器starter,就可以使用自动配置了

命名规范
官方命名规范

  • 前缀:spring-boot-starter-
  • 模式:spring-boot-starter-模块名
  • 举例:spring-boot-starter-web、spring-boot-starter-jdbc

自定义命名空间

  • 后缀:-spring-boot-starter
  • 模式:模块-spring-boot-starter
  • 举例:mybatis-spring-boot-starter

两个模块

  1. starter,是一个空的jar包
  2. autoconfigurer,写实现逻辑的bean

1:先创建starter 的pom

  1. <dependencies>
  2. <!--引入autoconfigure-->
  3. <dependency>
  4. <groupId>com.tulingxueyuan.springboot</groupId>
  5. <artifactId>tulingxueyuan-spring-boot-autoconfigure</artifactId>
  6. <version>0.0.1-SNAPSHOT</version>
  7. </dependency>
  8. <!--如果当前starter 还需要其他的类库就在这里引用-->
  9. </dependencies>

2:autoconfigurer的pom

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-web</artifactId>
  5. </dependency>
  6. <!--‐导入配置文件处理器,配置文件进行绑定就会有提示-->
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-configuration-processor</artifactId>
  10. <optional>true</optional>
  11. </dependency>
  12. </dependencies>

在configurateion写对应的bean

再创建spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.starter.tulingxueyuan.HelloAutoConfitguration

然后本地按照就可以使用了

测试
新建个项目
引入我们写的stare

  1. <dependency>
  2. <groupId>com.tulingxueyuan.springboot</groupId>
  3. <artifactId>tulingxueyuan-spring-boot-starter</artifactId>
  4. <version>0.0.1-SNAPSHOT</version>
  5. </dependency>

就ok 啦

@ import的使用
把不在扫描范围内的bean导入

@Group 分组,利用分组,影响分组的实现顺序???
@DeferedImportSelector

扫描spring.factores文件的bean

过滤判断哪些类会生效,哪些不会,会有一个过滤
配置exclude排除不要的

BeanDefinitionMap:存储解析的bean定义

spring boot 2.0默认是CGlib动态代理的

@ConditionOnBean的含义:

自动配置,怎么把第三方的bean导入的。

SPI:spring boot启动外置Tomcat的东西

启动原理

最终把spring.factories的配置加载进来,
加载进beanDefinitionMap,提供使用提供很多默认的bean使用,可以扩展,自定义

如何定制自己的配置类加载

在自己的项目加一个META-INF/spring.factories
指向自己的注解方法

maven

true
@ConditionOnClass失效,

starter的用处

把相关配置,加载进来,
加载对应的额配置

@EnableConfigurationProperties吧配置注册成bean
通过bean的后置处理器加载bean
image.png