Using Spring #Value in bean construction - java

When my SpringApplicationContext is being boostrapped together, I want to get some values for that out of a properties file. From what I've read, it's best to use PropertySourcesPlaceholderConfigurer for this. I'm creating that bean in my spring java config and it is properly resolving the properties.
The problem is when I'm trying to use those properties in the construction of my other spring beans, like in my hibernate config. In my hibernate config, I have the following field:
#Value(value = "${myapp.database-access.url}")
public static String DB_ACCESS_URL;
Then I use that property to declare the url to access the database in my datasource bean like this:
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(DRIVER_CLASS_NAME);
dataSource.setUrl(DATABASE_URL);
dataSource.setUsername(DATABASE_USERNAME);
dataSource.setPassword(DATABASE_PASSWORD);
return dataSource;
}
Unfortunately the value is null at that point so my application bootstrapping fails. Post-construction the value is available, but apparently not mid-construction. Is there a way to get the #Value annotation to work for me in this circumstance, or do I have to use something else?
If I have to use something else, does anyone have any suggestions?

Spring does not allow injecting to static fields.
One approach:
public class Config {
public static String DB_ACCESS_URL;
#Value(value = "${myapp.database-access.url}")
public void setDbAccessUrl(String dbAccessUrl) {
Config.DB_ACCESS_URL = dbAccessUrl;
}
}

I think this is similar to the issue I was facing with the #PropertySource annotation where #Value wasn't injected in #Configuration POJOs. There are 2 ways I found to solve this:
1) Create a Spring XML config (if you don't have one already) which you'll refer to at your #Configuration class using #ImportResource and have in there a single entry: <context:property-placeholder />. That config should make #Value injection on the #Configuration class to work.
2) Don't use #Value in the #Configuration POJO but instead inject Environment and retrieve the props from there:
#Autowired Environment env;
//and further down at your dataSource bean retrieve the properties
//...
env.getProperty("myapp.database-access.url");

This is late but you can simply use #Value with constructor injection public DataSource dataSource(#Value(value = "${myapp.database-access.url}"))

Related

Spring boot PropertySourcesPlaceHolderConfigurer with #ProperySource

I have a simple question about PropertySourcesPlaceholderConfigurer and #PropertySource annotation. I have simple class with bean. I would like to inject property from application.properties and some another test.properties wiht #Value annotation. I read in several sources that #PropertySource needs to define staticPropertySourcesPlaceholderConfigurer bean. From documentation:
In order to resolve ${...} placeholders in definitions or
#Value annotations using properties from a PropertySource, one must
register a PropertySourcesPlaceholderConfigurer. This happens
automatically when using in XML, but
must be explicitly registered using a static #Bean method when using
#Configuration classes.
But for me it works fine without this bean. Is Spring in some way auto configures PropertySourcesPlaceholderConfigurer at application startup? Here is my simple example (first property is from application.properties and second from test.properties):
#Configuration
#PropertySource("classpath:test.properties")
public class AppConfiguration {
#Value("${first.property}")
private String firstProp;
#Value("${second.property}")
private String secondProp;
#Bean
public TestModel getModel() {
TestModel model = new TestModel();
model.setFirstProperty(firstProp);
model.setSecondProperty(secondProp);
return model;
}
}
The static PropertySourcesPlaceholderConfigurer bean is registered automatically when missing by PropertyPlaceholderAutoConfiguration class which appears to be introduced in Spring Boot 1.5.0.RELEASE (as there is no on-line javadoc for it in the previous releases).
Interestingly this new auto configuration is not mentioned in Spring Boot 1.5 Release Notes.

What's the Spring way of accessing properties from an entity?

