简体   繁体   English

在非弹簧注入类中使用 application.properties

[英]Use application.properties in a non-spring injected class

I have a class which is created with new B(this);我有一个用new B(this); in this class BI want to use a value from the application.properties.在此类 BI 中,想要使用 application.properties 中的值。 But because (as far as I understand) because it's not created with Spring it won't have any injection (I use the @Value annotation)但是因为(据我所知)因为它不是用 Spring 创建的,所以不会有任何注入(我使用@Value注释)

That is how the class is created:这就是类的创建方式:

@Component
public class A {

    public B getB(){return new B(this);}

    /**
        a lot more stuff
    **/
}

The class in question:有问题的班级:

public class B {

    private A a;

    public B(A a){
        this.a = a;
    }

    @Value("${threshold}")
    private String threshold;  //this is null because it's not created with Spring

    public String getThreshold(){
        return threshold;
    }
    /**
        a lot more stuff
    **/

}

So my question is the following:所以我的问题如下:

1) How can I use the value in the application.properties file or 1)如何使用 application.properties 文件中的值或

2) How can I write B that it is created with Spring? 2)我如何写B,它是用Spring创建的?

Some background information:一些背景资料:

  • I didn't wrote the initial code so I don't want to change too much but want to modify it so it can be maintained better in the future最初的代码不是我写的,所以我不想改动太多,但想修改它,以便将来可以更好地维护
  • I don't have that much Spring knowledge and only start getting more and more familiar with it.我没有那么多的 Spring 知识,只是开始越来越熟悉它。
  • In point 2) I'm struggling because of the constructorand how to set it via Spring...在第 2 点)我因为构造函数而苦苦挣扎,以及如何通过 Spring 设置它......

Any help would be appreciated任何帮助,将不胜感激

Here's an example of using @ConfigurationProperties to bind your application.properties to a POJO.这是一个使用@ConfigurationPropertiesapplication.properties绑定到 POJO 的示例。

Say you have a application.properties file like this,假设你有一个这样的application.properties文件,

mail.hostname=mailer@mail.com
mail.port=9000

You can create a POJO like this for the above scenario.您可以为上述场景创建这样的 POJO。

( Note: If your spring boot version is lower than 2.2 you might want to annotate this class with @Configuration and @Component as well) 注意:如果您的 Spring Boot 版本低于 2.2,您可能还需要使用@Configuration@Component注释此类)

@ConfigurationProperties(prefix = "mail")
public class ConfigProperties {

    private String hostname;
    private String port;

    // Create Getters and Setters

}

When the spring boot application initializes, it will automatically map values from application.properties into this POJO.当 spring boot 应用程序初始化时,它会自动将application.properties中的值映射到这个 POJO 中。 If you want to use this, all you have to do is create a variable and mark it with @Autowire如果你想使用它,你所要做的就是创建一个变量并用@Autowire标记它

@Component
public class TestClass {

    @Autowire
    private ConfigProperties properties;

    public void printSomething() {
       System.println(properties.getHostname());
       System.println(properties.getPort());
    }

}

Following up on your question...跟进你的问题...

Since the class in your example is not managed by spring, and you have to keep it this way for some reason, you can use the following helper class to manually autowire a spring bean in a non spring managed class.由于您的示例中的类不是由 spring 管理的,并且由于某种原因您必须保持这种方式,因此您可以使用以下帮助程序类在非 spring 托管类中手动自动装配 spring bean。

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

@Service
public class BeanUtil implements ApplicationContextAware {

    private static ApplicationContext context;

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

    /**
     *Use this method to manually autowire Spring Beans into classes that are not managed by Spring.
     *
     *@param beanClass - Class type of the required bean.
     **/
    public static <T> T getBean(Class<T> beanClass) {
        return context.getBean(beanClass);
    }

}

To use this in your class B do the following.要在class B中使用它,请执行以下操作。

public class B {

    private ConfigProperties properties;

    public B() {
        BeanUtil.getBean(ConfigProperties.class); // This will initialize properties variable properly.
    }

    public void printSomething() {
       System.println(properties.getHostname());
       System.println(properties.getPort());
    }

}

You can write as below:你可以写如下:

@Component
public class A {

    @Value("${threshold}")
    private String threshold;

    public B getB(){
        return new B(this);
    }

    public String getThreshold() {
        return threshold;
    }

}

public class B {

    private A a;
    private String threshold;

    public B(A a){
        this.a = a;
        this.threshold=a.getThreshold();
    }

    public String getThreshold(){
        return threshold;
    }

} }

You can create a class that will load the properties for you directly from a file.您可以创建一个类,该类将直接从文件中为您加载属性。 The file must be in the resources package.该文件必须在资源包中。

Config properties class where these properties are defined定义这些属性的配置属性类

@ConfigurationProperties(prefix = "reader")
public class ReaderProperties {
    private String threshold;
}

The property class属性类

import java.util.Properties;

class MyProperties {

    private final Properties props;

    private MyProperties(Class<?> propertiesClass) throws IOException {
        this.props = new Properties();
        this.props.load(propertiesClass.getResourceAsStream("/application.properties"));
    }
    
    public String getThreshold() {
        return props.getProperty("threshold");
    }

}

Then inside B:然后在 B 内:

public class B {

    private A a;
    private String threshold;

    public B(A a){
        this.a = a;
        MyProperties props = new MyProperties(ReaderProperties.class);
        this.threshold = props.getThreshold();
    }

    public String getThreshold(){
        return threshold;
    }
    /**
        a lot more stuff
    **/

}

The existing answers work if you're willing and able to annotate class B with @ConfigurationProperties but this might not be feasible if B is provided as part of non-Spring library, and or if B needs to be used in non-Spring projects.如果您愿意并且能够使用@ConfigurationProperties注释B类,则现有答案有效,但如果B作为非 Spring 库的一部分提供,或者如果B需要在非 Spring 项目中使用,这可能不可行。

Fortunately Spring does provide a more portable way to do this if B is a POJO/JavaBean:幸运的是,如果B是 POJO/JavaBean,Spring 确实提供了一种更可移植的方法:

Example class B :示例B类:

public class B {
    private String threshold;
    // Is a POJO/JavaBean i.e. has default constructor, getters, setters etc.
}

In application.properties :application.properties

my.config.prefix.threshold=42

Define a Spring bean in a @Configuration class for your Spring Boot project eg:@Configuration类中为您的 Spring Boot 项目定义一个 Spring bean,例如:

@Configuration
public class ApplicationConfig {
    @Bean
    @ConfigurationProperties("my.config.prefix")
    public B getB() {
        // Spring will later use setters to configure the fields per my.config.prefix
        return new B();
    }
}

You can now rely on Spring to autowire the dependency eg using field injection 1 :您现在可以依靠 Spring 来自动装配依赖关系,例如使用字段注入1

@Component
public class A {
    @Autowired
    private B b; // b.getThreshold() == 42
}

Unless a class is strictly for running or configuring a Spring Boot application, I would err to towards keeping the code more portable by defining a bean.除非一个类严格用于运行或配置 Spring Boot 应用程序,否则我会错误地通过定义 bean 来保持代码更具可移植性。


1 Field injection is generally not recommended but it's used here for concision. 1一般不推荐现场注入,但为了简洁,这里使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM