Replace environment variables in Spring properties file other than application.properties - java

Spring Boot will automatically resolve any ${ENV} placeholders in application.properties files, with the respective environment variable.
However such resolution will not happen when I provide a quartz.properties through a PropertiesFactoryBean file for Quartz configuration.
#Bean
public Properties getQuartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
Is there any Spring way of replacing these environment variables in the property file without utilising an external library?

You can declare a new class to provide the properties (annotated with #Configuration) and also mention the #PropertySource
#Configuration
#PropertySource("classpath:quartz.properties")
public class QuartzConfig {
//...
}
In this way your spring boot application can read as many properties file as you want.

Related

How to read external properties file In Spring?

Everybody knows if we want to read the properties file, we can do as follows:
#Configuration
#PropertySource("classpath:/application.properties")
public class AppConfig {
#Value("${app.name}")
public String name;
#Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public PostService postService() {
return new PostServiceImpl(name);
}
}
But, now I have a framework which is similar to SpringBoot. It can integrate Spring with Mybatis.
The problem is preceding code only can read my project classpath file but I need to read the properties file project using my framework. How I do it?
Update
I'm sorry for everybody. Maybe I don't say clearly, so here is the picture:
I don't use SpringBoot
I want to read the project(using my framework) classpath, not my framework classpath.
Thanks.
Spring provides external configuration. By this you can run your application in different environment.
refer link :
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
If you do not like application.properties as the configuration file name, you can switch to another file name by specifying a spring.config.name environment property.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
#Configuration
#PropertySource("classpath:db.properties")
#PropertySource("classpath:project.properties")
public class DBConfiguration {
#Autowired
Environment env;
#Bean
public DBConnection getDBConnection() {
System.out.println("Getting DBConnection Bean for
App:"+env.getProperty("APP_NAME"));
DBConnection dbConnection = new DBConnection(env.getProperty("DB_DRIVER_CLASS"),
env.getProperty("DB_URL"), env.getProperty("DB_USERNAME"),
env.getProperty("DB_PASSWORD").toCharArray());
return dbConnection;
}
}
DB.properties:
#Database configuration
DB_DRIVER_CLASS=com.mysql.jdbc.Driver
DB_URL=jdbc:mysql://localhost:3306/Test
DB_USERNAME=root
DB_PASSWORD=root
project.properties:
APP_NAME=TEST APP
Spring framework can read external configuration files from different locations.
It can read the configuration file from your project directory but you would need to remove this line:
#PropertySource("classpath:/application.properties")
that limits it to your application class path.
You can check here to see the different locations spring read configuration files from.
If you are just wanting to read properties yourself from the classpath, you can use
Properties prop = new Properties();
InputStream input = this.getClass().getResourceAsStream("/application.properties")
prop.load(input);
// get the property value and print it out
System.out.println(prop.getProperty("foo"));
For non boot users who want to scan properties external to application classpath:
#PropertySource("file:/path/to/application.properties")
The "file" can be replaced with "http" for webhosted remote properties
I using next option to load properties file from anywhere, and put it into environment to access it via Environment#getProperty or #Value("name"):
#Configuration
public class MVCConfig {
#Autowired
private ConfigurableEnvironment env;
#PostConstruct
public void setup() {
Properties config = new Properties();
try (InputStream stream = this.getClass().getResourceAsStream("/custom.properties")) {
config.load(stream);
}
env.getPropertySources().addLast(new PropertiesPropertySource("mvc", config));
}
}

Reading properties values from Resource and from System Variables in Spring 4

I'm trying to configure my Spring 4 application to be able to read properties values using the #Value annotation.
I need to be able to read values from .properties files as well as from system properties.
For reading from .properties file I am using #Value("${my.propery.name}") syntax along with #PropertySource("classpath:my.properties").
For reading from system properties I am using the #Value("#{systemProperties['myVariableName']}") syntax.
In my ApplicationConfig.java class, which is the main application configuration file I have both:
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
and:
#Bean
public static PropertyPlaceholderConfigurer propertyConfigurer() {
return new PropertyPlaceholderConfigurer();
}
When both Configurers are specified, I experience an issue in which sometimes the values are resolved and sometimes not (and I get a Could not resolve placeholder exception).
When only PropertyPlaceholderConfigurer is configured, I am able to read only from .properties file.
When only PropertySourcesPlaceholderConfigurer is configured, I am able to read only from system properties.
What is the best configuration for reading from both resources?
UPDATE:
I managed to resolve the issue by registering only the PropertyPlaceholderConfigurer bean and specifying a the .properties file path as a Resource in it:
#Bean
public static PropertyPlaceholderConfigurer propertyConfigurer() {
PropertyPlaceholderConfigurer ppc= new PropertyPlaceholderConfigurer();
ppc.setSearchSystemEnvironment(true);
final Resource resource = new ClassPathResource("my.properties");
ppc.setLocation(resource);
return ppc;
}

Loading additional spring profiles from java config

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.

How to use YAML files using Spring Framework?

My application is spring based, and I would like to load yml file from a centralized server, but the unable to do so.
My yml file is like this:
spring:
application:
name: signed-in-web
cloud:
config:
uri: ${server.url}
health:
config:
enabled: false
note: server.url is defined in vm options.
I had checked from rest client that properties are valid and available on the server.
Then I tried to copy it on a property file like this:
application.properties
LOCATION_SEARCH=${properties.app.api-key.location-search}
I had java configuration class like this:
#Profile("!test")
#ComponentScan(basePackages = { "com.company.frontend.*" })
#Configuration
#PropertySource("classpath:properties/qa_env.properties")
public class propertiesConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("bootstrap.yml"));
propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject());
return propertySourcesPlaceholderConfigurer;
}
}
I supposed that this will load the configuration like this:
#Value("${LOCATION_SEARCH}")
public static String LOCATION_SEARCH;
but I am getting null. Somehow I am not been able to find where the problem is. Will
If you're using Spring Boot you just need to call it application-qa.yaml and enable the qa profile. See also spring.config and spring.profiles in Common Application Properties.
Otherwise you just need to declare the yaml file in #PropertySource or #PropertySources.
Only if you don't want the properties in the global environment do you start needing to use PropertiesConfigurationFactory and YamlPropertiesFactoryBean to manually bind them.

Spring Boot Externalizing properties not working

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.

Categories