Skip to content

配置优先级

在我们前面的课程当中,我们已经讲解了SpringBoot项目当中支持的三类配置文件: - application.properties - application.yml - application.yaml

在SpringBoot项目当中,我们要想配置一个属性,可以通过这三种方式当中的任意一种来配置都可以,那么如果项目中同时存在这三种配置文件,且都配置了同一个属性,如:Tomcat端口号,到底哪一份配置文件生效呢? yaml、yml 两种配置文件,优先级最高的是yml。 配置文件优先级排名(从高到低): 1. properties配置文件 2. yml配置文件 3. yaml配置文件 yml是最主流的方式. YML 是 YAML 的文件扩展名写法之一,本质是同一种配置文件格式,遵循 YAML 语法规则(如大小写敏感、用缩进表示层级、冒号 + 空格分隔键值等 ),都用于存储配置信息,被各类编程语言 / 框架(如 Spring Boot、Python 等)支持,可互相转换,功能完全等效。

命令行配置

  1. Java系统属性配置 (格式: -Dkey=value)
    -Dserver.port=9000
    
  2. 命令行参数 (格式:--key=value)
    --server.port=10010
    

idea

Pasted image 20250630224125命令行参数总是最高优先级.系统属性参数其次.配置文件在后面. Pasted image 20250630224342

打包时配置

Pasted image 20250719205252

java -Dserver.port=9000 -jar XXXXX.jar --server.port=10010
Pasted image 20250719205314 Pasted image 20250701215839 Pasted image 20250701215945 这些命令行参数可以直接顶替掉配置文件当中的任何属性,不仅仅是上面的port之类.具体用法可搜.

bean管理

bean作用域配置

Pasted image 20250706231138 测试类: Pasted image 20250706231259 都是一样的. 另外,这样的单例都是默认饿汉模式(容器启动时创建),如果想使用懒汉模式,可以使用@Lazy. 如果我们改成这样: Pasted image 20250706231612 也就是会有多个实例. - ApplicationContext 是 Spring 的核心容器接口,通过它可以获取 Spring 管理的 Bean - 实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性 - 不保存数据的无状态的bean使用单例,Controller,Service,Dao等bean均属于无状态的bean - 如果要保存数据,那么就需要prototype.因为如果保存数据还用单例,,那么就需要考虑线程安全的问题 Pasted image 20250719210324 Pasted image 20250719210456

第三方bean

在我们项目开发当中,有一种情况就是这个类它不是我们自己编写的,而是我们引入的第三方依赖当中提供的,那么此时我们是无法使用 @Component 及其衍生注解来声明bean的,此时就需要使用@Bean注解来声明bean 了。 Pasted image 20250706235756 这相对于引入了一个bean类. 加上bean注解后,代表当前项目在启动的时候会自动的调用该方法并且会将方法的返回值自动的交给IOC容器管理.返回值设置为需要声明的bean的类型 在构造函数里加上依赖的其他bean:(有依赖,肯定原本就有这个构造函数) Pasted image 20250719210754

然后就正常使用: Pasted image 20250706235844

如果无法访问权限的记得把yml文件中的#阿里云OSS配置文件修改成原来的配置

集中管理

Pasted image 20250707000012 上面这个配置类放到com.itheima.config包之下.注意,只要有config注解,那么肯定会被springboot扫到. - 通过@Bean注解的name 或 value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名。如: Pasted image 20250719211006 - 如果一个第三方bean需要依赖其他bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配。 比如:

// 我们自己写的
// 使用 @Service 注解,Spring会自动扫描并将其注册为一个Bean
@Service
public class OrderService {
    public void createOrder(String product) {
        System.out.println("正在创建订单,商品:" + product);
        // ... 订单创建逻辑 ...
    }
}
// 这是一个模拟的第三方库的类,我们无法修改它的代码
public class ThirdPartyPaymentClient {

    private final OrderService orderService; // 它依赖 OrderService
    private final String apiKey;

    public ThirdPartyPaymentClient(OrderService orderService, String apiKey) {
        this.orderService = orderService;
        this.apiKey = apiKey;
    }

    public void processPayment() {
        System.out.println("使用API Key: '" + apiKey + "' 进行支付处理...");
        // 在支付前,可能需要先创建一个订单
        orderService.createOrder("some-product-id");
        System.out.println("支付成功!");
    }
}
@Configuration
public class AppConfig {

