@PropertySource、@ImportResource、@Bean

SpringBoot中**@PropertySource、@ImportResource、@Bean三个注解的用法,核心是用它们扩展/替代默认的application配置文件**(并非直接修改原配置,而是补充/自定义配置),这三个注解解决的是不同场景的配置需求,其中**@Bean是SpringBoot最推荐的核心方式**,另外两个主要做兼容/配置文件扩展。

先明确一个前提:SpringBoot默认只自动加载application.properties/yml核心配置文件,这三个注解的出现,是为了解决默认配置不够用、兼容老Spring配置、纯代码替代配置文件这三类场景,所有示例基于基础SpringBoot项目(仅引入web依赖即可)。

一、@PropertySource:加载自定义的.properties配置文件

核心作用

专门让Spring加载默认配置文件以外的自定义.properties文件 ,把文件里的key=value加载到Spring的环境变量中,后续可以通过@Value@ConfigurationProperties取值使用。

通俗理解

SpringBoot默认只认application.properties/yml,你想自己建个配置文件(比如my-config.properties)放业务配置,用这个注解告诉Spring:把这个文件也加载进来,里面的配置我要用到

关键注意

默认不支持.yml/yaml文件(如需支持yml,需自定义配置工厂类,实际开发中极少用,因此重点讲.properties);可指定编码避免中文乱码。

注解核心属性
  • value/locations:指定自定义配置文件的类路径路径(最常用);
  • encoding:指定文件编码(如UTF-8,解决中文乱码);
  • ignoreResourceNotFound:是否忽略文件不存在,默认false(文件不存在会报错)。

代码示例:@PropertySource

步骤1:创建自定义.properties配置文件

resources目录下新建my-config.properties,写入自定义配置:

properties 复制代码
# 自定义业务配置
my.user.name=张三
my.user.age=20
my.user.desc=这是自定义配置文件的内容
步骤2:用@PropertySource加载配置文件

创建配置类 (或直接加在主启动类上,推荐单独建配置类,更规范),通过@PropertySource加载上述文件:

java 复制代码
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

// 配置类标识(也可用@Component,效果一致)
@Component
// 加载自定义配置文件,指定UTF-8编码避免中文乱码
@PropertySource(value = "classpath:my-config.properties", encoding = "UTF-8")
public class MyPropertyConfig {
}
步骤3:读取加载的配置(两种常用方式)
方式1:@Value 单个取值(简单场景用)

创建Controller,注入并测试:

java 复制代码
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
    // 用@Value("${配置key}")取值,:后是默认值(配置不存在时使用)
    @Value("${my.user.name:默认名称}")
    private String userName;

    @Value("${my.user.age:18}")
    private Integer userAge;

    @Value("${my.user.desc:无描述}")
    private String userDesc;

    @GetMapping("/test/property")
    public String testProperty() {
        return "姓名:" + userName + ",年龄:" + userAge + ",描述:" + userDesc;
    }
}
方式2:@ConfigurationProperties 批量绑定(推荐,适合多配置项)

创建实体类,批量绑定前缀为my.user的配置(需加@Component让Spring管理):

java 复制代码
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

// 让Spring管理该类
@Component
// 绑定配置的前缀(配置key的公共部分)
@ConfigurationProperties(prefix = "my.user")
public class UserProperties {
    // 字段名与配置key的后缀一致(name对应my.user.name)
    private String name;
    private Integer age;
    private String desc;

    // 生成get/set方法(必须,否则无法绑定)
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
    public String getDesc() { return desc; }
    public void setDesc(String desc) { this.desc = desc; }

    // 重写toString,方便测试
    @Override
    public String toString() {
        return "UserProperties{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", desc='" + desc + '\'' +
                '}';
    }
}

在Controller中注入实体类测试:

java 复制代码
@RestController
public class TestController {
    // 注入批量绑定的配置实体
    @Autowired
    private UserProperties userProperties;

