[Java]SpringBoot能力进阶
配置优先级
SpringBoot中支持三种格式的配置文件
- 优先级: application.properties文件 > application.yml文件 > application.yaml文件
SpringBoot除了通过配置文件配置属性, 还支持Java系统属性和命令行参数的方式 进行属性配置
1.在IDEA中配置java系统属性和命令行参数
2.在命令行中配置java系统属性和命令行参数
配置文件和java属性以及命令行参数的优先级
bean的管理
手动获取bean
默认情况下, Spring项目启动时, 会把bean对象都创建好放在IOC容器中, 如果需要主动获取这个bean, 可以通过下面的方法
@SpringBooTest
class SpringbootWebConfig2ApplicationTest {
@Autowired
private ApplicationContext applicationContext; //注入IOC容器对象
//获取bean对象
//根据bean的名称获取
//获取到的bean是Object类型, 所以要进行强转
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);
}
执行效果
- 默认情况下bean是单例模式, 所以拿到的是同一个bean对象
bean的作用域
Spring支持五种作用域, 后三种在web环境才生效
可以通过 @Scope("作用域值")注解 设置bean的作用域
- 默认springboot中的bean, 在容器启动时就会被创建,
- 可以使用 @Lazy注解 来延迟初始化(延迟到第一次使用时创建)
- prototype的bean, 每一次使用该bean的时候都会创建一个新的实例
- 实际开发中, 绝大部分的bean都是单例的, 不需要配置scope属性
第三方bean
如果要管理的bean对象来自于第三方, 是无法用 Component及其衍生注解 声明bean的, 而是需要SpringBoott提供的 @Bean注解 完成bean的声明
@SpringBootTest
class TliasWebManagementApplicationTests {
// 第三方bean的管理
@Test
public void testThirdBean() throws Exception {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(this.getCLass().getClassLoader().getResource('1.xml'));
Element rootElement = document.getRootElement();
String name = rootElement.element("name").getText();
String age = rootElement.element("age").getText();
System.out.printIn(name + ":" + age)
}
}
- 第三方文件是只读的, 无法通过添加 @Compoment 注解的形式完成bean的声明
- 此时使用第三方对象是只能手动创建, 但是执行效率比较低, 因为无法复用该对象, 耗费资源
在启动类中注册第三方bean对象, 非常简单, 但是不推荐, 因为启动类要保持简洁
@SpringBootApplication
public class TliasWebManagementApplication {
public static void main(String[] args) {
SpringApplication.run(TliasWebManagementApplication.class, args);
}
// 声明第三方bean
// 将当前方法的返回值对象,交给IOC容器管理,称为IOC容器的bean
@Bean
public SAXReader saxReader() {
return new SAXReader();
}
}
@SpringBootTest
class TliasWebManagementApplicationTests {
@Autowired
private SAXReader saxReader;
@Test
public void testThirdBean() throws Exception {
// 不再需要手动创建对象,而是自动注入bean对象
// SAXReader saxReader = new SAXReader();
Document document = saxReader.read(this.getCLass().getClassLoader().getResource('1.xml'));
Element rootElement = document.getRootElement();
String name = rootElement.element("name").getText();
String age = rootElement.element("age").getText();
System.out.printIn(name + ":" + age)
}
}
若要管理第三方bean对象, 建议对这些bean进行集中分类配置, 可以通过 @Configuration注解 声明配置类
@Configuration //声明为配置类
public class commonConfig {
// 声明第三方bean
// 将当前方法的返回值交给IOC容器管理,成为bean对象
@Bean
public SAXReader saxReader(DeptServer deptServer){
// 第三方bean依赖其他的bean对象, 可以通过形参声明,
// springboot会根据类型自动注入对象
System.out.printIn(deptServer);
return new SAXReader();
}
// 还可以继续声明其他bean
}
@SpringBootTest
class TliasWebManagementApplicationTests {
// 使用时注入bean
@Autowired
private SAXReader saxReader;
@Test
public void testThirdBean() throws Exception {
Document document = saxReader.read(this.getCLass().getClassLoader().getResource('1.xml'));
Element rootElement = document.getRootElement();
String name = rootElement.element("name").getText();
String age = rootElement.element("age").getText();
System.out.printIn(name + ":" + age)
}
}
- 项目中自定义的对象, 使用@Componet及其衍生注解, 即可交给IOC容器管理
- 项目引用的第三方对象, 使用 @Bean注解, 交给IOC容器管理
SpringBoot原理
Spring Boot框架简化Spring配置的核心就是 起步依赖 和 自动配置
- Spring家族的框架都是基于Spring Framework框架运行的,
- 直接基于Speing Framework进行项目开发, 需要我们进行大量的依赖引入和配置, 这个过程非常繁琐,
- 所以Spring又推出了Spring Boot框架来简化Spring Frameword的配置,
- 让我们可以专注于业务的实现, 减少框架层面的配置
起步依赖
如果使用spring框架开发, 需要自己下载用到的依赖, 还要管理依赖的版本
使用springboot开发, 只需要引入web开发的起步依赖, 就完成了依赖的配置
- 起步依赖的原理, 就是maven的依赖传递, 只要引入起步依赖, 与其相关的依赖也会被引入
- 并且项目中依赖的版本也会由起步依赖统一管理, 不会出现版本冲突的问题
自动配置
Springboot的自动配置就是当spring容器启动后, 我们自己定义的bean对象, 还有一些内置的配置类和bean对象就自动创建并存入到ioc容器中, 不需要我们手动去声明, 就可以注入使用, 从而简化开发, 省去了繁琐的配置操作
自动配置的关键: 如何把pom.xml中依赖的jar包中的配置类自动的加载到ICO容器中?
实现方案
自动配置的核心就是包扫描, 想要实现自动配置, 只需要让spring扫描到依赖包, spring就会自动把依赖包的配置类交给IOC容器管理
方案1: 在启动类中, 使用@ComponentScan() 注解修改组件扫描的范围, 把第三方包添加到组件扫描的范围内
- 实际开发中会使用很多第三方包, 如果都要手动添加, 需要频繁修改, 并不合适
方案2: 使用 @import 导入的类会被Spring加载到IOC容器中, 支持多种导入形式
- 使用导入类的方式完成自动配置, 我们要清楚的知道第三方依赖所用到的配置类和bean对象, 还是繁琐
方案3: 使用第三方提供的@EnableXxxx注解
- 第三方依赖包的作者, 肯定比我们更加清楚, 依赖包中使用到了哪些配置类,
- 所以作者会自己封装@EnableXxxx注解, 注解中使用@import注解导入使用到的配置类和bean对象
- 我们只需要使用作者提供的 @EnableXxxx注解, 就可以完成依赖的自动配置, 把依赖交给IOC容器管理
源码跟踪
@Conditional注解
原理总结
- 实现自动装配的核心注解是 @EnableAutoConfiguration
- @EnableAutoConfiguration 注解 封装了 @Import注解
- @Import注解 引入了自动配置类,
- 自动配置类 实现了selectImport方法,
- selectImport方法会读取jar包的两份配置文件
- 配置文件中 有很多自动配置类
- 满足装配条件的自动配置类会被方法返回, 最终被IOC容器管理
自定义starter
- 官方起步依赖命名: spring-boot-starter-功能:版本
- 第三方起步依赖命名: 功能-spring-boot-starter:版本
实现步骤
1.创建aliyun-oss-spring-boot-starte模块
<?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.5</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>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
// 引入自动配置模块
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
2.创建 aliyun-oss-spring-boot-auticonfigure 模块, 该模块要实现自动配置
<?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.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--阿里云OSS-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</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>
</dependencies>
</project>
3.引入文件, 并且改造部分代码
package com.aliyun.oss;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
// 手动提供get/set方法 替换 @Data注解
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getAccessKeyId() {
return accessKeyId;
}
public void setAccessKeyId(String accessKeyId) {
this.accessKeyId = accessKeyId;
}
public String getAccessKeySecret() {
return accessKeySecret;
}
public void setAccessKeySecret(String accessKeySecret) {
this.accessKeySecret = accessKeySecret;
}
public String getBucketName() {
return bucketName;
}
public void setBucketName(String bucketName) {
this.bucketName = bucketName;
}
}
package com.aliyun.oss;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;
/**
* 阿里云 OSS 工具类
* @Component 和 @Autowired 不能使用
*/
public class AliOSSUtils {
// 阿里云参数配置对象
private AliOSSProperties aliOSSProperties;
public AliOSSProperties getAliOSSProperties() {
return aliOSSProperties;
}
public void setAliOSSProperties(AliOSSProperties aliOSSProperties) {
this.aliOSSProperties = aliOSSProperties;
}
/**
* 实现上传图片到OSS
*/
public String upload(MultipartFile file) throws IOException {
//获取阿里云OSS参数
String endpoint = aliOSSProperties.getEndpoint();
String accessKeyId = aliOSSProperties.getAccessKeyId();
String accessKeySecret = aliOSSProperties.getAccessKeySecret();
String bucketName = aliOSSProperties.getBucketName();
// 获取上传的文件的输入流
InputStream inputStream = file.getInputStream();
// 避免文件覆盖
String originalFilename = file.getOriginalFilename();
String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
//上传文件到 OSS
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ossClient.putObject(bucketName, fileName, inputStream);
//文件访问路径
String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
// 关闭ossClient
ossClient.shutdown();
return url;// 把上传到oss的路径返回
}
}
4.定义自动配置类
package com.aliyun.oss;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration // 标明配置类
@EnableConfigurationProperties(AliOSSProperties.class) //把类交给IOC容器管理
public class AliOSSAutoConfiguration {
@Bean // 把对象交给IOC容器管理
public AliOSSUtils aliOSSUtils(AliOSSProperties aliOSSProperties){
AliOSSUtils aliOSSUtils = new AliOSSUtils();
aliOSSUtils.setAliOSSProperties(aliOSSProperties);
return aliOSSUtils;
}
}
5.定义自动加载文件
右键resources -> new -> Directory -> META-INF/spring
右键 META-INF/spring -> new File -> 文件名 -> ok
文件名: org.springframework.boot.autoconfigure.AutoConfiguration.imports
6.以后使用阿里云oss只需要引入我们自定义的起步依赖就可以了
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId></artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
#阿里云OSS
aliyun:
oss:
endpoint: https://oss-cn-beijing.aliyuncs.com
accessKeyId: LTAI5tFE6zMbdaLyhSvNM9J1
accessKeySecret: jeHMl9EBnCOErmomdgKrZrmCKMcKTt
bucketName: tlias-web-practice
@RestController
public class UploadController {
// 注入自定义依赖中的工具类
@Autowired
private AliOSSUtils aliOSSUtils;
@PostMapping("/upload")
public String upload(MultipartFile image) throws Exception {
//上传文件到阿里云 OSS
String url = aliOSSUtils.updload(image);
return url;
}
}