    // 这个方法定义了 ThirdPartyPaymentClient 这个 Bean
    // 注意看这个方法的参数 OrderService orderService
    @Bean
    public ThirdPartyPaymentClient paymentClient(OrderService orderService) {
        // 1. **设置形参**: 我们在 paymentClient 方法上增加了一个 OrderService 类型的参数。

        // 2. **自动装配**: Spring在调用这个方法来创建 paymentClient Bean时,
        //    它会发现需要一个 OrderService 类型的参数。
        //    于是,Spring会自动在自己的容器里寻找一个已经存在的、类型为 OrderService 的Bean。
        //    在本例中,它会找到上面用@Service注解的那个OrderService实例。

        // 3. **注入**: Spring将找到的 orderService 实例作为参数传递给这个方法。

        // 4. **创建Bean**: 方法内部使用被注入的 orderService 来创建并返回 ThirdPartyPaymentClient 实例。
        String apiKey = "YOUR_SUPER_SECRET_API_KEY"; // 假设API Key来自配置文件
        return new ThirdPartyPaymentClient(orderService, apiKey);
    }
}
事实上,在参数上,OrderService orderService 是省略了autowired的.

SpringBoot原理

起步依赖

  • 通过SpringBoot所提供的起步依赖,就可以大大的简化pom文件当中依赖的配置,从而解决了Spring框架当中依赖配置繁琐的问题。 当我们引入了 spring-boot-starter-web 之后,maven会通过依赖传递特性,将web开发所需的常见依赖都传递下来。 Pasted image 20250707222720 起步依赖的原理就是Maven的依赖传递。 springboot-starter-web,这是web开发的起步依赖,在web开发的起步依赖当中,就集成了web开发中常见的依赖:json、web、webmvc、tomcat等。我们只需要引入这一个起步依赖,其他的依赖都会自动的通过Maven的依赖传递进来.

自动配置

自动配置就是当spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。 比如,在我们前面讲解AOP记录日志的那个案例中,我们要将一个对象转为json,直接注入一个Gson,然后就可以直接使用了。而我们在我们整个项目中,也并未配置Gson这个类型的bean,为什么可以直接注入使用呢? 原因就是因为这个bean,springboot中已经帮我们自动配置完毕了,我们是可以直接使用的。 Pasted image 20250707222932

自动配置的原理

假设ithema-util是一个第三方工具包.测试类是我们自己的. Pasted image 20250707223430 直接这样写会报错. - 原因在我们之前讲解IOC的时候有提到过,在类上添加@Component注解来声明bean对象时,还需要保证@Component注解能被Spring的组件扫描到。 - SpringBoot项目中的@SpringBootApplication注解,具有包扫描的作用,但是它只会默认扫描启动类所在的当前包以及子包。

那么,如何才能被扫描到呢?

@ComponentScan 组件扫描

@SpringBootApplication
@ComponentScan({"com.itheima","com.example"}) //指定要扫描的包
public class SpringbootWebConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebConfigApplication.class, args);
    }
}
注意,如果用了CompoentSacan,那么默认的扫描就不生效了.因此还需要额外把默认扫描的包引入. 缺点: 1. 使用繁琐 2. 性能低 SpringBoot中对于那些自动引入的包,并没有采用以上这种方案。

@import导入

该注解一般放于配置类上面

1). 使用@Import导入普通类

@Import(TokenParser.class) //导入的类会被Spring加载到IOC容器中
@SpringBootApplication
public class SpringbootWebConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebConfigApplication.class, args);
    }
}

2). 使用@Import导入配置类:

导入配置类之后,配置类当中所有的bean都会被导入.

配置类
@Configuration
public class HeaderConfig {
    @Bean
    public HeaderParser headerParser(){
        return new HeaderParser();
    }

    @Bean
    public HeaderGenerator headerGenerator(){
        return new HeaderGenerator();
    }
}
启动类
@Import(HeaderConfig.class) //导入配置类
@SpringBootApplication
public class SpringbootWebConfig2Application {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebConfig2Application.class, args);
    }
}
测试类
@SpringBootTest
public class AutoConfigurationTests {
    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void testHeaderParser(){
        System.out.println(applicationContext.getBean(HeaderParser.class));
    }

    @Test
    public void testHeaderGenerator(){
        System.out.println(applicationContext.getBean(HeaderGenerator.class));
    }

    //省略其他代码...
}

3). 使用@Import导入ImportSelector接口实现类

