I have searched multiple pages thru google. It tells you how to load the configuration thru the annotation. But the tutorial always forget how to use the created object in the controller.
Here is my code.
Properties file (demo.properties)
demo.out_path=c:\demo_dir
Demo Config file (DemoAppConfig.java)
#Configuration
#PropertySource("classpath:demo.properties")
public class DemoAppConfig {
#Value("${demo.out_path}")
private String OutPath;
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Servlet config (demo-servlet.xml)
<!-- Properties -->
<context:property-placeholder location="classpath:demo.properties" ignore-unresolvable="true" />
How do I call the properties inside a controller? I tried auto wire annotation of DemoAppConfig as a property but it fails. I tried instantiating the DemoAppConfig as a new class but all property were not loaded.
Note: Used spring version 4.1.7.RELEASE
I know one way is to configure system property look up in xml config as below:
<util:properties id="systemPropertyLookup" location="classpath:demo.properties"/>
Of course, you need to add in spring-util schema declaration:
<beans ....
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="....
http://www.springframework.org/schema/util/spring-util.xsd">
Then inject your property value into your controller as follow:
#Value("#{systemPropertyLookup['demo.out_path']")
private String OutPath;
Checking my project, this is how I have been loading persistence.properties and I have been able to use #Value just like you have configured:
#Configuration
#ComponentScan(basePackageClasses = Application.class)
class ApplicationConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setLocation(new ClassPathResource("/persistence.properties"));
return ppc;
}
}
Make sure that it is on the classpath and that the compiler copies the resource file into the distributable.
Related
What is the purpose of adding "PropertySourcesPlaceholderConfigurer" as a bean in spring? . As far as I researched it says when you name your property file as application.properties, spring will automatically take the file when it is in src/main/resources Folder. Having so, when I remove the Bean Declaration for PropertySourcesPlaceholderConfigurer, it says couldn't autowire the property.
What am I missing, Why isn't it working without PropertySourcesPlaceholderConfigurer
Sample 1:
#Configuration
#PropertySource(value = { "application.properties" }, ignoreResourceNotFound = true)
#ComponentScan(basePackages = { Some Package })
public class ApplicationConfig {
ApplicationConfig() {
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Sample 1 works fine, When I remove #PropertySources and #PropertySourcesPlaceholderConfigurer bean since spring will pick up application.properties automatically, it doesn't work.
it says when you name your property file as application.properties,
spring will automatically take the file when it is in
src/main/resources Folder
As I know - this is correct only for Spring Boot.
For spring core you should define you prps in contxet.
There are several ways.
In xml
< context:property-placeholder location="classpath:application.properties" />
or using Java annotation
#Configuration
#PropertySource("classpath:application.properties")
It's not necessary to define PropertySourcesPlaceholderConfigurer since Spring 4.3RC2
To my surprise I have had a difficult time finding an answer to this question. I have Seen many examples where you can use #PropertySource to load a specific properties file for a class. I have also seen examples where you can easily add different property files in spring boot projects. But what I want to do is to do this for a spring project that is NOT spring boot and load a properties file so that the values of this file can be injected in classes annotated with #Component which is dependent on the server environment. So for example if I am on development server I want a particular properties file loaded and on production a different properties file. The reason that I am doing it like this is because my data and service layers are their own modules. These modules contain their own unit tests and can be imported as their own modules in other spring boot projects. I need properties files to be loaded to serve these modules which use spring but not spring boot. I have tried the following, but this does not work.
#Configuration
#Profile("test")
#EnableJpaRepositories("com.hi.repository")
#EnableTransactionManagement
#EnableScheduling
public class InfrastructureConfig {
...
#Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
Map<String, String> env = System.getenv();
String propertiesFile=null;
String e = env.get("SERVER_ENV");
if (e.equals("dev")) {
propertiesFile = "environment/development.properties";
} else if (e.equals("prod")) {
propertiesFile = "environment/production.properties";
}
configurer.setLocation(new ClassPathResource(propertiesFile));
return configurer;
}
Then I have a test which looks like this
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/spring/DealServiceTest-context.xml"})
#ActiveProfiles("test")
public class LogTest {
private static final Logger log = LogManager.getLogger(LogTest.class);
#Autowired
PathsService pathsService;
#Autowired
Environment environment;
#Test
public void testBeans(){
System.out.println("********** WASSUP from LogTest");
System.out.println(environment.getProperty("imageBucket"));
}
Although the test prints out null which indicates to me the properties file has not been loaded and prepared for its values to be injected. How can I achieve this?
You don't really need to set properties yourself, but you can do this using spring configuration. Check the documentation: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties
If you're using spring boot - all you need to do is create multiple properties file for your environments. And only for properties you need to override.
So your main properties file would be at
src/main/resources/application.properties
Production
src/main/resources/application-prod.properties
Development
src/main/resources/application-dev.properties
Testing
src/main/resources/application-test.properties
And then just use the profile name as your environment variable
java -jar -Dspring.profiles.active=prod demo-0.0.1-SNAPSHOT.jar
Actually, you can just use a placeholder in #PropertySource annotation.
See documentation:
Any ${...} placeholders present in a #PropertySource resource location will be resolved against the set of property sources already registered against the environment.
Assuming that placeholder is present in one of the property sources already registered, e.g. system properties or environment variables, the placeholder will be resolved to the corresponding value.
I've made a simple example, it receives a 'property.environment' value to choose, which .properties file should be used as property source. I have two resource files in my classpath - application-test.properties and application-dev.properties, each one contains a 'test.property' value ('test-env' and 'dev-env' respectively).
Property configuration:
#Configuration
#PropertySource("classpath:/config/application-${property.environment}.properties")
public class PropertyConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
return propertySourcesPlaceholderConfigurer;
}
}
Component with #Value
#Component
public class TestService {
#Value("${test.property}")
String testProperty;
#PostConstruct
void init() {
System.out.println("---------------------------------------------------------");
System.out.println("Running in " + testProperty + " environment");
System.out.println("---------------------------------------------------------");
}
}
Build command line example (it runs tests with test environment properties)
mvn clean install -DargLine="-Dproperty.environment=test"
Output
---------------------------------------------------------
Running in test-env environment
---------------------------------------------------------
Run command line example
java -jar -Dproperty.environment=dev PATH_TO_YOUR_JAR.jar
Output
---------------------------------------------------------
Running in dev-env environment
---------------------------------------------------------
Don't hard code based on different environment, in spring boot you can able to maintain properties specific environment easily. Refer https://spapas.github.io/2016/03/31/spring-boot-settings/
I would try to take advantage of the profile mechanism already in place in Spring. You basically have done the job yourself already, the only thing you need to change is to have different configurations for "test" and "production" profiles. I prefer to keep everything related to test away from production code (allowing me to place the TestConfig class below in the test source path), so I would probably do something like this:
#Configuration
#Profile("!test")
#PropertySource(value = "classpath:/environment/production.properties")
#Import(AppConfig.class)
public class ProductionConfig
{
// Your production-specific config goes here
}
#Configuration
#Profile("test")
#PropertySource(value = "classpath:/environment/development.properties")
#Import(AppConfig.class)
public class TestConfig
{
// Your test-specific config goes here
}
#Configuration
public class AppConfig
{
// Needed for spring to handle ${property:default} syntax
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigIn() {
return new PropertySourcesPlaceholderConfigurer();
}
}
If you prefer to have one config for both cases, you can let the AppConfig import the TestConfig and the ProductionConfig instead, but that will put test code in to production...
Good luck with your project!
I am running into a problem where I can't access a Spring property from my Java code.
Here is the context:
<context:property-placeholder ignore-resource-not-found="false"
location="file:/${setup.properties.directory}/setup.properties"/>
The setup.properties file looks like this:
paymentProvider.x.url=x
The code is:
SpringContext.INSTANCE.getEnvironment()
.getProperty("paymentProvider.x.url");
There are no errors during run. However, the result of the code above gives null.
Anyone knows why?
Modify context:property-placeholder configuration like:
<context:property-placeholder location="classpath:setup.properties" />
Where you want to access this properties value on that class level use one annotation like:
#PropertySource(value = { "classpath:setup.properties" })
And to read the properties values autowire Environment inside that class like:
#Autowired
private Environment environment;
And finally you can access like:
environment.getRequiredProperty("paymentProvider.x.url");
Only
#Configuration
#PropertySource("file:/${setup.properties.directory}/setup.properties")
public class SpringContext {
public static final ApplicationContext PROPERTIES_INSTANCE = new AnnotationConfigApplicationContext
(SpringContext.class);
}
works for me.
I am started writing application where I wanted to include as much spring configuration in java code as I can. The problem that I encounter is with properties file. Take a look what I have writen so far:
File containing beans declaration:
#Configuration
#ImportResource("classpath:properties-configuration.xml")
public class ContextConfigutarion {
#Value("${database.url}")
private String database_url;
#Value("${database.user}")
private String database_user;
#Value("${database.password}")
private String database_password;
#Value("${database.default.shema}")
private String database_default_shema;
#Bean
public BasicDataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(com.mysql.jdbc.Driver.class.getName());
dataSource.setUrl(database_url);
dataSource.setUsername(database_user);
dataSource.setPassword(database_password);
return dataSource;
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setHibernateProperties(hibernateProperties); // <- here I encountered a problem
return sessionFactory;
}
...
}
properties-configuration.xml it is minimum necessery file, used only for specify file properties location:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:database.properties" />
</beans>
When I started configuring sessionFactory object I notice a problem. As I understand in ContextConfiguration class I have to subtract every property from my database.properties file. If my application have a lot of properties then my configuration java code is redundantly growing. Isn't there better way to transfer properties through Spring to my components without extracting every single one of them.
Second related question: what is there a good way to preserve application properties in tree like structure? Because as you see in above example application properties contain: data source properties, hibernate properties, etc. which in fact is property tree. If my application whould be bigger and have more components preserving properies in tree like structure whould be great. I image that I have properties stored in catalogs like that:
/application
/hibernate
filename.properties
/database
filename.properties
/someOddComponent
/someStrangeComponent
filename.properties
filename.properties
filename.properties
So if I ask for application.properties I whould got sum for all .properties files in application directory (and sub catalogs), if I ask for hibernate.properties I whould got sum for all .properties files hibernate directory (and sub catalogs), etc. Maybe here I exaggerate the problem, what do you think?
First ditch your xml file and use a #PropertySource annotation to load the properties file and register a PropertySourcePlaceholderConfigurer in your configuration class.
#Configuration
#PropertySource("classpath:database.properties")
public class ContextConfigutarion {
#Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer ();
}
}
If you have a lot of properties instead of specifying #Value annotations use the Environment and the getProperty and getRequiredProperty methods instead.
#Configuration
#PropertySource("classpath:database.properties")
public class ContextConfigutarion {
#Autowired
private Environment env;
#Bean
public BasicDataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(com.mysql.jdbc.Driver.class.getName());
dataSource.setUrl(env.getRequiredProperty("database.url"));
dataSource.setUsername(env.getRequiredProperty("database.user));
// Other properties
return dataSource;
}
}
You don't want to have a lot of configuration files as that will only make things complex and unmaintainable. Limit them to a certain number. If you want a tree like system don't use a property file use a yaml file instead. Although a bit harder too load (not supported by #PropertySource) this allows for tree like configuration structures in a single file.
Or even better let Spring Boot handle the complexity for you (that supports both properties and yaml files out of the box). Reduces your configuration and gives you nice auto config out-of-the-box.
I have the following configuration piece on my xml file:
<util:properties id="apiConfigurator" location="classpath:api.properties" scope="singleton"/>
And here is my properties file:
appKey=abc
appSecret=def
On my spring classes I get some of the values like this:
#Value("#{apiConfigurator['appKey']}")
I would like to create a #Configuration class in Spring to parse the properties file in a way that
#Value("#{apiConfigurator['appKey']}")
still works thorough my classes that use this. How do I properly do that?
When you specify
<util:properties .../>
Spring registers a PropertiesFactoryBean bean with the name/id that you also specified.
All you need to do is to provide such a #Bean yourself
// it's singleton by default
#Bean(name = "apiConfigurator") // this is the bean id
public PropertiesFactoryBean factoryBean() {
PropertiesFactoryBean bean = new PropertiesFactoryBean();
bean.setLocation(new ClassPathResource("api.properties"));
return bean;
}