    @GetMapping("/test/property/batch")
    public String testPropertyBatch() {
        return userProperties.toString();
    }
}
测试结果

启动项目,访问http://localhost:8080/test/propertyhttp://localhost:8080/test/property/batch,能正常获取到自定义配置文件的内容,说明加载成功。


二、@ImportResource:导入传统Spring的xml配置文件

核心作用

让SpringBoot兼容老的Spring xml配置 ,把xml文件中通过<bean>标签定义的Bean,导入到SpringBoot的IOC容器中,让这些Bean被Spring管理并注入使用。

通俗理解

以前写SSM时,会用applicationContext.xml配置<bean id="" class="">创建Bean,现在SpringBoot推荐无xml开发 ,但如果有现成的xml配置不想重写,用这个注解告诉Spring:把这个xml文件导入进来,里面的Bean我还要用

关键注意

SpringBoot官方强烈不推荐使用该注解 ,它仅做老项目兼容 ,新项目优先用@Bean替代xml配置。

注解核心属性

  • locations/value:指定xml配置文件的类路径路径(最常用);
  • name:配置集的名称,几乎不用。

代码示例:@ImportResource

步骤1:创建传统Spring xml配置文件

resources目录下新建spring-beans.xml,里面用<bean>定义一个普通Bean(比如业务类HelloService):

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 传统xml方式定义Bean:id是Bean名称,class是全类名 -->
    <bean id="helloService" class="com.example.demo.service.HelloService"></bean>
</beans>
步骤2:创建xml中定义的Bean类

新建com.example.demo.service.HelloService

java 复制代码
package com.example.demo.service;

// 普通类,无任何注解(因为Bean由xml定义)
public class HelloService {
    public String sayHello() {
        return "Hello! 我是xml配置的Bean";
    }
}
步骤3:用@ImportResource导入xml文件

必须加在SpringBoot的主启动类上(唯一有效位置),指定xml文件路径:

java 复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;

// 导入xml配置文件,让里面的Bean被Spring管理
@ImportResource(locations = "classpath:spring-beans.xml")
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
步骤4:注入并测试xml定义的Bean

在Controller中注入helloService(通过xml的id),测试是否能使用:

java 复制代码
@RestController
public class TestController {
    // 注入xml中定义的Bean
    @Autowired
    private HelloService helloService;

    @GetMapping("/test/xml")
    public String testXmlBean() {
        return helloService.sayHello();
    }
}
测试结果

访问http://localhost:8080/test/xml,返回Hello! 我是xml配置的Bean,说明xml中的Bean被成功加载到Spring容器中。


三、@Bean:纯代码方式创建Spring Bean(SpringBoot主推)

核心作用

替代xml中的<bean>标签 ,在配置类 中写方法,方法返回一个对象,给方法加@Bean注解,Spring就会把这个返回对象作为Bean放入IOC容器 ,后续可通过@Autowired/@Resource注入使用。

通俗理解

不用配置文件、不用xml,直接用代码"造对象",并告诉Spring:这个对象你帮我管理,别人要用直接拿 ,相当于代码版的<bean id="" class="">

核心搭配

@Bean必须配合@Configuration注解使用@Configuration标识的类是SpringBoot的配置类 ,专门用来写@Bean方法,替代传统的xml配置文件,一个项目可以有多个配置类。

注解核心属性

  • name/value:自定义Bean的名称(id),数组类型,可指定多个别名;
  • initMethod:Bean的初始化方法(相当于xml的init-method);
  • destroyMethod:Bean的销毁方法(相当于xml的destroy-method);
  • primary:设置为主Bean,解决同类型多个Bean的注入优先级问题。

关键默认规则

如果不指定name/value,Bean的默认名称是**@Bean标注的方法名**。

代码示例:@Bean(分2个场景,覆盖90%实际开发)

场景1:基础使用------纯代码创建Bean(替代xml)
步骤1:创建要被管理的Bean类(普通类,无注解)

还是用之前的HelloService,无需任何注解:

java 复制代码
package com.example.demo.service;

