You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring中通过静态工厂方法同时注入依赖与动态属性?

解决Spring依赖注入与动态属性设置共存的问题

这个问题我之前也碰到过,核心问题在于你写的静态工厂方法of是直接通过私有无参构造器创建了Service实例——这个实例完全脱离了Spring容器的管理,Spring根本没机会帮你注入repository依赖,自然会出现未实例化的问题。

下面给你几种可行的解决方案,既能保留Spring的依赖注入,又能实现动态属性的设置:

方案一:利用Spring原型Bean + ApplicationContext持有者

这种方式适合你希望通过静态方法直接创建实例的场景,核心思路是让Service成为原型作用域的Bean(每次获取都是新实例),然后通过ApplicationContext从容器中获取已经注入好依赖的实例,再设置动态属性。

步骤1:创建ApplicationContext持有者

首先定义一个工具类,用于持有Spring的ApplicationContext:

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class ApplicationContextHolder implements ApplicationContextAware {
    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    public static ApplicationContext getContext() {
        return context;
    }
}

步骤2:修改Service类

将Service标记为原型Bean,并调整静态工厂方法:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype") // 标记为原型作用域,每次获取都是新实例
class Service {
    private final Repository repository;
    private String field;

    // Spring注入Repository的构造器
    @Autowired
    public Service(Repository repository) {
        this.repository = repository;
    }

    public static Service of(String field) {
        // 从容器获取已注入依赖的Service实例
        Service service = ApplicationContextHolder.getContext().getBean(Service.class);
        service.setField(field);
        return service;
    }

    // 设置动态属性的方法(可以是私有或公开,根据需求调整)
    public void setField(String field) {
        this.field = field;
    }

    // 你的业务方法
}

使用时直接调用Service.of("动态属性值")即可,返回的实例既包含Spring注入的repository,又设置了动态的field属性。

方案二:使用建造者模式(更优雅的方式)

这种方式避免了直接操作ApplicationContext,符合Spring的依赖注入设计理念,适合需要灵活构建实例的场景。

步骤1:创建ServiceBuilder

让Builder由Spring管理,注入所需的Repository依赖,同时提供设置动态属性的方法:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
class ServiceBuilder {
    private final Repository repository;
    private String field;

    @Autowired
    public ServiceBuilder(Repository repository) {
        this.repository = repository;
    }

    // 设置动态属性的链式方法
    public ServiceBuilder withField(String field) {
        this.field = field;
        return this;
    }

    // 构建Service实例
    public Service build() {
        return new Service(repository, field);
    }
}

步骤2:调整Service类

添加一个接收Repository和动态属性的构造器:

class Service {
    private final Repository repository;
    private final String field;

    // 用于Spring直接注入的构造器(如果需要Spring管理默认实例的话)
    @Autowired
    public Service(Repository repository) {
        this.repository = repository;
        this.field = null; // 可设置默认值
    }

    // 用于Builder的构造器
    public Service(Repository repository, String field) {
        this.repository = repository;
        this.field = field;
    }

    // 你的业务方法
}

使用方式

在Spring管理的类中注入ServiceBuilder,然后链式构建实例:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
class SomeBusinessClass {
    @Autowired
    private ServiceBuilder serviceBuilder;

    public void doSomething() {
        // 构建带动态属性的Service实例
        Service service = serviceBuilder.withField("动态属性值").build();
        // 调用业务方法
        service.someBusinessMethod();
    }
}

方案三:使用@Lookup方法(适合单例Bean中获取原型实例)

如果你的Service需要被其他单例Bean依赖,但又需要每次获取新的实例并设置动态属性,可以使用Spring的@Lookup注解:

修改Service类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
class Service {
    private final Repository repository;
    private String field;

    @Autowired
    public Service(Repository repository) {
        this.repository = repository;
    }

    public void setField(String field) {
        this.field = field;
    }

    // 业务方法
}

在依赖Service的类中使用@Lookup

import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.stereotype.Component;

@Component
class SomeSingletonBean {
    // @Lookup注解会自动从容器获取原型实例
    @Lookup
    protected Service createService() {
        return null; // 仅作为方法签名,Spring会动态生成实现
    }

    public void doBusiness() {
        Service service = createService();
        service.setField("动态属性值");
        service.someBusinessMethod();
    }
}

内容的提问来源于stack exchange,提问作者DWB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:05:20