SpringBoot - 02 配置方式
1、Spring配置历史
事实上,在Spring3.0开始,Spring官方就已经开始推荐使用java配置来代替传统的xml配置了,我们不妨来回顾一下
Spring的历史:
Spring1.0时代,在此时因为jdk1.5刚刚出来,注解开发并未盛行,因此一切Spring配置都是xml格式,想象一下所有的bean都用xml配置,细思极恐啊,心疼那个时候的程序员2秒
Spring2.0时代,Spring引入了注解开发,但是因为并不完善,因此并未完全替代xml,此时的程序员往往是把xml与注解进行结合,貌似我们之前都是这种方式。
Spring3.0及以后,3.0以后Spring的注解已经非常完善了,因此Spring推荐大家使用完全的java配置来代替以前的xml,不过似乎在国内并未推广盛行。然后当Spring Boot来临,人们才慢慢认识到java配置的优雅。
2、尝试java配置
2.1、配置类方式
以前配置数据源是通过xml文件实现的,例如:
现在通过定义配置类:
数据库配置:
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://47.100.229.xxx:3306/springStudy?useSSL=false&serverTimezone=UTC jdbc.username=root jdbc.password=xxxx jdbc.initialSize=1 jdbc.minIdle=3 jdbc.maxActive=20 jdbc.maxWait=60000
配置类代码:
package rui.config; import com.alibaba.druid.pool.DruidDataSource; import jdk.nashorn.internal.objects.annotations.Property; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import javax.sql.DataSource; /*数据库配置类*/ @Configuration @PropertySource("classpath:jdbc.properties") public class JdbcConfig { @Value("${jdbc.driverClassName}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Value("${jdbc.initialSize}") private int initialSize; @Value("${jdbc.minIdle}") private int minIdle; @Value("${jdbc.maxActive}") private int maxActive; @Value("${jdbc.maxWait}") private int maxWait; @Bean public DataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); dataSource.setInitialSize(initialSize); dataSource.setMinIdle(minIdle); dataSource.setMaxActive(maxActive); dataSource.setMaxWait(maxWait); return dataSource; } }
在控制器中注入数据源,调试即可查看是否注入相关的属性值
@RestController @RequestMapping(value = "hello") public class HelloController { @Autowired private DataSource dataSource; @RequestMapping(value = "index") public String hello() { System.out.println(dataSource.toString()); return "index"; } }
2.2、属性方式
属性读取类
package rui.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component @ConfigurationProperties(prefix = "jdbc") public class JdbcProperties { private String driverClassName; private String url; private String username; private String password; private int initialSize; private int minIdle; private int maxActive; private int maxWait; public String getDriverClassName() { return driverClassName; } public void setDriverClassName(String driver) { this.driverClassName = driver; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getInitialSize() { return initialSize; } public void setInitialSize(int initialSize) { this.initialSize = initialSize; } public int getMinIdle() { return minIdle; } public void setMinIdle(int minIdle) { this.minIdle = minIdle; } public int getMaxActive() { return maxActive; } public void setMaxActive(int maxActive) { this.maxActive = maxActive; } public int getMaxWait() { return maxWait; } public void setMaxWait(int maxWait) { this.maxWait = maxWait; } }
配置类代码,现在不需要通过@value去读取每一个配置项目。
package rui.config; import com.alibaba.druid.pool.DruidDataSource; import jdk.nashorn.internal.objects.annotations.Property; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import javax.sql.DataSource; /*数据库配置类*/ @Configuration @EnableConfigurationProperties(JdbcProperties.class) public class JdbcConfig { @Bean public DataSource dataSource(JdbcProperties jdbcProperties) { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(jdbcProperties.getDriverClassName()); dataSource.setUrl(jdbcProperties.getUrl()); dataSource.setUsername(jdbcProperties.getUsername()); dataSource.setPassword(jdbcProperties.getPassword()); dataSource.setInitialSize(jdbcProperties.getInitialSize()); dataSource.setMinIdle(jdbcProperties.getMinIdle()); dataSource.setMaxActive(jdbcProperties.getMaxActive()); dataSource.setMaxWait(jdbcProperties.getMaxWait()); return dataSource; } }
2.3、更优雅的注入
@Configuration public class JdbcConfig { @Bean @ConfigurationProperties(prefix = "jdbc") public DataSource dataSource() { return new DruidDataSource(); } }
3、Yaml配置文件
3.1、多个yaml文件
当一个项目中有多个yml配置文件的时候,可以以application-**.yml命名;在application.yml中配置项目使用激活这些配置文件即可。
4、自动配置原理
使用Spring Boot之后,一个整合了SpringMVC的WEB工程开发,变的无比简单,那些繁杂的配置都消失不见了,这是如何做到的?一切魔力的开始,都是从我们的main函数来的,所以我们再次来看下启动类:
我们发现类上边有注解:@SpringBootApplication,进入源码查看:
通过这段我们可以看出,在这个注解上面,又有一个 @Configuration 注解。通过上面的注释阅读我们知道:这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了 @Configuration 的类,并且读取其中的配置信息。而 @SpringBootConfiguration 是来声明当前类是SpringBoot应用的配置类,项目中只能有一个。所以一般我们无需自己添加。
第二级的注解 @EnableAutoConfiguration ,告诉Spring Boot基于你所添加的依赖,去“猜测”你想要如何配置Spring。比如我们引入了 spring-boot-starter-web ,而这个启动器中帮我们添加了 tomcat 、 SpringMVC的依赖。此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了!
所以,我们使用SpringBoot构建一个项目,只需要引入所需框架的依赖,配置就可以交给SpringBoot处理了。除非你不希望使用SpringBoot的默认配置,它也提供了自定义配置的入口。
@ComponentScan
配置组件扫描的指令。提供了类似与 <context:component-scan> 标签的作用通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包
而我们的@SpringBootApplication注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包。因此,一般启动类会放在一个比较前的包目录中。
5、自动配置修改方案
SpringBoot为我们提供了默认配置,而默认配置生效的步骤:
- @EnableAutoConfiguration注解会去寻找 META-INF/spring.factories 文件,读取其中以
- EnableAutoConfiguration 为key的所有类的名称,这些类就是提前写好的自动配置类
- 这些类都声明了 @Configuration 注解,并且通过 @Bean 注解提前配置了我们所需要的一切实例
- 但是,这些配置不一定生效,因为有 @ConditionalOn 注解,满足一定条件才会生效。比如条件之一: 是一些 相关的类要存在
- 类要存在,我们只需要引入了相关依赖(启动器),依赖有了条件成立,自动配置生效。
- 如果我们自己配置了相关Bean,那么会覆盖默认的自动配置的Bean
- 我们还可以通过配置application.yml文件,来覆盖自动配置中的属性
1)启动器
所以,我们如果不想配置,只需要引入依赖即可,而依赖版本我们也不用操心,因为只要引入了SpringBoot提供的starter(启动器),就会自动管理依赖及版本了。因此,玩SpringBoot的第一件事情,就是找启动器,SpringBoot提供了大量的默认启动器
2)全局配置
另外,SpringBoot的默认配置,都会读取默认属性,而这些属性可以通过自定义 application.properties 文件来进行覆盖。这样虽然使用的还是默认配置,但是配置中的值改成了我们自定义的。因此,玩SpringBoot的第二件事情,就是通过 application.properties 来覆盖默认属性值,形成自定义配置。我们需要知道SpringBoot的默认属性key,非常多,可以再idea中自动提示
在spring-Boot-AutoConfigure组件内有一个spring.factories,这个文件中定义了一些自动配置的类,也包含了很多的内置自动配置组件。
6、自动配置修改例子
以WebMVC为例介绍,
导航进入这个类的源代码:
在文件中找属性配置类
也可以通过组件目录内中找到属性配置文件:
进入属性配置类,找到配置前缀和相关的配置属性。
内部包含内部类View,用来配置视图前缀和后缀的。
在xml里边是这样的:
通过application.yaml文件进行配置修改,将默认的配置属性值修改成自己的内容。
大致步骤总结: