文章目录
配置优先级
SpringBoot中支持三种格式的配置文件:properties、yml、yaml
注意:虽然springboot支持多种格式配置文件,但是在项目开发时,推荐统一使用一种格式的配置(yml是主流)
SpringBoot除了支持配置文件属性配置,还支持Java系统属性和命令行参数的方式进行属性配置
java系统属性:
-Dserver.port=9000
命令行参数:
--server.port=10010
项目打包后,在运行时指定java系统属性和命令行参数:
① 执行maven打包指令package
② 执行java指令,运行jar包
java -Dserver.port=9000 -jar tlias-web-management-0.0.1-SNAPSHOT.jar --server.port=10010
java后跟java系统属性,jar文件后跟命令行参数
优先级:命令行参数 > java系统属性 > application.properties > application.yml > application.yaml
Bean管理
1.获取bean:
默认情况下,Spring项目启动时,会把bean都创建好放在IOC容器中,如果想要主动获取这些bean,可以通过如下方式:
根据name获取bean:
Object getBean(String name)
根据类型获取bean:
<T> T getBean(Class<T> requiredType)
根据name获取bean(带类型转换):
<T> T getBean(String name, Class<T> requiredType)
示例:
@Autowired
private ApplicationContext applicationContext; //IOC容器对象
//获取bean对象
@Test
public void testGetBean(){
//根据bean的名称获取
DeptController bean1 = (DeptController) applicationContext.getBean("deptController");
System.out.println(bean1);
//根据bean的类型获取
DeptController bean2 = applicationContext.getBean(DeptController.class);
System.out.println(bean2);
//根据bean的名称 及 类型获取
DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);
System.out.println(bean3);
}
2.bean作用域:
Spring支持五种作用域,后三种在web环境才生效:
作用域 | 说明 |
---|---|
singleton | 容器内同名称的bean只有一个实例(单例)(默认) |
prototype | 每次使用该bean时会创建新的实例(非单例) |
request | 每个请求范围内会创建新的实例(web环境中,了解) |
session | 每个会话范围内会创建新的实例(web环境中,了解) |
application | 每个应用范围内会创建新的示例(web环境中,了解) |
可以通过@Scope
注解来进行配置作用域
@Scope("prototype")
@RestController
@RequestMapping("/depts")
public class DeptController {
}
注意:
① 默认singleton的bean,在容器启动时被创建,可以使用@Lazy
注解来延迟初始化(延迟到第一次使用时)
② prototype的bean,每一次使用该bean的时候都会创建一个新的实例
③ 实际开发中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性
3.第三方bean:
如果要管理的bean对象来自于第三方(不是自定义的),是无法用@Component
及衍生注解声明bean的,就需要用到@Bean
注解
若要管理第三方bean对象,建议对这些bean进行集中分类配置,可以通过@Configuration
注解声明一个配置类
示例:
@Configuration //配置类
public class CommonConfig {
//声明第三方bean
@Bean //将当前方法的返回值对象交给IOC容器管理,成为IOC容器bean
//通过@Bean注解的name/value属性指定bean名称,如果未指定,默认是方法名
public SAXReader saxReader() {
return new SAXReader();
}
}
注意:
① 通过@Bean
注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名
② 如果第三方bean需要依赖其他bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配
@Component
及衍生注解与@Bean
注解使用场景:
① 项目中自定义的,使用@Component
及衍生注解
② 项目中引入第三方的,使用@Bean
注解
SpringBoot原理
1.起步依赖
若不使用springboot,而使用spring框架进行web程序开发,此时需引入依赖:
若使用springboot,则只需要引入一个依赖:
原理在于:Maven的依赖传递
2.自动配置
SpringBoot的自动配置就是当spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作
案例:将依赖中所提供的Bean和配置类加载到当前项目中的IOC容器
<dependency>
<groupId>com.example</groupId>
<artifactId>itheima-utils</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
方案一:@ComponentScan
组件扫描
即使对应依赖中的类加上了@Component
或其他声明Bean的注解,也不能直接加入当前项目的IOC容器。原因在于启动类的@SpringBootApplication
注解中的@ComponentScan
只会扫描当前包及其子包,不会扫描其他包
因此需要对@ComponentScan
的范围进行修改
@ComponentScan({
"com.example", "com.itheima"})
@SpringBootApplication
public class SpringbootWebConfig2Application{
}
但是如果依赖较多,需要扫描的包就会很多,会比较繁琐;且一个包下可能会有很多类,而Bean以及配置类可能并不多,所以性能也较低
方案二:@Import
导入
使用@Import
导入的类会被Spring加载到IOC容器中,导入形式主要有以下几种:
① 导入普通类
@Import({
TokenParser.class})
@SpringBootApplication
public class SpringbootWebConfig2Application{
}
② 导入配置类(此时配置类中所有的Bean对象都会被导入)
@Import({
HeaderConfig.class})
@SpringBootApplication
public class SpringbootWebConfig2Application{
}
③ 导入ImportSelector接口实现类
public class MyImportSelector implements ImportSelector {
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{
"com.example.HeaderConfig"}; //返回类的全类名的数组
}
}
@Import({
MyImportSelector.class})
@SpringBootApplication
public class SpringbootWebConfig2Application{
}
④ @EnableXxxx
注解,封装@Import
注解(这个注解一般是由第三方依赖提供的),这种方式也是SpringBoot方式采用的
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)
public @interface EnableHeaderConfig {
}
@EnableHeaderConfig
@SpringBootApplication
public class SpringbootWebConfig2Application{
}
源码跟踪:
@SpringBootApplication
public class SpringbootWebConfig2Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootWebConfig2Application.class, args);
}
}
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {
@Filter(
type = FilterType.CUSTOM,
classes = {
TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {
AutoConfigurationExcludeFilter.class}
)})
public @interface SpringBootApplication {
...
}
@SpringBootApplication
:
该注解标识在SpringBoot工程引导类上,是SpringBoot中最重要的注解。该注解由三个部分组成:
① @SpringBootConfiguration
:该注解与@Configuration
注解作用相同,用来声明当前也是一个配置类
② @ComponentScan
:组件扫描,默认扫描当前引导类所在包及其子包
③ @EnableAutoConfiguration
:SpringBoot实现自动化配置的核心注解
在@EnableAutoConfiguration
注解中,底层封装了一个@Import
注解,这个注解中指定的是一个ImportSelector接口的实现类,这个实现类实现了接口中的方法selectImports,返回值封装的是要导入到IOC的类的全类名。在这个方法中,加载了两个文件,一个是spring.factories(早期配置文件,后面会被移除),另一个是spring文件夹下的AutoConfiguration.imports文件。这个文件定义的是配置类的全类名,这些配置类中用了@Bean
注解来声明Bean对象
注意:这些并不会全部注册为IOC容器的bean,由于有@ConditionalMissingBean
注解,使得其能保证按条件装配,当满足一定的条件之后才会将这个bean注册到IOC中
@Conditional
:
作用:按照一定的条件进行判断,在满足给定条件后才会注册对应的bean对象到Spring IOC容器中
位置:方法、类
@Conditional
本身是一个父注解,派生出大量的子注解:
① @ConditionalOnClass
:判断环境中是否有对应字节码文件,若没有才注册bean到IOC容器
② @ConditionalOnMissingBean
:判断环境中没有对应的bean(类型或名称),才注册bean到IOC容器
③ @ConditionalOnProperty
: 判断配置文件中有对应属性和值,才注册bean到IOC容器
示例:
@Bean
@ConditionalOnClass(name = "io.jsonwebtoken.Jwts") //环境中存在指定的这个类,才会将该bean加入IOC容器中
public HeaderParser headerParser() {
...
}
@Bean
@ConditionalOnMissingBean //不存在该类型的bean,才会该bean加入IOC容器中 --- 指定类型(value) 或 名称(name)
public HeaderParser headerParser() {
...
}
@Bean
@ConditionalOnProperty(name = "name", havingValue = "itheima") //配置文件中存在指定的属性与值,才会将该bean加入IOC容器中
public HeaderParser headerParser() {
...
}
第一个主要用于判断是否引入了对应的依赖;第二个主要用于声明默认Bean对象,如果用户自定义了该对象,则使用该自定义对象,如果没有用户自定义对象,则使用默认Bean对象;第三个主要用于在引入第三方技术时,只有在配置文件中配置了对应的配置项,才会声明对应的Bean对象
案例:自定义starter
场景:在实际开发中,经常会定义一些公共组件,提供给各个项目团队使用。而在SpringBoot的项目中,一般会将这些公共组件封装为SpringBoot的starter
需求:自定义aliyun-oss-spring-boot-starter,完成阿里云OSS操作工具类AliyunOSSUtils的自动配置
目标:引入起步依赖之后,要想使用阿里云OSS,注入AliyunOSSUtils直接使用即可
步骤:
① 创建aliyun-oss-spring-boot-starter模块
② 创建aliyun-oss-spring-boot-autoconfigure模块,在starter中引入该模块
pom.xml:
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
③ 在aliyun-oss-spring-boot-autoconfigure模块中定义自动配置功能,并定义自动配置文件META-INF / spring / xxxx.imports
这个模块中还要加上之前引入的阿里云OSS相关的依赖,因为之后的类需要用到依赖中的方法
AliOSSAutoConfiguration:
@Configuration
@EnableConfigurationProperties(AliOSSProperties.class)
public class AliOSSAutoConfiguration {
@Bean
public AliOSSUtils aliOSSUtils(AliOSSProperties aliOSSProperties) {
AliOSSUtils aliOSSUtils = new AliOSSUtils();
aliOSSUtils.setAliOSSProperties(aliOSSProperties);
return aliOSSUtils;
}
}
这里多加了个@EnableConfigurationProperties
注解的原因在于,原先在AliOSSProperties类的@ConfigurationProperties
注解前是有@Component
注解的,而此时需要去掉@Component
注解,导致AliOSSProperties这个类没有注入到IOC中,因此无法使用@ConfigurationProperties
注解使properties配置文件转化成bean。此时就需要@EnableConfigurationProperties
注解来使AliOSSProperties这个类加载到IOC容器中(经过测试,这个注解也可以让引入这个依赖的模块,可以直接去注入这个类。另外,也可以直接使用@Bean
将这个类加入到IOC容器中)
而之后在参数声明了这个类的对象,这个对象会被IOC容器直接注入,且这个对象的属性与配置文件中的配置属性是对应的
AliOSSProperties:
跟之前一样,不过要删去Component注解(因为启动类和这个类不在同一个模块中)
AliOSSUtils:
跟之前一样,不过要删去Component注解,以及加上aliOSSProperties这个对象的get和set方法(因为之前是采用自动注入的方式为这个对象赋值的,而现在没有自动注入,则需要手动定义set方法让外界赋值),以及删去这个对象上的Autowired注解
org.springframework.boot.autoconfigure.AutoConfiguration.imports:
com.aliyun.oss.AliOSSAutoConfiguration