ImportSelector接口实现类
public class MyImportSelector implements ImportSelector {
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //返回值字符串数组(数组中封装了全限定名称的类)
        return new String[]{"com.example.HeaderConfig"};
    }
}
这个方法最终需要返回一个字符串数组,数组里的每一个字符串就是要导入的配置类/bean类的全限定名. 这样可以批量地导入其他类. 由于这是在函数中的逻辑,因此可以动态地添加类.
启动类
@Import(MyImportSelector.class) //导入ImportSelector接口实现类.注意,必须要import
@SpringBootApplication
public class SpringbootWebConfig2Application {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebConfig2Application.class, args);
    }
}
如果基于以上方式完成自动配置,当要引入一个第三方依赖时,还要知道第三方依赖中有哪些配置类和哪些Bean对象. 这对程序员不友好.最好就是让第三方自己指定bean对象. 所以一般是是第三方依赖给我们提供一个注解,这个注解一般都以@EnableXxxx开头的注解,注解中封装的就是@Import注解 如,这是一个Enable注解的源码 Pasted image 20250719212452 然后这样导入即可. Pasted image 20250719212541

自定义注解

在 Java 中,注解(Annotation)本质上是一种特殊的接口,它继承自 java.lang.annotation.Annotation 接口。当你定义注解时,其中的 “函数” 实际上是注解的属性(Attributes),这些属性在使用注解时需要被赋值(除非有默认值)。 注解实际上只是被注解的那些类/函数等的一个"元数据",用来被编译器\其他类等识别处理的,本质上没有什么作用. Pasted image 20250707231946

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)//指定要导入哪些bean对象或配置类
public @interface EnableHeaderConfig { 
}

使用时只需要在启动类上加注解

@EnableHeaderConfig  //使用第三方依赖提供的Enable开头的注解
@SpringBootApplication
public class SpringbootWebConfig2Application {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebConfig2Application.class, args);
    }
}

自定义注解

Retention Target都是元注解. Pasted image 20250707225421 我们也可以看到,注解写法其实就是@interface 例子:

import java.lang.annotation.*;

// 元注解:指定注解的生命周期(运行时保留)
@Retention(RetentionPolicy.RUNTIME)
// 元注解:指定注解可以应用的目标(类、方法、字段等)
@Target({ElementType.TYPE, ElementType.METHOD})
// 定义注解
public @interface MyAnnotation {
    // 定义注解属性(参数)
    String value() default "";          // 默认可省略的属性
    int count() default 1;              // 带默认值的属性
    String[] names() default {};        // 数组类型属性
    Class<?> type() default Void.class; // 类类型属性
}
使用:
// 应用于类
@MyAnnotation(value = "测试类", count = 3, names = {"A", "B"})
public class MyClass {
    // 应用于方法
    @MyAnnotation("测试方法")
    public void myMethod() {
        // ...
    }
}
在RUNTIME的情况下,可以通过反射获取注解信息:
public class AnnotationProcessor {
    public static void process(Object obj) {
        // 获取类上的注解
        Class<?> clazz = obj.getClass();
        if (clazz.isAnnotationPresent(MyAnnotation.class)) {
            MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class);
            System.out.println("类注解值: " + annotation.value());
            System.out.println("类注解count: " + annotation.count());
        }

        // 获取方法上的注解
        for (Method method : clazz.getDeclaredMethods()) {
            if (method.isAnnotationPresent(MyAnnotation.class)) {
                MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
                System.out.println("方法 " + method.getName() + " 的注解值: " + annotation.value());
            }
        }
    }

    public static void main(String[] args) {
        MyClass obj = new MyClass();
        process(obj);
    }
}

源码跟踪注解

每个main上面都有一个SpringBootApplication注解,内容如下: Pasted image 20250707231455

SpringBootConfiguration

Pasted image 20250707231523 使用了@Configuration,表明SpringBoot启动类就是一个配置类。 @Indexed注解,是用来加速应用启动的(不用关心)。

@ComponentScan

@ComponentScan注解是用来进行组件扫描的,扫描启动类所在的包及其子包下所有被@Component及其衍生注解声明的类。 SpringBoot启动类,之所以具备扫描包功能,就是因为包含了@ComponentScan注解。

@EnableAutoConfiguration

Pasted image 20250707231621 使用@Import注解,导入了实现ImportSelector接口的实现类。 AutoConfigurationImportSelector类是ImportSelector接口的实现类。 Pasted image 20250707231656 AutoConfigurationImportSelector类中重写了ImportSelector接口的selectImports()方法 Pasted image 20250707231739 selectImports()方法底层调用getAutoConfigurationEntry()方法,获取可自动配置的配置类信息集合 Pasted image 20250707233108 我们重点关注这个函数的返回值.(这里省略展示源码),AutoConfigurationEntry的构造函数传入两个参数:configurations和exclusions.其中exclusions表示排除哪些bean,configureration表示需要加入哪些bean.因此,这里面我们重点关注configurations怎么来的.我们可以看到,它是从getCandidateConfigurations的返回值得到的. getAutoConfigurationEntry()方法通过调用getCandidateConfigurations(annotationMetadata, attributes)方法获取在配置文件中配置的所有自动配置类的集合. Pasted image 20250707233124 我们也不用再跟踪load了,直接看断言里的信息: getCandidateConfigurations方法的功能: 获取所有基于 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中配置类的集合 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件这两个文件在哪里呢?(为什么说是两份?Spring2.7之前:spring.factories,2,7以后引入了autoConfiguration.imports,3.0之后:spring.factories被废除.)

note:jar文件表示的其实就是一个包的二进制程序. Pasted image 20250707233219 我们直接在测试类当中注入了一个叫gson的bean对象,进行JSON格式转换。虽然我们没有配置bean对象,但是我们是可以直接注入使用的。原因就是因为在自动配置类当中做了自动配置。到底是在哪个自动配置类当中做的自动配置呢? META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 配置文件中指定了第三方依赖Gson的配置类:GsonAutoConfiguration Pasted image 20250707233316 这些都是String,很正常,因为ImportSelector当中返回的就是String.

在GsonAutoConfiguration类上,添加了注解@AutoConfiguration,通过查看源码,可以明确:GsonAutoConfiguration 类是一个配置。 Pasted image 20250707233408 原理就是在配置类中定义一个@Bean标识的方法,而Spring会自动调用配置类中使用@Bean标识的方法,并把方法的返回值注册到IOC容器中。

在 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中定义的配置类非常多,而且每个配置类中又可以定义很多的bean,那这些bean都会注册到Spring的IOC容器中吗? 答案:并不是。 在声明bean对象时,上面有加一个以 @Conditional 开头的注解,这种注解的作用就是按照条件进行装配,只有满足条件之后,才会将bean注册到Spring的IOC容器中(下面会详细来讲解)

Conditional

  • 作用:按照一定的条件进行判断,在满足给定条件后才会注册对应的bean对象到Spring的IOC容器中。
  • 位置:方法、类 Pasted image 20250719220432
  • @Conditional本身是一个父注解,派生出大量的子注解:
  • @ConditionalOnClass:判断环境中有对应字节码文件,才注册bean到IOC容器。
  • @ConditionalOnMissingBean:判断环境中没有对应的bean(类型或名称),才注册bean到IOC容器。
  • @ConditionalOnProperty:判断配置文件中有对应属性和值,才注册bean到IOC容器。

ConditionalOnClass

@Configuration
public class HeaderConfig {

    @Bean
    @ConditionalOnClass(name="io.jsonwebtoken.Jwts")//环境中存在指定的这个类,才会将该bean加入IOC容器
    public HeaderParser headerParser(){
        return new HeaderParser();
    }

    //省略其他代码...
}

pom.xml
<!--JWT令牌-->
<dependency>
     <groupId>io.jsonwebtoken</groupId>
     <artifactId>jjwt</artifactId>
     <version>0.9.1</version>
</dependency>
因为 io.jsonwebtoken.Jwts 字节码文件在启动SpringBoot程序时已存在,所以创建HeaderParser对象并注册到IOC容器中。

@ConditionalOnMissingBean注解

@Configuration
public class HeaderConfig {

    @Bean
    @ConditionalOnMissingBean //不存在该类型的bean,才会将该bean加入IOC容器
    public HeaderParser headerParser(){
        return new HeaderParser();
    }

    //省略其他代码...
}
SpringBoot在调用@Bean标识的headerParser()前,IOC容器中是没有HeaderParser类型的bean,所以HeaderParser对象正常创建,并注册到IOC容器中。

@ConditionalOnProperty

这个注解和配置文件当中配置的属性有关系. Pasted image 20250707234219配置文件中存在指定属性名与值,才会将bean加入IOC容器.

自定义start

