通过在运行时传入“配置文件”来动态构造Bean

时间:2018-09-28 20:18:32

标签: java spring dependency-injection spring-profiles

假设我具有以下设置

application-toyota.properties

model=prius
type=hybrid

application-chevy.properties

model=volt
type=electric

课程:

public class Car{

@Value("${model}")
private String model;
@Value("${type}")
private String type;

...setters & getters...
}

public class CarFactory{

private Car car;
public Car makeCar(String profile){

return car;
}

}

有没有一种方法可以使makeCar方法接受一个配置文件(例如“ toyota”),动态构造一个Car对象,同时在这种情况下填充相应属性文件(application-toyota.properties)中的值,并返回有效的Car对象?

2 个答案:

答案 0 :(得分:1)

我认为您应该进一步澄清这个问题。我会解释

在Spring配置文件中最开始就指定了(通常是通过spring驱动的应用程序的执行参数)。

在此示例中,同时激活两个配置文件没有意义,因为它们将“竞争”属性“ model”和“ type”的实际值。

据此,我得出结论,您仅激活一个配置文件。

现在,如果配置文件(例如“ toyota”处于活动状态),则car对象的值已定义好,因此您甚至不需要Car工厂-spring将读取相关的属性文件(application-toyota.properties (在这种情况下),请解析属性值,并将正确的值注入也由spring驱动的car bean。 当然,“ chev”配置文件也是如此。

答案 1 :(得分:1)

我想我理解您要做什么,但是您混淆了术语。如果您的目标是创建一个支持单一类型汽车的单一应用程序,那么Mark的答案就是您想要的。但是,如果您要寻找的是一家工厂,它会创建具有不同配置的多种类型的汽车,而您在编译/启动时不知道它们的含义,那么您需要采取不同的方法。

在此版本中,我们将在配置文件中定义多个“类型”的汽车,因此我们将拥有一个POJO汽车类别。

public class Car {

    private String model;
    private String type;

    public Car() {
    }

    public Car(String model, String type) {
        this.model = model;
        this.type = type;
    }
}

然后我们将拥有您的CarFactory,仅是因为我们对Factory有多种配置,所以我们将在地图中处理它们。

public class CarFactory {

    Map<String, ConfiguredCarFactory> factories = new HashMap<>();

    public Car makeCar(String profile) {
        return getFactory(profile).makeCar();
    }

    private ConfiguredCarFactory getFactory(String profile) {
        ConfiguredCarFactory carFactory = factories.get(profile);
        if(carFactory == null) {
            carFactory = new ConfiguredCarFactory(profile);
            factories.put(profile, carFactory);
        }
        return carFactory;
    }
}

在这种情况下,为简单起见,我使用的配置文件是属性文件的实际文件位置。尚未将其设置为Bean,但是如果您想创建一个Bean来处理地图下的地图功能,则可以很快完成。

然后,最后,我们将有一个配置好的CarFactory通过配置文件执行实际的汽车创建。

public class ConfiguredCarFactory {

    private final String profile;
    private String model;
    private String type;


    public ConfiguredCarFactory(String profile) {
        this.profile = profile;
        Properties prop = new Properties();
        File file = new File(profile);
        try(FileInputStream input = new FileInputStream(profile))  {
            prop.load(input);
            model = (String) prop.get("model");
            type = (String) prop.get("type");
        } catch (Exception e) {
            e.printStackTrace();
            model = "Generic";
            type = "Generic";
        }
    }

    public Car makeCar() {
        return new Car(model, type);
    }
}

虽然这肯定满足您的要求,但我有点犹豫地说这是您要寻找的。例如,提供未知数量的汽车配置作为属性比将所有汽车配置存储在数据库中并通过JPA实例化为实体不太理想。与相对僵化的,除了文件源的一些未知输入外,还要求机器上存在配置文件的东西相比,这更具“动态性”,并且将更紧密地遵循Spring的设计理念。