Spring能否基于Bean字段值注入属性?实例化ServiceConfig时自动注入配置
直接通过new ServiceConfig("service1")让Spring自动注入对应配置属性是不可行的,原因很简单:你手动new出来的对象不在Spring容器的管控范围内,Spring没有办法主动识别并为这个对象填充配置属性。不过我们可以通过几种Spring友好的方式实现你想要的效果,下面给你具体方案:
方案1:通过@ConfigurationProperties批量创建容器管理的ServiceConfig实例
这种方式适合你提前知道所有service配置(比如service1到service4)的场景,把每个service的配置都创建成Spring Bean,后续直接注入使用即可。
步骤1:完善ServiceConfig类
首先给你的ServiceConfig添加属性的getter和setter方法(Spring的配置绑定需要这些方法来设置属性):
public class ServiceConfig { private String url; private String endpoint; private String serviceName; public ServiceConfig(String serviceName) { this.serviceName = serviceName; } // 添加getter和setter public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getEndpoint() { return endpoint; } public void setEndpoint(String endpoint) { this.endpoint = endpoint; } public String getServiceName() { return serviceName; } }
步骤2:创建配置类生成Bean
编写一个配置类,通过@ConfigurationProperties指定每个service的配置前缀,生成对应的ServiceConfig Bean:
@Configuration public class ServiceConfigRegistry { @Bean("service1Config") @ConfigurationProperties(prefix = "service1") public ServiceConfig service1Config() { return new ServiceConfig("service1"); } @Bean("service2Config") @ConfigurationProperties(prefix = "service2") public ServiceConfig service2Config() { return new ServiceConfig("service2"); } @Bean("service3Config") @ConfigurationProperties(prefix = "service3") public ServiceConfig service3Config() { return new ServiceConfig("service3"); } @Bean("service4Config") @ConfigurationProperties(prefix = "service4") public ServiceConfig service4Config() { return new ServiceConfig("service4"); } }
使用方式
之后在需要使用的地方,通过@Autowired配合@Qualifier注入对应的实例:
@Autowired @Qualifier("service1Config") private ServiceConfig service1Config;
方案2:通过工厂类动态创建配置实例
如果需要根据传入的serviceName动态生成对应的ServiceConfig(比如运行时才确定要使用哪个service),可以创建一个Spring管理的工厂类来实现:
步骤1:完善ServiceConfig类
同样需要先添加getter和setter方法(和方案1的ServiceConfig一致)。
步骤2:编写ServiceConfig工厂类
@Component public class ServiceConfigFactory { private final Environment environment; // 构造注入Environment,用于读取配置文件中的属性 public ServiceConfigFactory(Environment environment) { this.environment = environment; } public ServiceConfig create(String serviceName) { // 根据serviceName拼接配置键,读取对应属性 String url = environment.getProperty(serviceName + ".url"); String endpoint = environment.getProperty(serviceName + ".endpoint"); ServiceConfig config = new ServiceConfig(serviceName); config.setUrl(url); config.setEndpoint(endpoint); return config; } }
使用方式
在需要的地方注入工厂类,调用create方法获取实例:
@Autowired private ServiceConfigFactory configFactory; // 生成service1的配置实例 ServiceConfig sc = configFactory.create("service1");
关键说明
为什么直接new不行?因为Spring的依赖注入、配置绑定等能力只针对容器内的Bean生效。手动new的对象脱离了Spring的管理生命周期,Spring不会主动去处理它的属性填充。上面两种方案都是通过Spring容器的能力来帮我们完成配置属性的绑定,最终达到你想要的效果。
内容的提问来源于stack exchange,提问作者user2647271

