Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".
We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need minimal Spring configuration.
Create stand-alone Spring applications
Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
Provide opinionated 'starter' dependencies to simplify your build configuration
Automatically configure Spring and 3rd party libraries whenever possible
Provide production-ready features such as metrics, health checks, and externalized configuration
Absolutely no code generation and no requirement for XML configuration
总结:1,独立的spring应用 2,集成了Tomcat、Jetty等 3,starter 4,自动装配 5,监控及外部配置 6,非XML配置
下面将根据以上重点特征进行讲述
SpringBoot框架诞生原因之一就是要对Spring框架进行最小化配置的实现,所以就出现了“约定大于配置"这个解决方案!
约定优于配置的主要体现:
@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 {
...
}
核心来讲就@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
...
}
@SpringBootConfiguration 其实就是@Configuration的派生
SpringBootApplication 本质上是由 3 个注解组成,分别是
1. @Configuration
2. @EnableAutoConfiguration
3. @ComponentScan
Configuration 这个注解大家应该有用过,它是 JavaConfig形式的基于 Spring IOC 容器的配置类使用的一种注解。因为SpringBoot 本质上就是一个 spring 应用,所以通过这个注解来加载 IOC 容器的配置是很正常的。所以在启动类里面标注了@Configuration,意味着它其实也是一个 IoC容器的配置类。传统意义上的 spring 应用都是基于 xml 形式来配置 bean的依赖关系。然后通过 spring 容器在启动的时候,把 bean进行初始化并且,如果 bean 之间存在依赖关系,则分析这些已经在 IoC 容器中的 bean 根据依赖关系进行组装。
直到 Java5 中,引入了 Annotations 这个特性,Spring 框架也紧随大流并且推出了基于 Java 代码和 Annotation 元信息的依赖关系绑定描述的方式,也就是 JavaConfig。 从 spring3 开始,spring 就支持了两种 bean 的配置方式,一种是基于 xml 文件方式、另一种就是 javaConfig,任何一个标注了@Configuration 的 Java 类定义都是一个JavaConfig 配置类。而在这个配置类中,任何标注了@Bean 的方法,它的返回值都会作为 Bean 定义注册到Spring 的 IOC 容器,方法名默认成为这个 bean 的 id
核心就是IOC支持的三种配置方式:
1.XML
2.@Configuration --> @Bean (JavaConfig)
//该注解表示这个类为javaConfig类
@Configuration
public class MyConfig {
//该注解表示:向容器中注册一个叫做myCar的对象
@Bean("myCar")
public Car getCar() {
return new Car("保时捷","911",300);
}
//该注解表示:向容器中注册一个叫做person的对象
//并且通过byType的方式注入car
@Bean(name="person",autowire=Autowire.BY_TYPE)
public Person getPerson() {
return new Person(1001,"望穿秋水见伊人");
}
}
3.Annotation注解
ComponentScan 这个注解是大家接触得最多的了,相当于 xml 配置文件中的
@Repository、@Service、@Controller 这类的注解标识的类。ComponentScan 默认会扫描当前 package 下的的所有加
了相关注解标识的类到 IoC 容器中
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
}
2.3.3 AutoConfigurationImportSelector?
Enable注解不仅仅可以像前面演示的案例一样很简单的实现多个 Configuration 的整合,还可以实现一些复杂的场景,比如可以根据上下文来激活不同类型的 bean
@Import 注解可以配置三种不同的 class实现方式
1. 第一种就是基于普通 bean 或者带有@Configuration 的 bean 进行注入
2. 实现 ImportSelector 接口进行动态注入
3. 实现 ImportBeanDefinitionRegistrar 接口进行动态注入
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
...
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
SpringFactoriesLoader
@Conditional注解是个什么东西呢,它可以根据代码中设置的条件装载不同的bean,比如说当一个接口有两个实现类时,我们要把这个接口交给Spring管理时通常会只选择实现其中一个实现类,这个时候我们总不能使用if-else吧,所以这个@Conditional的注解就出现了。
//@ConditionalOnBean的示例代码
/*这个方法上加了@ConditionalOnBean注解,注解里的属性是RedisConnectionFactory。它的意思呢,就是说*如果你配置了redis的相关配置信息那么我就实例化RedisTemplate供你进行操作,如果你没有配置redis的相关*配置那么我就不实例化(毕竟没有配置实例化也报错不是)
*/
@Bean
@ConditionalOnBean(RedisConnectionFactory.class)
public RedisTemplate
补充:
pring-boot 在配置上相比spring要简单许多, 其核心在于spring-boot-starter, 在使用spring-boot来搭建一个项目时, 只需要引入官方提供的starter, 就可以直接使用, 免去了各种配置, 原因在于spring-boot的自动发现,比如当classpath下面有tomcat-embedded.jar 时,对应的bean就会被加载.其核心就是上面讲的自动装配。
下面会介绍如何自己写一个简单的starter,并在自己的工程中使用这个starter
项目结构:
3.1.1 MyProperties :配置文件读取类
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "my-properties")
public class MyProperties {
private String name;
private String msg;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@Override
public String toString() {
return "MyProperties{" +
"name='" + name + '\'' +
", msg='" + msg + '\'' +
'}';
}
}
3.1.2 MyService :自定义功能类
import com.example.properties.MyProperties;
public class MyService {
private MyProperties myProperties;
public MyService(MyProperties myProperties) {
this.myProperties = myProperties;
}
public String getMyProperties(){
return myProperties.toString();
}
}
3.1.3 MyAutoConfiguration :自动装配类
import com.example.properties.MyProperties;
import com.example.service.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ConditionalOnClass(MyService.class)
@EnableConfigurationProperties(MyProperties.class)
@Configuration
public class MyAutoConfiguration {
@Autowired
private MyProperties myProperties;
@Bean
@ConditionalOnMissingBean(MyService.class)
public MyService getMyService(){
return new MyService(myProperties);
}
}
3.1.4 在resources/META-INF下构建spring.factories文件:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.configuration.MyAutoConfiguration
3.1.4 pom.xml :引入spring-boot-starter
4.0.0
com.example
starter-my
0.0.1-SNAPSHOT
starter-my
org.springframework.boot
spring-boot-starter
2.3.0.RELEASE
3.1.5 打成jar包供其它地方使用
3.1.6 测试该starter
测试项目
首先在测试项目中引入该jar包
com.example
starter-my
0.0.1-SNAPSHOT
在项目目录resources/application.properties下写入测试数据,注意前缀要与MyProperties标注的前缀保持一致。
my-properties.name=jack
my-properties.msg=this is my autoConfiguration
测试类
import com.example.service.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TestApplication implements CommandLineRunner {
@Autowired
private MyService service;
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
System.out.println(service.getMyProperties());
}
}
结果:
SpringBoot自带监控功能Actuator,可以帮助实现对程序内部运行情况监控,比如监控状况、Bean加载情况、环境变量、日志信息、线程信息等
pom.xml
org.springframework.boot
spring-boot-starter-actuator
/actuator
/actuator/health
/actuator/health/{component}
/actuator/health/{component}/{instance}
/actuator/info
如果要查看其它状态就得设置相应权限:
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
{
"_links": {
"self": {
"href": "http://localhost:8080/actuator",
"templated": false
},
"beans": {
"href": "http://localhost:8080/actuator/beans",
"templated": false
},
"caches-cache": {
"href": "http://localhost:8080/actuator/caches/{cache}",
"templated": true
},
"caches": {
"href": "http://localhost:8080/actuator/caches",
"templated": false
},
"health": {
"href": "http://localhost:8080/actuator/health",
"templated": false
},
"health-path": {
"href": "http://localhost:8080/actuator/health/{*path}",
"templated": true
},
"info": {
"href": "http://localhost:8080/actuator/info",
"templated": false
},
"conditions": {
"href": "http://localhost:8080/actuator/conditions",
"templated": false
},
"configprops": {
"href": "http://localhost:8080/actuator/configprops",
"templated": false
},
"env": {
"href": "http://localhost:8080/actuator/env",
"templated": false
},
"env-toMatch": {
"href": "http://localhost:8080/actuator/env/{toMatch}",
"templated": true
},
"loggers": {
"href": "http://localhost:8080/actuator/loggers",
"templated": false
},
"loggers-name": {
"href": "http://localhost:8080/actuator/loggers/{name}",
"templated": true
},
"heapdump": {
"href": "http://localhost:8080/actuator/heapdump",
"templated": false
},
"threaddump": {
"href": "http://localhost:8080/actuator/threaddump",
"templated": false
},
"metrics-requiredMetricName": {
"href": "http://localhost:8080/actuator/metrics/{requiredMetricName}",
"templated": true
},
"metrics": {
"href": "http://localhost:8080/actuator/metrics",
"templated": false
},
"scheduledtasks": {
"href": "http://localhost:8080/actuator/scheduledtasks",
"templated": false
},
"mappings": {
"href": "http://localhost:8080/actuator/mappings",
"templated": false
}
}
}
Loggers
显示当前 spring-boot 应用中的日志配置信息,针对每个package 对应的日志级别
beans
获取当前 spring-boot 应用中 IoC 容器中所有的 bean
Dump
获取活动线程的快照
Mappings
返回全部的 uri 路径,以及和控制器的映射关系
conditions
显示当前所有的条件注解,提供一份自动配置生效的条件情况,记录哪些自动配置条件通过了,哪些没通过
{
"contexts":{
"application":{
"beans":{
"endpointCachingOperationInvokerAdvisor":{
"aliases":[
],
"scope":"singleton",
"type":"org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationInvokerAdvisor",
"resource":"class path resource [org/springframework/boot/actuate/autoconfigure/endpoint/EndpointAutoConfiguration.class]",
"dependencies":[
"environment"
]
}
}
}
}
}
{
"activeProfiles":[
],
"propertySources":[
{
"name":"server.ports",
"properties":{
"local.server.port":{
"value":8080
}
}
},
{
"name":"servletContextInitParams",
"properties":{
}
},
{
"name":"systemProperties",
"properties":{
"java.vendor":{
"value":"Oracle Corporation"
},
"sun.java.launcher":{
"value":"SUN_STANDARD"
},
"catalina.base":{
"value":"C:%users\timxia\AppData\Local\Temp\tomcat.2979281870254394426.8080"
}
}
}
]
}
启用端点
默认情况下,除shutdown以外的所有端点均已启用。要配置单个端点的启用,请使用management.endpoint.
属性。以下示例启用shutdown
端点:
management.endpoint.shutdown.enabled=true
另外可以通过management.endpoints.enabled-by-default
来修改全局端口默认配置,以下示例启用info端点并禁用所有其他端点:
management.endpoints.enabled-by-default=false
management.endpoint.info.enabled=true
注意:禁用的端点将从应用程序上下文中完全删除。如果您只想更改端点公开(对外暴露)的技术,请改为使用include和exclude属性,详情见下文
暴露端点
要更改公开哪些端点,请使用以下技术特定的include和exclude属性:
Property | Default |
---|---|
management.endpoints.jmx.exposure.exclude | * |
management.endpoints.jmx.exposure.include | * |
management.endpoints.web.exposure.exclude | * |
management.endpoints.web.exposure.include | info, health |
include属性列出了公开的端点的ID,exclude属性列出了不应该公开的端点的ID
exclude属性优先于include属性。包含和排除属性都可以使用端点ID列表进行配置。
注意:这里的优先级是指同一端点ID,同时出现在include
属性表和exclude
属性表里,exclude
属性优先于include
属性,即此端点没有暴露
health
和info
端点,请使用以下属性:management.endpoints.jmx.exposure.include=health,info
*
可以用来选择所有端点。例如,要通过HTTP公开除env
和beans
端点之外的所有内容,请使用以下属性:
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=env,beans
应用健康状态的检查应该是监控系统中最基本的需求,所以我们基于 health 来分析一下它是如何实现的。SpringBoot 预先通过
org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration,这个就是基于 spring-boot 的自动装配来载入的。所以,我们可以在 actuator-autoconfigure 这个包下找到spring.factories。
其核心还是运用了spring boot的自动装配原理。
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnAvailableEndpoint(
endpoint = HealthEndpoint.class
)
@EnableConfigurationProperties
@Import({LegacyHealthEndpointAdaptersConfiguration.class, LegacyHealthEndpointCompatibilityConfiguration.class, HealthEndpointConfiguration.class, ReactiveHealthEndpointConfiguration.class, HealthEndpointWebExtensionConfiguration.class, HealthEndpointReactiveWebExtensionConfiguration.class})
public class HealthEndpointAutoConfiguration {
public HealthEndpointAutoConfiguration() {
}
@Bean
HealthEndpointProperties healthEndpointProperties(HealthIndicatorProperties healthIndicatorProperties) {
HealthEndpointProperties healthEndpointProperties = new HealthEndpointProperties();
healthEndpointProperties.getStatus().getOrder().addAll(healthIndicatorProperties.getOrder());
healthEndpointProperties.getStatus().getHttpMapping().putAll(healthIndicatorProperties.getHttpMapping());
return healthEndpointProperties;
}
}