【问题标题】:Construct a bean dynamically by passing in a "profile" at runtime通过在运行时传入“配置文件”来动态构造 bean
【发布时间】:2018-09-28 20:18:31
【问题描述】:

假设我有以下设置

应用程序-toyota.properties

model=prius
type=hybrid

应用程序-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对象?

【问题讨论】:

  • 这个问题的形成方式......这看起来不是一个好主意......其次......你有一个工厂只排放一种类型的汽车。
  • @shinjw 没有。工厂根据轮廓制造汽车。因此,如果您要传递“Acura”配置文件,它应该从 application-acura.properties 中获取属性,使用该属性文件中的值创建一个 bean,然后返回它。

标签: java spring dependency-injection spring-profiles


【解决方案1】:

我认为你应该进一步澄清这个问题。我来解释一下

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

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

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

现在,如果配置文件,比如“toyota”是活动的,汽车对象的值已经定义好,所以你甚至不需要汽车工厂 - spring 将读取相关的属性文件(application-toyota.properties在这种情况下),解析属性的值并将正确的值注入到同样由 spring 驱动的 car bean。 当然,“chev”配置文件也是如此。

【讨论】:

    【解决方案2】:

    我想我理解你想要做什么,但你混淆了术语。如果您的目标是创建一个支持单一类型汽车的应用程序,那么 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,只是因为我们有多个工厂配置,我们会在地图中处理它们。

    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 的设计理念,而不是相对僵化并且需要机器上存在配置文件以及文件源的一些未知输入。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-29
      • 1970-01-01
      相关资源
      最近更新 更多