优点:
- 快速创建独立运行的spring项目,并且集成主流框架;
- 项目使用嵌入式的servlet容器,所以不需要打成war包;
- 使用staters实现自动依赖和版本控制;
- 使用大量的自动化配置,简化代码,当然也可以修改默认配置;
- 项目不需要配置xml,不需要生成代码,开箱即用;
- 项目可以实现生产环境运行时的应用监控;
- 与云计算天然集成;
pom.xml
- 管理spring-boot所有版本依赖,spring-boot版本仲裁中心
org.springframework.boot.spring-boot-dependencies
org.springframework.boot.spring-starter-parent - spring-boot-starter:
场景启动器;
如:spring-boot-starter-web帮我们导入web模块正常运行需要依赖的组件;
spring-boot将开发中的功能场景抽取出来,做成很多starters(启动器),只需要在项目中引入这些starter,相关开发场景需要的依赖都会自动导入,需要什么功能导入什么场景对应的启动器即可;
springboot主程序类
- @SpringBootApplication
该注解标注标识该类是SpringBoot的主配置类;springboot应该运行这个类的main方法来启动springboot应用;
组合注解:- @SpringBootConfiguration:该注解标注标识该类是springboot的配置类
组合注解:- @Configuration:该注解标注标识该类是一个配置类,相当于配置文件;配置类也是容器中的一个组件;
- @EnableAutoConfiguration:该注解标注标识开启自动配置功能,以前需要在spring中配置的东西,由springboot自动配置
- @AutoConfigurationPackage:自动配置包注解
- @Import(AutoConfigurationPackages.Registrar.class):spring底层注解,给容器中导入一个组件,导入的组件由后面的类来指定,后面的类可以写业务逻辑,来判断可以导入 哪些组件;将主配置类的所在包及其所有子包包含的所有组件扫描到Spring容器中 ;
- @Import(EnableAutoConfigurationImportSelector.class):给容器中导入组件;后面的类表示导入哪些组件的选择器;将所有需要导入的组件以全类名的方式返回;这些组件会被加入到容器中;会给容器导入非常多的自动配置类;给容器导入某个场景需要的所有组件,并配置好这些组件;有了自动配置类,免去手动编写配置注入功能组件等工作 ;SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,classLoader);springboot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类即生效,并帮助我们进行自动配置,以前我们需要自己配置的,spring都帮我们做了;JavaEE的整体解决方案和自动配置都在org.springframework.boot.autoconfigure中;
- @AutoConfigurationPackage:自动配置包注解
- @SpringBootConfiguration:该注解标注标识该类是springboot的配置类
目录结构
src
|_main
| |_java java程序目录
| |_resources
| |_static 保存所有的静态资源,js css images
| |_template 保存所有的模板页面,springboot默认达成jar包使用嵌入式tomcat,默认不支持jsp页面,可以使用模板引擎freemarker、thymleaf;
| |_application.yml
| |_application.properties springboot应用配置文件,可以修改一些默认配置
|_test
|_java
配置文件
springboot的配置文件名固定,用于修改springboot内部底层自动配置的默认值;
1. application.properties配置文件
# 使用时需要注意文件编码格式,否则容易乱码
#值写法:
#Pesonx配置:
personx.lastNamex=zhangsan
personx.agex=19
personx.bosx=false
personx.birthx=2021/3/17
# map对象
personx.mapsx.k1=v1
personx.mapsx.k2=23
# list对象
personx.listsx=lisi,赵六
# 对象
personx.dogx.namex=gougou
personx.dogx.agex=2
2. application.yml配置文件
YAML(YAML Ain’t Markup Language)<==>YAML A Markup Language &YAML Isn’t Markup Language;
以数据为中心,更适合做配置文件(不会像xml一样把数据浪费在了标签的开闭上);
yml配置文件语法 :
k:(空格)v 标识一对键值对,必须有空格;以空格缩进控制层级关系;只要是左对齐的一列数据,都是同一层级的;属性和值大小写敏感;
yml配置文件值写法:
-
字面量:
也就是普通值(如:数字、字符串、布尔);
k: v 字面量可以直接来写;
字符串默认不用加单引号或者双引号,其区别如下;
双引号“”会转义特殊字符,转义表达:namex: “abc\ndef” ⇒ abc换行def;
单引号‘’不会转义特殊字符,原字符串表达:namex: ‘abc\ndef’ ⇒ abc\ndef; -
对象:属性和值(键值对);
k: v 对象v还是k: v的方式
举例:
friendsx:
lastnamex: zhangsanx
agex: 20
等价于<==>行内写法
friendsx: {lastnamex: zhangsanx,agex:20} -
数组:List、Set:用-值表示数组中的其中一个元素;
举例:
petsx:
- catx
- dogx
等价于<==>行内写法
petsx: [catx,dogx] -
配置Bean
@ConfigurationProperties 告诉springboot将配置文件中的属性绑定到被注解的类属性中
其中prefix可以指定绑定配置文件中拿一个对象配置;
配置属性注入依赖spring-boot-configuration-processor;
该注解需要和@Component结合使用作为spring容器组件,才能由spring管理该组件;属性配置注入
<bean>
<property name="lastNamex" value="字面量/${key}从环境变量或者配置文件中获取值/#{SpEL}"></property><!--#{SpEL是spring的表达式语言}-->
</bean>
等价于<==>
@Component
//@ConfigurationProperties(prefix = "person")
public class Personx {
@Value("${personx.lastNamex}")
private String lastNamex;
@Value("#{11*2}")
private Integer agex;
@Value("true")
private Boolean bosx;
private Date birthx;
private Map<String, Object> mapsx;
private List<Object> listsx;
private Dog dogx;
//...
}
说明:
- @ConfigurationProperties和@Value
前者可以批量注入配置文件中的属性,后者需要一个个的指定;
前者支持支持驼峰命名和-/_的自动转换(松散语法绑定),后者不支持;
前者不支持SpEL表达式语言,后者支持;
前者支持JSR303配置文件数据校验(@Validated、@Email等),后者不支持;
前置支持复杂类型的数据封装(如map),后者不支持;
如果只是为了获取配置文件中的一个值那么使用后者 ,如果我们专门编写了一个javaBean和配置文件进行映射,那么使用后者批量注入;
注意:
-
@ConfigurationProperties默认从全局配置文件中获取值;
@PropertySource(value={“classpath:person.properties”})加载指定的配置文件,然后批量注入;
@ImportResource(locations={“classpath:spring-xxx.xml”}):导入Spring配置文件,让配置文件里面内容生效【springboot里面没有spring配置文件,也不能自动识别到我们自己编写的配置文件,那么要向让我们编写的spring xml配置文件生效,加载进来,就需要使用该注解标注在一个类(如主类)上;编写配置文件的方式不建议了】 -
springboot推荐给容器添加组件的方式:配置类
@Configuration 告诉springboot当前类是一个配置类,相当于之前的spring配置文件;我们在配置文件中使用<bean/>添加组件,现在使用@Bean添加Bean组件;
@Bean:写在方法上,把方法的返回值添加到容器中,容器中这个组件默认的id就是方法名; -
配置文件占位符
-
RandomValuePropertySource:配置文件可以使用的随机数
# ${random.value} # ${random.int} # ${random.long} # ${random.int(10)} # ${random.int[1024,65536] app.name=MyApp app.description=${app.name} is a Spring Boot application # 可在配置文件中引用前面配置过的属性(优先级是前面配置过的后面才可以使用) # ${app.name:默认值}来指定找不到属性时的默认值,如果没有写默认值时,那么输出的是表达式原样
-
springboot加载默认配置文件application.properties/application.yml顺序:
-file:./config/
-file:./
-classpath:/config/
-classpath:/
优先级由高到低;
高优先级配置覆盖低优先级配置;
springboot会扫描所有这四个目录下的配置文件,高低优先级会形成互补配置;
可以通过spring.config.location来改变默认配置文件位置,这个配置是在命令行中实现的,配置在配置文件中无效(注意命令行中指定的参数具有最高优先级);
除上述配置之外spring还支持很多位置的配置文件加载,如下外部配置文件的加载; -
springboot加载外部配置文件application.properties/application.yml
springboot也可以从以下位置加载配置,优先级从高到低;高优先级覆盖低优先级;所有配置互补;- 命令行参数中;
- 来自java:comp/env的JNDI属性;
- java系统属性(System.getProperties()):虚拟机系统属性;
- 操作系统环境变量;
- RandomValuePropertySouce配置的random.*属性值
- jar包外的application-{profile}.properties或application.yml(有spring.profile)配置文件
- jar包内的application-{profile}.properties或application.yml(有spring.profile)配置文件
- jar包外的application.properties或application.yml(没有spring.profile)配置文件
- jar包内的application.properties或application.yml(没有spring.profile)配置文件
- @Configuration注解类上的@PropertySource
- 通过SpringApplication.setDefaultProperties指定的默认属性
springboot自动配置原理
- springboot启动加载主配置类,主配置类开启自动配置功能 @EnableAutoConfiguration
- @EnableAutoConfiguration作用:
- 利用AutoConfigurationImportSelector给容器中导入一些组件(xxxAutoConfiguration类);
每一个xxxAutoConfiguration类都是容器的一个组件,都加入到容器中,用他们来做自动配置;
- 利用AutoConfigurationImportSelector给容器中导入一些组件(xxxAutoConfiguration类);
//给容器中导入一些组件
public String[] selectImports(AnnotationMetadata annotationMetadata) {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
}
//获取候选配置项,并导入组件
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
}
//加载自动配置组件
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
//扫描所有jar包类路径下的META-INF/spring.factories文件
Enumeration urls = classLoader.getResources("META-INF/spring.factories");
//遍历扫描到的文件
while(urls.hasMoreElements()) {
//遍历某个扫描到的文件获取到一个properties对象
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
//遍历properties对象内容
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
//EnableAutoConfiguration对应的很多xxxAutoConfiguration配置被拆分成数组形式
String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
String[] var10 = factoryImplementationNames;
int var11 = factoryImplementationNames.length;
//遍历所有要加载的xxxAutoConfiguration类String配置,放入List<String>待返回和加载
for(int var12 = 0; var12 < var11; ++var12) {
String factoryImplementationName = var10[var12];
((List)result.computeIfAbsent(factoryTypeName, (key) -> {
return new ArrayList();
})).add(factoryImplementationName.trim());
}
}
}
}
- 每一个xxxAutoConfiguration做自动配置功能,以HttpEncodingAutoConfiguration为例解释自动配置原理
//表示这是一个配置类,给容器添加组件
@Configuration(proxyBeanMethods = false)
//启用指定类的ConfigurationProperties功能,将配置文件对应的值和ServerProperties类绑定,并将ServerProperties加入到spring容器中
@EnableConfigurationProperties({ServerProperties.class})
//@Conditional是spring底层注解,根据不同的条件,如果满足那么整个配置类中的配置就会生效,如下面这个配置判断当前应用是否是web应用,如果是那么当前xxxAutoConfiguration配置类就会生效,否则不生效
@ConditionalOnWebApplication(type = Type.SERVLET)
//判断是否有指定的类CharacterEncodingFilter(springMVC解决乱码的类,原来配置在web.xml中使其起作用的)存在
@ConditionalOnClass({CharacterEncodingFilter.class})
//判断配置文件中是否存在指定的配置server.servlet.encoding.enabled;如果不存在也是正确的,也就是说即使我们配置文件中没有配置server.servlet.encoding.enabled=true,那么默认也是生效的
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = {"enabled"}, matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
private final Encoding properties;
//properties在构造初始化中从ServerProperties中获取,而ServerProperties已经和配置文件映射绑定且加入到了spring容器中
public HttpEncodingAutoConfiguration(ServerProperties properties) {
this.properties = properties.getServlet().getEncoding();
}
//该配置类生效时,为spring添加一个组件CharacterEncodingFilter,filter字符集从properties中获取
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
filter.setEncoding(this.properties.getCharset().name());
return filter;
}
}
所有配置文件能配置的属性都在xxxProperties类中封装着,配置文件能配置什么就可以参考这个功能对应的xxxProperties类
//从配置文件中获取指定的值和Bean的属性进行绑定
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
private final ServerProperties.Servlet servlet;
}
- spring自动配置原理总结:
spring会根据不同条件判断,配置类是否生效;
配置类一旦生效,配置类会给容器添加各种组件;
这些组件的属性都是从对应的properties类中获取到的;
这些properties类中的属性又是和配置文件绑定的; - 核心
- spring会加载大量的自动配置类;
- 首先需要看一下我们的功能有没有springboot默认写好的自动配置类;
- 若有,则再来看自动配置类中配置了哪些组件,只要我们要用的组件有,那么我们就不需要再来配置了,若没有那么就需要我们自己写对应的配置类把我们需要的配置配过去;
- 给容器中自动配置类添加组件的时候,会从properties类中获取属性,我们可以在配置文件中指定这些属性的值;
- xxxAutoConfiguration:自动配置类,给容器添加组件;
- xxxProperties:封装配置文件中相关属性;
- 附1:@Conditional注解
-
按条件使配置类生效,配置类不生效,内部配置和组件装配都不会生效;
-
相关注解扩展
-
自动配置类大多都会有一定的加载条件
查看有哪些配置类生效的方法:我们可以开启springboot的debug模式:在配置文件中添加debug:true配置,启动时控制台会打印自动配置报告;
-