英文:
How to access a property in .properties file during or before the main() method in Spring?
问题
我们已经将现有的 Web 应用转换为 Spring Boot。
我想要做的就是能够使用 @Profile("production") 注解。我们将它存储在 resources 文件夹中的 myProps.properties 文件中。
我可以在整个应用程序中轻松使用 @Value 访问 .properties 文件,但是似乎为了使 @Profile 生效,你必须在 ServletContext 被设置/完成之前设置活动配置文件,而这似乎是在 main() 方法执行期间发生的。
我尝试了很多方法,但都失败了。我发现不能在主应用程序类中使用 @Value 设置静态字段。我尝试过创建一个实现了 WebApplicationInitializer 的类,就像 https://www.baeldung.com/spring-profiles 中的示例,但是我重写的 onStartup() 方法从未被执行过。我放了一个断点,但从未命中过。我唯一可以让断点命中的方式是在那个方法上使用 @Autowire 注入 servletContext,但那时上下文已经被设置,无法更改。
我尝试过 AnnotationConfigWebApplicationContext,尝试过 ServletContainerInitializer,尝试过 ConfigurableEnvironment 等。我感觉我陷入了一个死循环。
我觉得我在这里缺少一个重要环节,以便以 "Spring 的方式" 进行操作。是否有人可以提供一个基于 Java 注解配置的方法,让我能够获取属性并设置活动配置文件,以便以后在产品中使用?谢谢。
英文:
We have converted an existing web app over to Spring Boot.
All I want to to do is be able to use @Profile("production"). We store that in myProps.properties in the resources folder.
I can access the .properties file all over the app just fine using @Value, but it seems in order to get the @Profile to work, you have to set the active profiles before the ServletContext is set/final which seems to happen during the main() method.
I've tried dozens of things and failed. I've found you can't set a static field with @Value in the main application class. I've tried making a class that implements WebApplicationInitializer like https://www.baeldung.com/spring-profiles but my onStartup() method that I override doesn't ever get run.. I put in a break point and it never gets hit. The only way I can get a break point to hit is if I @Autowire the servletContext on that method, but then the context is already set and cannot be altered.
I've tried AnnotationConfigWebApplicationContext, I've tried ServletContainerInitializer, I've tried ConfigurableEnvironment, etc. I feel like I'm going in circles.
I feel like there is a big piece I'm missing here in order to do things the "Spring way". Can anyone offer Java annotation-configured way for me to get a property and set the active profiles for using later in the product? Thanks.
答案1
得分: 0
为什么需要在main函数之前使用它?为什么不只是创建多个属性文件,并在顶层属性文件中定义配置文件?
(父级)application.properties
spring.profiles.active = development-application.properties
(配置文件)development-application.properties
my.value = foo
英文:
Why do you need it before main? Why don't you just create multiple properties files and define the profile in the top-level property file?
(parent) application.properties
spring.profiles.active = development-application.properties
(profile) development-application.properties
my.value = foo
答案2
得分: 0
基于您的评论,我建议将以下内容作为解决方案:
将您的任务定义为带有 @Component
注释的 beans,并使用 @Profile
进行注释,以按照您想要在其中使用它们的环境进行划分(我建议将配置文件设置为环境变量)。
@Component
@Profile("production")
public class TaskA implements Task {
public void doWork(){}
}
@Component
@Profile("staging")
public class TaskB implements Task {
public void doWork(){}
}
使用 @Component
对这些类进行标记意味着 Spring 将管理它们,并且它们可以被注入,可能注入到执行任务的 @Component
中:
@Component
public class TaskDoer {
private List<Task> tasksToDo;
@Inject
public TaskDoer(List<Task> tasksToDo) {
this.tasksToDo = tasksToDo;
}
}
在部署应用程序时,根据您的设置以适当的方式在环境变量中设置要使用的配置文件:
SPRING_PROFILES_ACTIVE = production, someOtherProfile
现在,当应用程序启动时,Spring 将看到活动配置文件为 "production" 和 "someOtherProfile"(可以设置多个配置文件),并且不会加载任何不适用于该配置文件的带有 @Profile
的 bean。
英文:
Based on your comments, I suggest something like the following as a solution:
Define your tasks as beans with @Component
s and annotate them with @Profile
to divide them up by the environment you want them to be used in (I prefer setting profiles as environment variables).
@Component
@Profile("production")
public class TaskA implements Task {
public void doWork(){}
}
@Component
@Profile("staging")
public class TaskB implements Task {
public void doWork(){}
}
Marking these classes with @Component
means Spring will manage them and they can be injected, perhaps into a @Component
that executes the tasks:
@Component
public class TaskDoer {
private List<Task> tasksToDo;
@Inject
public TaskDoer(List<Task> tasksToDo) {
this.tasksToDo = tasksToDo;
}
}
When deploying your app, set the profile to use in the environment variables in whatever way is appropriate for your setup:
SPRING_PROFILES_ACTIVE = production, someOtherProfile
Now, when the application starts, Spring will see that the active profiles are "production" and "someOtherProfile" (multiple profiles can be set) and will not load any beans with an @Profile
that aren't for that profile.
专注分享java语言的经验与见解,让所有开发者获益!
评论