所谓starter指的就是SpringBoot当中的起步依赖。在SpringBoot当中已经给我们提供了很多的起步依赖了,我们为什么还需要自定义 starter 起步依赖? 这是因为在实际的项目开发当中,我们可能会用到很多第三方的技术,并不是所有的第三方的技术官方都给我们提供了与SpringBoot整合的starter起步依赖,但是这些技术又非常的通用,在很多项目组当中都在使用。 - 我们前面案例当中所使用的阿里云OSS对象存储服务,现在阿里云的官方是没有给我们提供对应的起步依赖的,这个时候使用起来就会比较繁琐,我们需要引入对应的依赖。我们还需要在配置文件当中进行配置,还需要基于官方SDK示例来改造对应的工具类,我们在项目当中才可以进行使用。 - SpringBoot项目中,一般都会将这些公共组件封装为SpringBoot当中的starter,也就是我们所说的起步依赖。 Pasted image 20250707234709 Pasted image 20250707235109

样例

引入起步依赖引入之后,要想使用阿里云OSS,注入AliyunOSSOperator 直接使用即可。 Pasted image 20250719220825 Pasted image 20250719220801 Pasted image 20250707235243 首先我们先来创建两个Maven模块: 1). 创建 aliyun-oss-spring-boot-starter Pasted image 20250707235309 选择springboot的版本,不需要勾选任何的依赖。直接点击 create 创建项目 Pasted image 20250707235406

Pasted image 20250707235355 pom.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>3.2.8</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>17</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

</project>
2). 创建 aliyun-oss-spring-boot-autoconfigure 模块 Pasted image 20250707235539

选择Springboot的版本,不用勾选任何依赖。 Pasted image 20250707235557 pom.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>3.2.8</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>17</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

</project>
按照我们之前的分析,是需要在starter模块中来引入autoconfigure这个模块的。打开starter模块中的pom文件:
<?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>3.2.8</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>17</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>
Pasted image 20250707235701
AliyunOssOperator
package com.itheima.utils;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Component
public class AliyunOSSOperator {

    @Autowired
    private AliyunOSSProperties aliyunOSSProperties;

    /**
     * 文件上传
     */
    public String upload(byte[] content, String originalFilename) throws Exception {
        String endpoint = aliyunOSSProperties.getEndpoint();
        String bucketName = aliyunOSSProperties.getBucketName();

        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();

        // 填写Object完整路径,例如202406/1.png。Object完整路径中不能包含Bucket名称。
        //获取当前系统日期的字符串,格式为 yyyy/MM
        String dir = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM"));
        //根据原始文件名originalFilename, 生成一个新的不重复的文件名
        String newFileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
        String objectName = dir + "/" + newFileName;

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        //文件上传
        try {
            ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content));
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }

        return endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + objectName;
    }


    /**
     * 查询文件列表
     */
    public List<String> listFiles() throws Exception {
        String endpoint = aliyunOSSProperties.getEndpoint();
        String bucketName = aliyunOSSProperties.getBucketName();
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 指定前缀,例如exampledir/object。
        String keyPrefix = null;

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            // 列举文件。如果不设置keyPrefix,则列举存储空间下的所有文件。如果设置keyPrefix,则列举包含指定前缀的文件。
            ObjectListing objectListing = ossClient.listObjects(bucketName, keyPrefix);
            List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
            if(sums != null && !sums.isEmpty()){
                return sums.stream().map(OSSObjectSummary::getKey).collect(Collectors.toList());
            }
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return null;
    }

    /**
     * 删除指定对象
     */
    public void deleteFile(String objectName) throws Exception {
        String endpoint = aliyunOSSProperties.getEndpoint();
        String bucketName = aliyunOSSProperties.getBucketName();

        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            // 删除文件或目录。如果要删除目录,目录必须为空。
            ossClient.deleteObject(bucketName, objectName);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

}
另外,需要把依赖也放进来:
<?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>3.2.8</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>17</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--阿里云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>

    </dependencies>

</project>
Pasted image 20250707235858 Pasted image 20250707235922Pasted image 20250707235947 这里这个Enable注解,就是导入AliyunOSS properties的bean对象,从而使得下面的函数形参有匹配的bean对象. 其实上面这个图就已经把原理搞的很清楚了. 另外,注意这里的"三个文件" Pasted image 20250708000030 Pasted image 20250708000052 可见,springboot是会扫描引入的所有的module的imports文件的. 使用: Pasted image 20250708000112 Pasted image 20250708000128