In my Spring Boot project (SB v2.4.4) I'm trying to conditionally enable a configuration class using #ConditionalOnProperty:
#ConditionalOnProperty(
value = "feature1.enabled",
havingValue = "true",
matchIfMissing = false
)
#Configuration
public class NewConfig {
...
}
Property feature1.enabled is declared in a features.properties file that is loaded using a second configuration class:
#Configuration
#PropertySource("classpath:features.properties")
public class FeaturesConfig {
}
Properties declared in features.properties are correctly loaded, but #ConditionalOnProperty doesn't seem to resolve feature1.enabled.
I also tried to annotate NewConfig class with a #DependsOn("featuresConfig"), but nothing changes.
The only thing that seems to work is to move feature1.enabled in application.properties.
So why this is not working? What's wrong with my configuration?
As suggested by M.Denium in his comment, I solved the issue adding this command line argument on application launch:
-Dspring.config.additional-location=classpath:/features.properties
adding features.properties file as an additional configuration location for my application, fixes the property resolution issue in #ConditionalOnProperty.
Related
I have a spring boot project, with a dependency(another spring-boot project) with an implementation like this.
#Configuration
#Lazy
#Slf4j
#RequiredArgsConstructor
public class UtilityConfiguration{
private final ProducerFactory producerFactory;
#Bean
public KafkaProducer<K, V> getProducers(){
return producerFactory.getProducers();
}
}
The getProducers method reads the kafka configuration and does
new KafkaProducer<>(producerProperties)
Context of project and problem.
The above piece of code is from an utility, which also has few other things which is of the only interest in the spring boot project, and not the kafka implementation.
However, when I start the spring boot project, this producer automatically gets initialized and fails with authentication error.
I searched in SO and found that there is an exlude filter option which can be used with component scan
Eg -
#ComponentScan(basePackages = "com.basepackage", excludeFilters = #Filter(type = FilterType.ASSIGNABLE_TYPE, classes = UtilityConfiguration.class))
But, these aren't helping.
Is there a way for me to exlcude this bean from getting created at all, THAT TOO REFERRED FROM AN UTILITY?
Any assistance would be much appreciated.
Spring version - 2.3.1.RELEASE
kafka - org.apache.kafka 2.5.0
Maybe you can use #EnableAutoConfiguration(exclude={UtilityConfiguration.class}) on top of your #SpringBootApplication annotated class as referred in the official documentation.
If the UtilityConfiguration.class is not in your classpath, you can use FQN (full qualified name) of the class.
Additionally, you can use application.properties or applycation.yml to exclude class:
spring.autoconfigure.exclude
Need help, where is the issue?
I have a configuration class which is loading properties as
WebConfig.java
#Configuration
#PropertySource(value={"classpath:application.properties"})
class WebConfig extends WebMvcConfigurerAdapter{
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
I have another configuration class where I am trying to use the properties as
MyServerConfig.java
#Configuration
class MyServerConfig {
#Value("${server.url}")
private String url;
...
}
application.properties
server.url=http://localhost:8080/test/abc
But getting:
java.lang.IllegalArgumentException: Could not resolve placeholder 'server.url'.
Don't know what is missing here? Any thoughts?
Use the #PropertyScan annotation in the class where a certain property will be used:
#Configuration
#PropertyScan("classpath:application.properties")
class MyServerConfig {
#Value( "${server.url}" )
private String url;
}
For getting the values for your #Value variables, the application.properties is not needed to be configured in any special way because this file is always scanned. So remove the #PropertySource annotation and PropertySourcesPlaceholderConfigurer bean.
These are used if you want to add other .properties files (e.g. constants.properties, db-config.properties).
So just remove those and try to run your application again
Very important:
Make sure you scan the class that uses the #Value annotation (If your BootApplication is in some package instead of the 'main' package, add the proper #SpringBootApplication(scanBasePackages = { "com.my.project" }) annotation).
Make sure your application.properties is on your classpath.
Bonus If you are using spring profiles (e.g: prod, dev), you can also have application-prod.properties and application-dev.properties files that will be scanned and included depending on which profile you are running.
Is there any possibility to load aditional spring profiles from java config?
I know that I can use -Dspring.profile.active argument and also add profiles to spring.profiles.include in application.properties.
What I need is to be able to activate profiles from java config. I've created PropertyPlaceholderConfigurer, where I'm adding some custom property files, which also contains property spring.profiles.include, all properties are load and it works ok, but spring doesn't activate any profiles which are inclded using this property.
#Bean
public static PropertyPlaceholderConfigurer ppc() throws IOException {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setLocations(new ClassPathResource("properties/" + property + ".properties"));
ppc.setIgnoreUnresolvablePlaceholders(true);
return ppc;
}
The active spring profiles are defined in properties via the following configuration: spring.profiles.active:.
You should list in all the files that you import the profiles that they activate via the above configuration key.
EDIT
First, as per the official documentation the configuration spring.profiles.include is more suitable for unconditionally adding active profiles.
Second, I can assume that PropertyPlaceholderConfigurer is not suitable for what you want to achieve. The official documentation lists the ways you can Externalize Configuration. You can try to use #PropertySource:
#PropertySources({
#PropertySource(value = "classpath:application.properties"),
#PropertySource(value = "classpath:other.properties", ignoreResourceNotFound = true)
})
public class Application {
...
}
}
Additionally, you can try to list the other properties files in property spring.config.location inside application.properties as described here.
I have looked at the below threads and followed things given there. Still my property override is not happening
Spring Boot - Externalized properties
Profile Specific Property Enablement
Spring Boot External Config
I am on Tomcat 8.0.33 and Spring boot starter web and got this in my setenv.sh
export JAVA_OPTS="$JAVA_OPTS -Dlog.level=INFO -Dspring.config.location=file:/opt/jboss/apache-tomcat-8.0.33/overrides/ -Dspring.profiles.active=dev"
And in the overrides folder I got 2 files
1) application.properties
2) application-dev.properties
The application.properties has a single entry in it
spring.profiles.active=dev
I see that the proper log.level is fed to my code which means this command is working. Its just that I am clueless as to why my override is not happening as expected
I don't have any `PropertyPlaceholderConfigurer code in my workspace. I am not even sure if I need 1
I don't use this method to externalise properties. First, I'll try a suggestion for your method and then I'll show you what I'm using.
The suggestion for your method is to use file:/// instead of file:/ as with Spring I found that when not passing the three slashes after the colon it didn't recognise the property.
I've created a sample project for you, available here with instructions.
Now for the method I use.
I define a Configuration file for each profile and I keep the application.properties file under src/main/resources.
Then I use the #Profile and #PropertySource annotations on each configuration file.
For example:
#Configuration
#Profile("dev")
#PropertySource("file:///${user.home}/.devopsbuddy/application-dev.properties")
public class DevelopmentConfig {
#Bean
public EmailService emailService() {
return new MockEmailService();
}
#Bean
public ServletRegistrationBean h2ConsoleServletRegistration() {
ServletRegistrationBean bean = new ServletRegistrationBean(new WebServlet());
bean.addUrlMappings("/console/*");
return bean;
}
}
And
#Configuration
#Profile("prod")
#PropertySource("file:///${user.home}/.devopsbuddy/application-prod.properties")
public class ProductionConfig {
#Bean
public EmailService emailService() {
return new SmtpEmailService();
}
}
I have also got a Configuration file that is valid for all profiles, which I call ApplicationConfig, as follows:
#Configuration
#EnableJpaRepositories(basePackages = "com.devopsbuddy.backend.persistence.repositories")
#EntityScan(basePackages = "com.devopsbuddy.backend.persistence.domain.backend")
#EnableTransactionManagement
#PropertySource("file:///${user.home}/.devopsbuddy/application-common.properties")
public class ApplicationConfig {
}
My src/main/resources/application.properties file looks like the following:
spring.profiles.active=dev
default.to.address=me#example.com
token.expiration.length.minutes=120
Of course I could externalise the spring.profile.active property by passing it as a system property but for my case and for now it's fine.
When running the application, if I pass the "dev" profile, Spring will load all properties and Beans defined in the DevelopmentConfig class plus all those in ApplicationConfig. If I pass "prod", the ProductionConfig and ApplicationConfig properties will be loaded instead.
I'm completing a course on how to create a Spring Boot website with Security, Email, Data JPA, Amazon Web Services, Stripe and much more. If you want, you can register your interest here and you will get notified when the course is open for enrolment.
I want to be able to place a application.properties outside the classpath (eg on d:/), and there define the spring.profile.active=production.
If this is activated, spring should additionally load a properties file from classpath called my-production.properties.
I tried the following, which did not work. What might I have forgotten?
#Component
#PropertySources({
#PropertySource("classpath:my-default.properties"),
#PropertySource(value = "file:D:/my.properties"),
#PropertySource(value = "classpath:my-${spring.profiles.active}.properties", ignoreResourceNotFound = true)
})
d:\my.properties:
spring.profiles.active=production
my-default.properties:
testkey=default
my-production.properties:
testkey=production
App:
#Configuration
#EnableAutoConfiguration
public class AppCfg {
#Value("${testkey}")
private String testkey;
#PostConstruct
public void init() {
Sysout(testkey); //prints: "default" instead of "production"
}
}
If you want to put applciation properties in other location you can use command line arguments or enviroment variable.
See section 21.2 Application property files
http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/
If you just want to set the active profile, take a look at section 21. Externalized Configuration
You can override the active profile property by using OS environment variables for example.
You can set SPRING_CONFIG_NAME and SPRING_CONFIG_LOCATION environment variables to set the location of application.properties manually. Also you can use the /config subdir of the current directory or
the current directory to load the application.properties.