public class HelloService {
    public String sayHello() {
        return "Hello! 我是@Bean配置的Bean";
    }
}
步骤2:创建配置类,用@Bean创建Bean

新建配置类(推荐放在config包下),加@Configuration,写@Bean方法:

java 复制代码
import com.example.demo.service.HelloService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

// 配置类标识:替代传统xml配置文件
@Configuration
public class MyBeanConfig {

    // 方式1:默认Bean名称(方法名helloService)
    @Bean
    public HelloService helloService() {
        return new HelloService(); // 方法返回Bean对象,Spring自动管理
    }

    // 方式2:自定义Bean名称(name/value指定,可多个别名)
    /*
    @Bean(name = {"myHelloService", "helloService2"})
    public HelloService helloService() {
        return new HelloService();
    }
    */
}
步骤3:注入并测试

在Controller中注入,直接使用(默认用方法名注入,自定义名称则用名称注入):

java 复制代码
@RestController
public class TestController {
    // 注入@Bean创建的Bean(默认方法名helloService)
    @Autowired
    private HelloService helloService;

    @GetMapping("/test/bean")
    public String testBean() {
        return helloService.sayHello();
    }
}
场景2:高级使用------结合自定义配置动态创建Bean(实际开发常用)

@PropertySource加载的自定义配置,动态设置到@Bean创建的Bean中,实现配置驱动Bean,这是实际开发中最常用的组合方式。

步骤1:修改自定义配置文件my-config.properties

增加Bean的配置项:

properties 复制代码
# 自定义Bean的配置
my.service.name=业务服务Bean
my.service.version=v1.0
步骤2:创建带属性的Bean类

新建com.example.demo.service.MyService,包含属性和set/get方法:

java 复制代码
package com.example.demo.service;

public class MyService {
    private String name; // 服务名称
    private String version; // 服务版本

    // 业务方法
    public String getServiceInfo() {
        return "服务名称:" + name + ",版本:" + version;
    }

    // 必须生成set/get方法(用于动态赋值)
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getVersion() { return version; }
    public void setVersion(String version) { this.version = version; }
}
步骤3:配置类中组合@PropertySource+@Bean

在配置类中加载自定义配置,并用@Value取值,动态设置到Bean中:

java 复制代码
import com.example.demo.service.HelloService;
import com.example.demo.service.MyService;
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;

// 1. 加载自定义配置文件
@PropertySource(value = "classpath:my-config.properties", encoding = "UTF-8")
// 2. 标识为配置类
@Configuration
public class MyBeanConfig {

    // 3. 从自定义配置中取值
    @Value("${my.service.name}")
    private String serviceName;
    @Value("${my.service.version}")
    private String serviceVersion;

    // 4. 动态创建Bean,设置配置属性
    @Bean
    public MyService myService() {
        MyService myService = new MyService();
        myService.setName(serviceName); // 给Bean设置配置值
        myService.setVersion(serviceVersion);
        return myService;
    }
}
步骤4:注入并测试动态Bean
java 复制代码
@RestController
public class TestController {
    // 注入动态配置的MyService
    @Autowired
    private MyService myService;

    @GetMapping("/test/bean/dynamic")
    public String testDynamicBean() {
        return myService.getServiceInfo();
    }
}
测试结果
  • 访问http://localhost:8080/test/bean,返回Hello! 我是@Bean配置的Bean
  • 访问http://localhost:8080/test/bean/dynamic,返回服务名称:业务服务Bean,版本:v1.0
    说明Bean被动态配置并成功加载。

四、三个注解的核心对比(通俗总结)

为了让你快速区分,用表格清晰说明作用、使用场景、推荐程度,这是实际开发的核心参考:

