在初始化时加载 Spring Boot 属性并尊重所有属性并根据属性文件中的值控制 @Aspect
Posted
技术标签:
【中文标题】在初始化时加载 Spring Boot 属性并尊重所有属性并根据属性文件中的值控制 @Aspect【英文标题】:Spring boot properties to be loaded at initialization and respect all and control @Aspect based on the value from property file 【发布时间】:2019-06-28 08:50:38 【问题描述】:我们正在使用@PropertySources
从外部文件加载属性。现在我想基于属性启用/禁用@Aspect
。我尝试使用@ConditionalOnExpression
,但没有成功。我通过创建propertyplaceholderconfig
的bean 来尝试相同的方法。即使在相同的情况下,它也不起作用。然后我尝试了@profile
,它最初也不起作用。
我发现当启动时使用propertysource
或propertyplaceholder
bean 时,这些变量在启动时并未初始化。某些变量总是被忽略,例如(logging.file)。但是@Value
工作正常。为了设置这些变量,我必须将它们作为 JVM 参数传递。
所以我的问题是:
1. 如何让 spring 在启动时始终读取指定的属性文件并尊重所有这些文件?
2. 这是启用/禁用@Aspect
的最佳方式。使用@profile
或@ConditionalOnExpression
或其他什么?
目前,我们在 main 方法中设置 logging.file
,因为它的行为方式也相同。但是你们知道这不是正确的方法,因为我最终可能会像这样一个一个地添加属性。我想将所有属性放入外部文件中,以便 spring 读取这些文件并设置其属性。
我们的属性结构:
-
common.properties #这有所有的共同属性
service.properties #特定于服务的属性。这还将包含来自 common.properties 的现有属性,这些属性将被覆盖。
我了解我可以使用个人资料。但是,我们希望将属性保留在外部,如果您要更改属性,则需要重新启动服务。我也不想将变量作为 JVM 参数传递,然后我必须以这种方式传递大部分变量。传递 -Dspring.config.location 也很困难,因为使用了 common.properties
和 service.properties
,并且每个服务的“service.properties”文件名各不相同。
示例代码:
主类:
@PropertySources(
@PropertySource(value = "file:$property_path/common.properties", ignoreResourceNotFound = false),
@PropertySource(value = "file:$property_path/service1.properties", ignoreResourceNotFound = true) )
public class MainClass
static String logDirectory = ApplicationContext.getGlobalProperty("logging.file");
public static void main(String[] args)
SpringApplication springApplication = new SpringApplication(MainClass.class);
Properties properties = new Properties();
properties.put("logging.file", logDirectory);
springApplication.setDefaultProperties(properties);
springApplication.run(args);
应用程序上下文:
@Configuration
@EnableAutoConfiguration
public class ApplicationContext implements EnvironmentAware
private static Environment environment;
@Override
public void setEnvironment(Environment environment)
ApplicationContext.environment = environment;
public static String getGlobalProperty(String propertyName)
return environment.getProperty(propertyName);
在这里您可以看到我使用environment
获取property
的任何方式。有没有办法使用环境设置属性,以便在 spring boot 初始化本身时填充属性?
我们还可以实现ApplicationContextInitializer
并重写initialize
方法来读取属性。但是我怎样才能让它读取 2 个属性文件并用最新的值覆盖重复的属性呢? Reference(I'm not sure how to implement my requirements in this way.)。即使在这种情况下,您听起来也不像是想用锤子杀死蚊子吗?
当前工作解决方案:
@Aspect
@Profile("!production")
@Configuration
public class ControllerAspect
@pointcut(....)
//Here also I've to pass spring.profiles.active as JVM params.
//setting the value in common.properties or service1.properties is not working.
我是 Spring Boot 的新手,所以请让我知道以获取更多说明。
【问题讨论】:
【参考方案1】:似乎 Spring 默认会在初始化时加载一些属性,除非您专门编写逻辑来覆盖它们(就像我在 MainClass.java
中写的那样)没有选项可以覆盖这些。其中一些包括(logging.file,@ConditionalonExpression 中使用的键)。
一些具有自身挑战的技巧:
-
在您的类路径中指定
application.properties
中的属性。在早期阶段加载的变量总是从此文件中读取。 挑战:我已将所有属性紧密耦合到 jar 中,为了更改值,我必须重新编译并重新启动 Jar。
使用配置文件并将application.properties
定义为application-profile.properties
。 挑战:我要创建这么多个人资料,但之前的挑战仍然存在。
将属性值作为 JVM 参数传递为 -Dproperty.key=value
。 挑战:认真吗?我应该发送多少个属性作为 JVM 参数?
实现 ApplicationContextInitialize
并覆盖 initialize
方法。挑战:不建议覆盖 Spring 的默认行为,仅将其用于读取属性文件是不是有点矫枉过正?
解决办法:
使用-Dspring.config.location
指定属性文件。在这种情况下,spring 总是只从指定的位置读取属性。您也可以提供多个属性文件。 Refer this for much more details. 似乎如果您在目录弹簧以相反的顺序加载它们时提供属性位置。但是如果你指定文件,它会按照指定的顺序。
注意:所有这些都可以组合在一起。 To know about precedence refer this.
【讨论】:
以上是关于在初始化时加载 Spring Boot 属性并尊重所有属性并根据属性文件中的值控制 @Aspect的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot 2 - 在初始化 bean 之前做一些事情