<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
@SpringBootApplication public class MainSpringBoot { public static void main(String[] args) { SpringApplication.run(MainSpringBoot.class,args); } }
main
方法访问控制层映射 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent> <!--上面的父项目又依赖下面的父项目--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>1.5.9.RELEASE</version> <relativePath>../../spring-boot-dependencies</relativePath> </parent>
第一个父项目用来加载Spring Boot启动需要加载的插件和资源文件
第二个父项目用来加载所有的依赖版本,所以每次导入依赖的时候不需要书写版本号,spring boot默认会导入这个父项目中的版本。如果当前依赖在spring boot中没有进行依赖版本的控制,则需要书写版本号
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <!--上面的依赖依赖下面的父项目--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starters</artifactId> <version>1.5.9.RELEASE</version> </parent>
spring-boot-starter-web
导入了一系列的web应用可以使用到的依赖 spring-boot-starters
顾名思义,starters使用了复数,即为springboot启动器的合集 spring-boot-starter-parent
然后通过这个依赖获取了所有可能使用到的依赖的版本 @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 {
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration {
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({EnableAutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration {
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import({Registrar.class}) public @interface AutoConfigurationPackage {
类 Registrar
是抽象类 AutoConfigurationPackages
的静态内部类,在 Registrar
中调用 registerBeanDefinitions
,该方法内部又调用 AutoConfigurationPackages
的另一个静态内部类 PackageImport
执行包导入。
debug模式下的运行结果为:我们自己的主程序入口的所在包,即 springboot会扫描当前主程序所在包及其子包的所有文件
EnableAutoConfigurationImportSelector
继承 AutoConfigurationImportSelector
类,其父类存在一个 selectImports
方法。 this.getCandidateConfigurations(annotationMetadata, attributes);
获得相应的配置信息 getCandidateConfigurations
方法内部,通过 SpringFactoriesLoader.loadFactoryNames
加载配置文件,最后作为一个list集合返回。具体加载的配置文件为 META-INF/spring.factories
这是所有的自动导入的配置。有了这些自动导入,所以我们在使用的时候就不需要自己去配置,直接使用相应的功能即可。
最新版本的springboot的@EnableAutoConfiguration注解发生了一些变化,不过和之前版本几乎相同。
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration {
AutoConfigurationImportSelector.class
类,并且内部导入的组件从96增加到了124个 Spring-boot-autoconfigure
jar包
该包下的 META-INF/maven/spring.factories
文件中存放了所有的自动导入的配置
YML通过使用空格和缩进来决定层级关系。相比于XML和JSON格式来说可以更好的作为配置文件
person: name: 张三 sex: 男
等价于
<person> <name>张三</name> <sex>男</sex> </person>
属性:空格值
下面是YML对应的多种数据类型的写法
person: name: 张三 age: 12 accounts: [a1,a2,a3] tels: - 123456 - 456789 - 789798 dogs: {frist:'12/n12',second:"12/n12"} cats: frist: 12 second: 13 brithday: 2018/12/8 sex: true
通过使用 @ConfigationProperties(prefix='属性名')
注解,参数指定需要注入的属性名。即上面YML数据的person
@ConfigationProperties
注解的时候需要指定该Bean为容器中的组件,否则该注解无作用。 使用场景 | @ConfigrationProperties | @Value |
---|---|---|
松散绑定 | 支持 | 不支持 |
SPEL | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂类型注入 | 支持 | 不支持 |
@Validated
注解实现,指定该类需要进行数据校验,具体实现通过 @Email
, @Min
, @Max
等注解实现 注:两者的使用场景,YML适用于批量注入数据;Properties适用于单个数据的注入
@PropertiesSource
和 @ImportResource
注解 出现背景:由于默认的springboot项目仅仅可以存在两个配置文件(application.properties和application.yml),而为了可读性,所以会将不同功能的配置文件分开。
作用:导入一个或多个配置文件
使用方法:@PropertiesSource(value={"classpath:person.properties","classpth:person.yml"}),之后通过@Value或者@ConfigationProperties注解注入对应值
出现背景:在之前的SSM项目整合的时候通常会使用xml进行配置,而springboot默认不读取xml文件,所以如果想要编写xml文件并且在springboot项目中使用的话,就需要使用@ImportResource注解
作用:导入一个或多个配置文件,将在xml中配置的信息导入到spring组件中
使用方式:@ImportResource({"classpath:bean.xml"})
${random.uuid},${random.int},${random.int(10,20)}
person.frist-name=123 person.last-name=123 person.sex=${person.frist-name:1}
注:通过$(frist-name:默认值)来为这个属性指定一个默认值
在实际开发中,不同的生产环境所需要的配置也不相同,所以需要多种配置文件去对不同的环境进行适应
profiles文件的格式:application-profiles.properties
例:application-dev.properties或者application-pro.properties等
在主配置文件中,通过spring.profiles.active=dev来激活对应的配置
yml文件支持多文档,通过 ---
来分割不同的文档
server: port: 8082 servlet: context-path: /demo2 spring: profiles: active: dev --- spring: profiles: dev --- spring: profiles: pro
java -jar spring…….jar --spring.profiles.active=dev -Dspring.profiles.active=dev
配置文件的加载存在四种加载方式,可以通过不同的配置文件的加载时间,来对项目进行不同环境的配置和升级
以上的顺序即为springboot 加载配置文件的顺序
在命令行中通过 java -jar spring…….jar --spring.config.loation=盘符
命令行参数方式。
java -jar spring……jar --server.port=8082 --server.servlet.context-path=/abc --spring.config.location=盘符
来自java:comp/env的JNDI属性
Java系统属性
操作系统环境变量
RandomValuePropertySource配置的random.*属性值
和jar包在同一路径下的application.properties文件
@Configuration注解类上的@PropertySource
在上面讲解 springBoot
主配置类的时候,提到了 @EnableAutoConfiguration
注解。这个注解给spring容器中导入了一些组件,这些组件来源于 spring-boot-autoconfigure-2.2.2.RELEASE.jar!/META-INF/spring.factories
文件,总共有124个
现在我们刨析一个组件的源码,看一下springboot是如何进行配置的。
@Configuration( proxyBeanMethods = false ) @EnableConfigurationProperties({HttpProperties.class}) @ConditionalOnWebApplication( type = Type.SERVLET ) @ConditionalOnClass({CharacterEncodingFilter.class}) @ConditionalOnProperty( prefix = "spring.http.encoding", value = {"enabled"}, matchIfMissing = true ) public class HttpEncodingAutoConfiguration {
@EnableConfigurationProperties
注解导入了一个 HttpProperties
类 @ConfigurationProperties( prefix = "spring.http" ) public class HttpProperties { public static class Encoding { public static final Charset DEFAULT_CHARSET; private Charset charset; private Boolean force; private Boolean forceRequest; private Boolean forceResponse; private Map<Locale, Charset> mapping;
这个类导入了配置文件spring.http,也就是说我们在自己的配置文件中可以通过spring.http为HttpProperties中的属性赋值,所以为Encoding中的属性赋值的时候需要通过,spring.http.encoding.charset=UTF-8的方式,来进行赋值。
@ConditionalOnClass
注解都是由 @Conditional
注解演变过来的 @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
属性;可以在控制台中打印自动配置报告,这样我们就可以知道哪些配置类生效了。 Positive matches: //生效的自动配置类 ----------------- AopAutoConfiguration matched: - @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition) AopAutoConfiguration.ClassProxyingConfiguration matched: - @ConditionalOnMissingClass did not find unwanted class 'org.aspectj.weaver.Advice' (OnClassCondition) - @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition) DispatcherServletAutoConfiguration matched: - @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet' (OnClassCondition) - found 'session' scope (OnWebApplicationCondition) Negative matches: //没有自动配置的 ----------------- ActiveMQAutoConfiguration: Did not match: - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition) AopAutoConfiguration.AspectJAutoProxyingConfiguration: Did not match: - @ConditionalOnClass did not find required class 'org.aspectj.weaver.Advice' (OnClassCondition) ArtemisAutoConfiguration: Did not match: - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)