注解 核心作用 通俗理解 主要使用场景 SpringBoot推荐程度
@PropertySource 加载自定义.properties配置文件到Spring环境 给Spring加"额外的配置文件" 配置项太多,想分文件管理(解耦) ⭐⭐⭐⭐(常用)
@ImportResource 导入传统Spring xml配置文件,加载xml中的Bean 兼容老项目的xml配置 老SSM项目迁移到SpringBoot,不想重写xml ⭐(仅兼容用)
@Bean 纯代码创建Spring Bean,放入IOC容器 代码版的<bean>标签,造对象给Spring管理 新项目自定义Bean、动态配置Bean、替代xml ⭐⭐⭐⭐⭐(核心主推)

五、关键补充知识点

  1. @Configuration的小细节 :SpringBoot中配置类加@Configuration后,默认是单例模式 ------无论调用多少次@Bean方法,Spring只会创建一个Bean对象,保证容器中Bean的单例性;

  2. @Bean的注入优先级 :如果同一种类型有多个@Bean,注入时会报NoUniqueBeanDefinitionException,解决方式:

    • @Resource(name = "Bean名称")指定名称注入;
    • 给其中一个@Bean@Primary,设置为主Bean,Spring会优先注入;
  3. @PropertySource支持yml的坑 :默认不支持yml,如需支持,需自定义PropertySourceFactory,代码如下(了解即可,实际开发推荐用.properties):

    java 复制代码
    import org.springframework.boot.env.YamlPropertySourceLoader;
    import org.springframework.core.env.PropertySource;
    import org.springframework.core.io.support.EncodedResource;
    import org.springframework.core.io.support.PropertySourceFactory;
    import java.io.IOException;
    import java.util.List;
    
    public class YamlPropertySourceFactory implements PropertySourceFactory {
        @Override
        public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
            List<PropertySource<?>> sources = new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource());
            return sources.get(0);
        }
    }

    使用时在@PropertySource中指定工厂:

    java 复制代码
    @PropertySource(value = "classpath:my-config.yml", factory = YamlPropertySourceFactory.class, encoding = "UTF-8")
  4. 配置类的扫描 :SpringBoot会自动扫描主启动类所在包及其子包下的@Configuration配置类,无需额外配置,如需扫描外部包,用@ComponentScan指定包路径。


六、总结

  1. @PropertySource是"加载配置文件" ,仅负责把自定义.properties的k-v加载到Spring环境,本身不创建Bean,需配合@Value/@ConfigurationProperties取值;
  2. @ImportResource是"兼容老xml",仅用于老项目迁移,新项目坚决不用,是过渡方案;
  3. @Bean是SpringBoot配置的"核心" ,替代xml和手动new对象,可结合@PropertySource实现配置驱动Bean ,是实际开发中自定义Bean的唯一推荐方式
  4. 三个注解的核心目的都是扩展SpringBoot的默认配置 ,而非修改原application.properties/yml,默认配置文件依然是SpringBoot的核心,负责框架自身的配置(如端口、数据库、日志等)。
相关推荐
ManThink Technology1 分钟前
如何使用EBHelper 简化EdgeBus的代码编写?
java·前端·网络
invicinble5 分钟前
springboot的核心实现机制原理
java·spring boot·后端
人道领域13 分钟前
SSM框架从入门到入土(AOP面向切面编程)
java·开发语言
大模型玩家七七33 分钟前
梯度累积真的省显存吗?它换走的是什么成本
java·javascript·数据库·人工智能·深度学习
space621232739 分钟前
在SpringBoot项目中集成MongoDB
spring boot·后端·mongodb
CodeToGym1 小时前
【Java 办公自动化】Apache POI 入门:手把手教你实现 Excel 导入与导出
java·apache·excel
凡人叶枫1 小时前
C++中智能指针详解(Linux实战版)| 彻底解决内存泄漏,新手也能吃透
java·linux·c语言·开发语言·c++·嵌入式开发
JMchen1231 小时前
Android后台服务与网络保活:WorkManager的实战应用
android·java·网络·kotlin·php·android-studio
阔皮大师2 小时前
INote轻量文本编辑器
java·javascript·python·c#
小法师爱分享2 小时前
StickyNotes,简单便签超实用
java·python