目录
前言
SpringBoot四大组件:
1, starter 开箱即用 2, 自动装配 AutoConfiguration 3,actuator监控 4.SpringBoot CLI 命令行工具快速构建SpringBoot应用
想要理解SpringBoot,首先需要理解JavaConfig 以及 “约定优于配置”思想,其次我们分析下SpringBoot是如何通过JavaConfig实现自动装配及starter开箱即用的,最后再了解下actuator监控和SpringBoot CLI。
一、JavaConfig是什么?
JDK1.5增加了注解的支持,Spring2.X开始,可以使用注解对Bean进行声明注入。JavaConfig就是通过java代码替代xml配置的一种方式。
@Bean:IoC实体类
@Configuration :配置类
@ComponentScan :扫码类所在包下的所有资源
@ComponentScan注解默认就会装配标识了@Controller,@Service,@Repository,@Component注解的类到spring容器中。
@Controller,@Service,@Repository注解,查看其源码你会发现,他们中有一个共同的注解@Component。
1,自定扫描路径下边带有@Controller,@Service,@Repository,@Component注解加入spring容器2,通过includeFilters加入扫描路径下没有以上注解的类加入spring容器
3,通过excludeFilters过滤出不用加入spring容器的类
4,自定义增加了@Component注解的注解方式
@Import :实现静态导入或动态导入
- @Import(xxxConfiguration.class) 静态导入,直接导入配置类;
- @Import(AutoConfigurationImportSelector.class) 动态导入,根据 ImportSelector 或 ImportBeanDefinitionRegistrar 实现类批量导入;
@Conditional:条件装配,即设置加载条件
@Conditional() 中的value强制添加,且value必须是实现Condition接口的类(Class<? extends Condition>[] value(); ),以实现根据条件判断加载。
SpringBoot对@Conditional做了扩展,提供更简单的使用形式。常用的注解有:
- ConditionalOnBean/ConditionalOnMissingBean:容器中存在(不存在)某个类时进行Bean装载。
- ConditionalOnClass/ConditionalOnMissingClass:classpath下存在(不存在)某个类时进行Bean装载。
- ConditionalOnProperty:系统 application.properties 或 application.yml 文件中指定的对应的属性是否有对应的值。
- ConditionalOnResource:要加载的Bean依赖指定资源是否存在于classpath中。
- ConditionalOnSingleCandidate:只有在确定了给定Bean类的单个候选项时才会加载Bean。
- ConditionalOnWebApplication/ConditionalOnNotWebApplication:如果是Web应用或者不是Web应用,才加载指定的Bean。
- ConditionalOnJava:只有运行指定版本的Java后才加载Bean。
- ConditionalOnExpression:基于SpEl表达式的条件判断。
二、约定优于配置
“约定优于配置”思想:
体现在以下方面(包括但不限于):
- Maven目录结构的约定
- SpringBoot默认的配置文件及配置文件中配置属性的约定
- 对于SpringMVC的依赖,自动依赖内置的tomcat容器
- 对于Starter组件自动完成装配
三、剖析@SpringBootApplication
@SpringBootApplication是SpringBoot实现自动装配的主要注解,它是如何实现的呢?让我们揭开她的神秘面纱。
1.初步认识
由上图可见,@SpringBootApplication是主要由@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan()三个注解组成的复合注解。
- @SpringBootConfiguration:点开便知,其实是@Configuration注解,表明为配置类。
- @EnableAutoConfiguration:点开可见,@Import(AutoConfigurationImportSelector.class)引入了Selector类,和@AutoConfigurationPackage(即: @Import(AutoConfigurationPackages.Registrar.class))引入了Registrar类。
- @ComponentScan():在此的作用为,通过excludeFilters过滤出不用加入spring容器的类。
2. @EnableAutoConfiguration
由此可见,@SpringBootApplication 主要是由@EnableAutoConfiguration来实现自动装配的,那引入的这两个类是如何实现自动装配的呢?
- @Import(AutoConfigurationImportSelector.class)
Selector实现了String[] selectImports(AnnotationMetadata annotationMetadata)接口, selectImports调用了getAutoConfigurationEntry方法,我们重点标注注解分析一下此方法。
/**
* Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}
* of the importing {@link Configuration @Configuration} class.
* @param annotationMetadata the annotation metadata of the configuration class
* @return the auto-configurations that should be imported
*/
//annotationMetadata为@EnableAutoConfiguration()的参数,此处没有。
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
//获取@EnableAutoConfiguration()注解中的参数值exclude、excludeName。
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//获取所有自动装配的配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//去除重复的配置类
configurations = removeDuplicates(configurations);
//根据@EnableAutoConfiguration()注解的exclude属性值排除
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
//根据spring.factiores中AutoConfigurationImportFilter对应的配置类过滤
configurations = getConfigurationClassFilter().filter(configurations);
//广播事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
其中getCandidateConfigurations() 中运用了SpringFactoriesLoader实现了SPI机制,默认加载META-INF/spring.factories文件。此处通过loadFactoryNames()获取spring.factories中EnableAutoConfiguration对应的配置类。
- @AutoConfigurationPackage
注解作用:使用了该注解的类所在的包及子包下所有组件扫描到SpringIoC容器中
具体是由@Import(AutoConfigurationPackages.Registrar.class)来实现的,各位看官可以自己查看源码了解,这里就不展开分析了。
- spring-autoconfigure-metadata.properties
除了@Conditional注解类,SpringBoot还提供了spring-autoconfigure-metadata.properties 实现批量自动装配条件配置。
同样通过SPI机制,@EnableAutoConfiguration注解会扫描spring-boot-autoconfigure包中的spring-autoconfigure-metadata.properties文件,也是“约定优于配置”的体现。
ps:老版本是在AutoConfigurationImportSelector中的SelectImports()中,通过AutoConfigurationMetadataLoader.loadMetadata()方法实现获取。本文用的Spring-Boot-2.4.0版本,分析源码发现,此版本是在AutoConfigurationImportSelector的静态内部类AutoConfigurationGroup的selectImports()中实现的。
SPI配置方式:
- 固定的路径和文件名:/META-INF/spring-autoconfigure-metadata.properties
- 内容格式:自动配置类的全路径名.条件=值
综上所述,所有的注解方式都只是为了能够批量动态装配需要的配置类。
四、Starter开箱即用
Strater的开箱即用主要有三个功能:
- 相关Jar包依赖
- 实现Bean的自动装配
- 声明并加载application.properties文件中的属性配置
其中,Bean的自动装配主要是通过spring.properties的SPI机制装配,为了能够自动加载application.properties中所需的属性值;
定义属性类:通过@ConfigurationProperties注解,定义属性前缀和属性名,如:@ConfigurationProperties(prefix = "spring.datasource")。
加载属性类:通过配置类中加@EnableConfigurationProperties()来获取所需的属性值,如:@EnableConfigurationProperties(DataSourceProperties.class)。
五、Actuator监控
1.引入库
代码如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.Actuator
logging.level.root = info
//actuator 访问用
http://localhost:9999/actuator,不配置则用服务端口
management.server.port=9999
//自定义监控端口,不影响服务性能
management.endpoints.web.exposure.include=* //
management.endpoint.health.show-details=always //
management.endpoint.shutdown.enabled=true
访问 http://localhost:9999/actuator 即可查看。 PS :浏览器查看返回的json,可以安装JSONView插件自动解析
三、疑问
1,SpringBoot为什么没有web.xml了?
参考文章:SpringBoot为什么没有web.xml了 。文章分析很透彻,目前还看不透,需要慢慢领悟。
2,boot为什么有的引用的jar包内容是空的?
如:spring-boot-starter-jdbc ; spring-boot-starter-logger:2.4.1
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>从 spring-boot-starter-jdbc 可以看到 spring-boot-starter-jdbc-2.3.0.RELEASE.pom 中引用了相关jar包,包括spring-jdbc。
因为:spring-boot-autoconfigure中的spring.factories,EnableAutoConfiguration下已经加入了JdbcTemplateAutoConfiguration配置类元数据。进入JdbcTemplateAutoConfiguration配置类可以看到上面增加了条件注解。所以当 spring-jdbc 包中的JdbcTemplate.class 存在时,配置类才会加载。所以spring-boot-starter-jdbc只需引用jar包即可,不需要有其它内容。
3,jar包为什么可以直接启动?
1,因为引用了Maven插件
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>2,java -jar 命令
java -jar 会去找jar包中的MANIFEST.MF文件,执行真正的启动类Main-Class;3,jar中META-INF的MANIFEST.MF文件
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.wzf.springbootdemo.SpringbootDemoApplicationjava -jar找到JarLauncher,通过JarLauncher执行SpringbootDemoApplication的main方法。
4,常见的几种启动方式
1,创建SpringBoot项目/模块时,选择Web模块(即依赖 spring-boot-starter-web),启动会自动阻塞。
2,如果SpringBoot的pom.xml只依赖了spring-boot-starter,则通过SpringApplication.run()启动会直接结束,需要加 System.in.read();才能阻塞。
3,Dubbo服务可以依赖 dubbo-spring-boot-starter 来启动,只依赖 dubbo 无法阻塞启动,只能引用dubbo的API类。
<!--<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.3</version>
</dependency>--><dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>若只依赖dubbo.2.7.3包,可以通过配置文件来做属性配置,并在SpringApplication.run()后加 System.in.read();实现阻塞。
4,Dubbo服务可以使用Main.mian()启动项目。
总结
提示:这里对文章进行总结:
以上就是今天要讲的内容,本文仅仅简单介绍了SringBoot的相关知识点,希望对你有所帮助。