十、StringBoot原理
1、配置优先级
SpringBoot中支持三种格式的配置文件:①application. properties;②application.yml ;③application.yaml
配置优先级:properties > yml > yaml
SpringBoot除了支持配置文件属性配置,还支持Java系统属性和命令行参数的方式进行属性配置。
注意:Springboot项目进行打包时,需要引入插件spring-boot-maven-plugin (基于官网骨架创建项目,会自动添加该插件)
2、Bean管理
2.1 从IOC容器中获取Bean对象
默认情况下,Spring项目启动时,会把bean都创建好放在IOC容器中,如果想要主动获取这些bean,可以通过如下:
-
根据名字获取Bean
javaObject getBean(String name)
-
根据类型获取Bean
java<T> T getBean(Class<T> requiredType)
-
根据name获取bean ( 带类型转换)
java<T> T getBean (String name , Class<T> requiredType)
java
@SpringBootTest
class MybatisTestApplicationTests {
@Autowired
private ApplicationContext applicationContext; //注入IOC容器对象
@Test
void getBean(){
//通过IOC对象调用方法获取对应的Bean对象
//1、根据Bean名称获取Bean对象(如果没有指定Bean对象名称,那么默认就是类名首字母小写).返回类型是Object需要强转
UserController uc1= (UserController) applicationContext.getBean("userController");
System.out.println(uc1);
//2、根据Bean的类型来获取Bean对象
UserController uc2=applicationContext.getBean(UserController.class);
System.out.println(uc2);
//3、根据name获取bean ( 带类型转换)
UserController uc3=applicationContext.getBean("userController",UserController.class);
System.out.println(uc3);
}
}
注意:上述所说的[Spring项目启动时, 会把其中的bean都创建好] 还会受到作用域及延迟初始化影响,这里主要针对于默认的单例非延迟加载的bean而言。
2.2 Bean的作用域
Spring支持五种作用域,后三种在web环境才生效:
作用域 | 说明 |
---|---|
singleton | 容器内 同名称的Bean只有一个实例(单例) 默认 |
prototype | 每次使用Bean时都会创建新的实例(非单例) |
request | 每个请求范围内都会创建新的实例(web环境中,了解) |
session | 每个会话范围内都会创建新的实例(web环境中,了解) |
application | 每个应用范围内会创建新的实例(web环境中,了解) |
- 默认情况下Bean的初始化是在项目启动的时候进行的,不过在对应类上使用注解:@Lazy (懒惰的),可以使Bean的初始化延迟到获取Bean对象的时候才进行初始化。
- 在对应类上使用注解:@Scope("作用域") 来设置作用域的类型:如:@Scope("prototype")
- 实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性。
java
@Scope("prototype")
@RestController
@RequestMapping("/users")
public class UserController {
}
2.3 第三方Bean的配置
需要下载第三方的jar包时,通常都是只读的,无法在其中加@Component注解,加类交给IOC容器管理。
这时就可以使用注解:@Bean 如果要管理的bean对象来自于第三方(不是自定义的) , 是无法用@Component及衍生注解声明bean的,就需要用到@Bean注解。
若要管理的第三方bean对象,建议对这些bean进行集中分类配置,可以通过@Configuration注解声明一个配置类。
java
//定义一个配置类
@Configuration
public class CommonConfig {
@Bean //将方法返回值交给IOC容器管理,成为IOC容器的bean对象
//通过@Bean注解的name/value,属性指定bean名称,如果未指定,默认是方法名
public SAXReader saxReader(){
return new SAXReader();
}
}
//如果要使用,直接使用@Autowird 注入就行
如果想要在方法中进行注入对应的Bean,那么直接使用形参的方式来注入:
java
//定义一个配置类
@Configuration
public class CommonConfig {
@Bean
//根据形参自动注入userController对象
public SAXReader saxReader(UserController userController){
System.out.println(userController)
return new SAXReader();
}
}
注意:
- 通过@Bean注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名。
- 如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配。
3、SpringBoot原理
3.1 起步依赖原理
通过Maven的依赖传递的特性来进行自动依赖的导入,意思就是导入很少的依赖,就可以依次导入他们相关联的依赖。
3.2 自动配置原理
SpringBoot的原理就是,自动配置的原理,也就是如何将jar包中的配置类、Bean交给IOC容器管理的。
SpringBoot的自动配置就是当spring容器启动后,一些配置类、bean对象就自动存入到了I0C容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。
3.2.1 @ComponentScan组件扫描
在项目中不是所有被导入的依赖加上对应的配置Bean都会交给IOC容器管理,在启动类中:@SpringBootApplication会进行扫描,默认只有在该项目包中的依赖才会被扫描到,并且加入到IOC容器中。不过可以在启动类中使用注解:@ServletComponentScan 来配置扫描包的范围。
java
@ComponentScan( {"com.examp1e", " com.yhzy"})
@SpringBootApplication
public class SpringbootWebConfig2Application {
}
3.2.1 @lmport导入
使用@Import导入的类会被Spring加载到IOC容器中,导入形式主要有以下几种:普通类、配置类、ImportSelector接口实现类;@EnableXxxx注解,封装@Import注解
java
@Import ({TokenParser.class}) //导入普通类,交给IOC容器管理
@Import ({HeaderConfig.class}) //导入配置类,交给IOC容器管理
@Import ( {MyImportSelector.class}) //导入ImportSelector接口实现类
@SpringBootApplication
public class SpringbootWebCon fig2Appl ication {
public static void main (String[] args) {
SpringApp1ication.run(SpringbootWebConfig2Application.class, args) ;
}
}
3.2.2 @Conditional
作用:按照一定的条件进行判断, 在满足给定条件后才会注册对应的bean对象到Spring I0C容器中。
位置:方法、类
@Conditional 本身是一个父注解,派生出大量的子注解:
@ConditionalOnClass: 判断环境中是否有对应字节码文件,才注册bean到IOC容器。
@ConditionalOnMissingBean:判断环境中没有对应的bean (类型或名称),才注册bean到IOC容器。
@ConditionalOnProperty:判断配置文件中有对应属性和值,才注册bean到IOC容器。
java
@Configuration
public class HeaderConfig {
@Bean
@Conditional0nClass (name= "io.jsonwebtoken.Jwts") //环境中存在指定的这个类,才会将该bean加入IOC容器中
public HeaderParser headerParser () {
return new HeaderParser() ;
}
@Bean
@ConditionalOnMissingBean //不存在该类型的bean,才会将该bean加入IOC容器中 --- 指定类型(value属性)或名称(name属性)
@ConditionalOnProperty (name="name" havingValue="yhzy")//配置文件中存在指定的属性与值, 才会将该bean加入IOC容器中
public HeaderGenerator headerGenerator() {
return new HeaderGenerator() ;
}
}
3.3 自定义starter
在实际开发中,经常会定义一些公共组件,提供给各个项目团队使用。而在SpringBoot的项目中 ,一般会将这些公共组件封装为SpringBoot的starter。
案例:
需求:自定义aliyun-oss-spring-boot-starter, 完成阿里云0SS操作工具类AliyunOSSUtils的自动配置。
目标:引入起步依赖引入之后,要想使用阿里云0SS,注入AliyunOSSUtils直接使用即可。
实现步骤:
- 创建aliyun-oss-spring-boot-starter模块(主要作用依赖管理)
- 创建aliyun-oss-spring-boot-autoconfigure模块,在starter中引入该模块
- 在aliyun-oss-spring-boot-autoconfigure模块中的定义自动配置功能,并定义自动配置文件META-INF/spring/ xxxx.imports
具备实现步骤如下:
一、创建aliyun-oss-spring-boot-starter模块
1、按照规范创建对应的项目,不需要提前选择任何依赖。
2、删不需要文件和目录,只保留 (.iml 和pom.xml文件)
3、清理pom.xml 里面不需要的依赖(后面需要引入创建的aliyun-oss-spring-boot-autoconfigure依赖)
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-oss-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
二、创建aliyun-oss-spring-boot-autoconfigure模块,在starter中引入该模块(需要web开发依赖)
1、创建对应模块,将除sec目录和.iml、配置文件、pom.xml文件删除;将src下的启动类和测试类也删除
2、将pom文件中无用的依赖进行删除,并去aliyun-oss-spring-boot-starter模块的依赖文件中引入该模块
xml
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
</dependency>
三、在aliyun-oss-spring-boot-autoconfigure模块中的定义自动配置功能
1、引用阿里云OSS相关依赖
xml
<!-- 阿里云OSS-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
2、将阿里云OSS的工具类和参数实体类导入进来,并进行修改
java
package com.aliyun.oss;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.UUID;
//将类交给IOC容器管理(这样就用于去创建对象来调用其方法了)
//@Component
//通过样例将OSS打造为一个工具类
public class AliyunOSS {
// Endpoint以华北2(北京)为例,其它Region请按实际情况填写。 概括->外网访问
// @Value("${aliyun.oss.endpoint}")
// private String endpoint;
// // 填写Bucket名称,例如examplebucket。
// @Value("${aliyun.oss.bucketName}")
// private String bucketName;
private AliOSSProperties aliOSSProperties;
public AliOSSProperties getAliOSSProperties() {
return aliOSSProperties;
}
public void setAliOSSProperties(AliOSSProperties aliOSSProperties) {
this.aliOSSProperties = aliOSSProperties;
}
//文件上方法(返回上传后文件的访问路径)
public String upload(MultipartFile file) throws Exception {
//获取阿里云oss参数
String endpoint = aliOSSProperties.getEndpoint() ;
String bucketName = aliOSSProperties.getBucketName () ;
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
//1、获取上传文件的输入流
InputStream inputStream=file.getInputStream();
//2、避免覆盖,生成UUID作为文件名
String fileFullName=file.getOriginalFilename();
String fileName= UUID.randomUUID().toString()+fileFullName.substring(fileFullName.lastIndexOf("."));
// 上传到OSS
OSS ossClient=new OSSClientBuilder().build(endpoint,credentialsProvider);
ossClient.putObject(bucketName,fileName,inputStream);
//获取文件上传后的路径:https://bucket的名字.地区的路径/文件名字
String url=endpoint.split("//")[0]+"//"+bucketName+"."+endpoint.split("//")[1]+"/"+fileName;
//关闭 ossClient
ossClient.shutdown();
//返回文件访问的路径
return url;
}
//文件上方法(返回上传后文件的访问路径)
public String update(MultipartFile file,String filePath) throws Exception {
//获取阿里云oss参数
String endpoint = aliOSSProperties.getEndpoint() ;
String bucketName = aliOSSProperties.getBucketName () ;
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
//1、获取上传文件的输入流
InputStream inputStream=file.getInputStream();
//2、从文件路径中截取出文件名,使其覆盖远有我文件,达到修改的效果。
String fileName =filePath.substring(filePath.lastIndexOf("/")+1);
// 上传到OSS
OSS ossClient=new OSSClientBuilder().build(endpoint,credentialsProvider);
ossClient.putObject(bucketName,fileName,inputStream);
//关闭 ossClient
ossClient.shutdown();
//返回文件访问的路径
return fileName;
}
}
java
// AliOSSProperties配置参数实体类
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {
private String endpoint;
private String bucketName;
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getBucketName() {
return bucketName;
}
public void setBucketName(String bucketName) {
this.bucketName = bucketName;
}
}
3、在目录aliyun\oss创建一个配置类,并配置对应的工具类对象
java
//配置类
@Configuration
@EnableConfigurationProperties(AliOSSProperties.class) //将AliOSSProperties其交给IOC管理
public class AliOSSAutoConfiguration {
//外部Bean对象
@Bean
//注入对象直接通过参数形式
public AliyunOSS aliyunOSS(AliOSSProperties aliOSSProperties){
AliyunOSS aliyunOSS=new AliyunOSS();
aliyunOSS.setAliOSSProperties(aliOSSProperties);
return aliyunOSS;
}
}
4、在resource目录下创建目录META-INF\spring,并在创建的目录下创建名为(org.springframework.boot.autoconfigure.AutoConfiguration.imports)的文件
org.springframework.boot.autoconfigure.AutoConfiguration.imports文件内容:是自动配置类的全类名
txt
com.aliyun.oss.AliOSSAutoConfiguration
四、测试
1、创建一个测试模块,导入web依赖、lombok依赖和创建的阿里云oss-starter依赖
xml
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-oss-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
2、在yml配置文件中填写oss的配置
yml
#阿里云OSS配置
aliyun:
oss:
endpoint: https://oss-cn-beijing.aliyuncs.com
bucketName: yhzy-resource
3、创建Controller层,并写一POST接口,注入阿里云OSS的bean对象,通过接口测试工具对其测试
java
@RestController
@RequestMapping("/upload")
public class Upload {
@Autowired
private AliyunOSS aliyunOSS;
@PostMapping
public String upload(MultipartFile file) throws Exception {
String path= aliyunOSS.upload(file);
return path;
}
}