I'm new to Spring and I'm building an application where some entities (JPA/Hibernate) need access to a property from application.properties. I do have a configuration class in which this is trivial:
#Configuration
public class FactoryBeanAppConfig {
#Value("${aws.accessKeyId}")
private String awsAccessKeyId;
#Value("${aws.secretKey}")
private String awsSecretKey;
}
but since entities do not have and I think they should not have the annotations such as #Configuration or #Component, what's the Spring way for them to access the property?
Now, I know I can create my own class, my own bean, and make it as a simple wrapper around the properties; but is that the Spring way to do it or is there another way?
specify Property file location using #PropertySource
Something like below
#PropertySource("classpath:/application.proerties")
You also need to add below bean in your config
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigIn() {
return new PropertySourcesPlaceholderConfigurer();
}
There is no "Spring way", since JPA entities and Spring have nothing to do with each other. Most importantly, JPA entities are not Spring beans, so Spring doesn't know or care about them as they're not managed by Spring.
You can try to hack around, trying in vain to access Spring's configuration from code that should not be trying to access it, or you can accept the truth that your design is broken and you're trying to do something that's not meant to be done.
As was proposed several times, use a service class for this. It's managed by Spring, so it can access the Spring config, and it can handle entities, so there's no crossing boundaries.
First create a public static variable in some bean managed by Spring, then make the following use of the #Value annotation.
public static String variable;
#Value("${variable}")
private void setVariable(String value) {
variable = value;
}
It will be set at runtime on startup, now you can access it from entities and everywhere else because it is just a public static var.
You can use #PropertySource to load the properties file as follows
#Configuration
#PropertySource("classpath:/com/organization/config/application.proerties")
public class FactoryBeanAppConfig {
...
}
Entities should not acces environment properties. If you are using your entity through a service, then the service can access the properties to act on the entity.

SpringCloudConfig When I use these annotations #RefreshScope #ConfigurationProperties ,I was in trouble

SpringCloudConfig trouble
When I use these annotations #RefreshScope #ConfigurationProperties, I was in trouble.
#Component
#RefreshScope
#ConfigurationProperties(prefix = "config.message")
public class MessageProperties {
private int max_num;
private boolean begin;
private String ding_department;
// getter, setter...
}
like this ! Config does not work;
but when I use only #ConfigurationProperties,it works. So What's the use of #RefreshScope. And how to fix it?
So when you use "I was in trouble" in stackoveflow you are in trouble that there is high probability no one to answer.
#ConfigurationProperties is used for mapping properties to a POJO, with prefix you start using hierarchical properties structure. SO for example based on your description your code will work if you have the following .yml
config:
message:
max_num:
begin:
ding_department:
If for example you use spring-cloud-config server to store the configuration properties and spring-boot and want on change on the file the corresponding Bean with injected conf file to be update you add #RefreshScope, but even if you do this the bean is not updated you have to call the /refresh url or to trigger event which will refresh it.

create a commons config Configuration object from standard Properties object

I am loading settings from a YAML file and having Spring autowire the results in a Properties bean like so:
#ConfigurationProperties(prefix = "myPrefix")
#Bean
private Properties getProperties() {
return new Properties();
}
However, the Properties class is rather limiting, and I would like to have an Apache commons config Configuration object. The commons config documentation says that it can be integrated with Spring, but I don't see an example for this simple use case.
How can I autowire an apache commons Configuration in Spring Boot?
I do not think there is any ready-made solution for getting an Apache Commons Configuration object. However, you can get Spring's Environment object, which implements PropertyResolver, which is much more advanced than Properties (you can retrieve properties of any class type). You can get it autowired in your application's constructor like so:
...
private final Environment env;
#Autowired
public MyApplication(Environment env) {
this.environment = env;
}
...

Properties with Spring #Configuration

If I have a PropertyPlaceholderConfigurer coming via an XML file, is it possible to have my Spring #Configuration use that as its source of properties for all the beans it handles?
#Configuration
#ComponentScan(value = { "x.y.z })
#ImportResource({ "classpath:remote-properties/applicationContext.xml",})
public class CoreConfiguration implements TransactionManagementConfigurer {
#Resource(name = "com.c.h.c.PropertyPlaceholderConfigurer")
public PropertyPlaceholderConfigurer pp;
#Bean
public PropertyPlaceholderConfigurer propertiesFactoryBean() {
return pp;
}
}
With the above, it never hits my breakpoint on pp. If I remove the #Bean and the method, I can verify that pp is populated. So how I can I register it with the configuration?
I feel pretty stupid. I was missing a right curly brace on one of my #Value annotations. I can't imagine how many times I looked at that and missed it.
So, having a PropertyPlaceHolderConfigurer in an app context you #ImportResource on will work without any problems. You don't even need to bring it in as a #Resource.

Categories