Spring : Initialization of properties before any bean creation - java

I have the project structure as following -
Facade -> Service-> DAO
In the DAO layer, when the beans are initialized then many dependencies are injected from a property file. Therefore, the properties file must be read first and then the remaining dao beans must be created. When the application is started then it gives an error that Spring cannot resolve a placeholder.
The DAO-application-context.xml is like-
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="prop">
<value>app.properties</value>
</property>
</bean>
<import resource = "a-dao.xml" />
<import resource = "b-dao.xml" />
<import resource = "c-dao.xml" />
Now in all the child application contexts i.e. a-dao, etc, we have-
<bean ....>
<property name = "xyz">
<value>${appValue}<value/>
</property>
<bean>
The error received is that appValue cannot be resolved. I think that it may be due to incorrect sequence of bean creation. However, the same config is working in another larger project.
I have checked Order of Spring Bean Initialization but implementing that solution would not be feasible. Is there any other way ?

Reg this Block of Configuration, property prop seems to be wrong
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="prop">
<value>app.properties</value>
</property>
</bean>
According to the Spring documentation
You could use the property location or locations to set the one or multiple values of the properties file.
So the code should be refactored to
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>app.properties</value>
</property>
</bean>

Related

Spring Boot: Properties in Parent/Child Context

So, Spring Boot automatically loads the application.properties and makes the properties available for it´s ApplicationContext, so that i.e. XML-Bean-Definitions can use them.
But i can´t find a way to "expose" these properties to Child-Contexts. I have to define a Bean for a PropertyPlaceholder in each Childcontext to manually load the application.properties from the classpath.
Is there a way to give the properties to the ChildContext, so that they are automatically resolved when used? I don´t want to load the .properties-File in the Child-Context.
Basically i create the parent-Child-Relationship with
new SpringApplicationBuilder(Application.class).child(BaseApplication.class).run();
If i have a application.properties (defined in the Application-Module) with a property called username=XXX, i can access this property of course inside the Application-Module.
But, if i have a Beandefinition inside the Child-Context (BaseApplication), let´s say:
<bean id="beanB" class="com.example.nsm.BeanB" >
<constructor-arg index="0" value="${username}"/>
<constructor-arg index="1" value="${password}"/>
</bean>
the properties are not resolved. I have to manually load the application.properties from the classpath with
<bean
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:application.properties</value>
</list>
</property>
</bean>
Then they are resolved.
In fact, i do not want to load the properties like this.
Beandefinitions from parent are visible for the Child, but properties are not? Why not? Is this intentional? If not, can this be fixed?

How to use environment variables with properties file in Spring context file

I am trying to read in a configuration file based on a system environment variable. My environment variable is FOO_ENV with value dev and dev.properties contains the properties bar.host and bar.port.
<context:property-placeholder />
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:${FOO_ENV}.properties"></property>
<property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
<bean id="myServer" class="org.apache.solr.client.solrj.impl.HttpSolrServer">
<property name="ignoreUnresolvablePlaceholders" value="true" />
<constructor-arg type="String" value="http://${my.host}:${my.port}/" />
</bean>
When I deploy this in tomcat, I get the following error:
11:48:39.324 [localhost-startStop-14] ERROR o.s.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'myServer' defined in ServletContext resource [/WEB-INF/my-context.xml]:
Could not resolve placeholder 'my.host' in string value [http://${my.host}:${my.port}]
at org.springframework.beans.factory.config.PlaceholderConfigurerSupport.doProcessProperties(PlaceholderConfigurerSupport.java:209) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
By replacing $FOO_ENV with dev in the context file, I have determined that the properties file can be read correctly. By changing FOO_ENV to other names, I can show that Spring is reading the environment variable.
It seems that the element
<property name="ignoreUnresolvablePlaceholders" value="true" />
should allow Spring to ignore that ${my.host} is not an environment variable, but though I've tried it in various places, I still get the same error, which indicates that my.host is not found.
You actually have two PropertyPlaceHolderConfigurers defined here. One via the context namespace and one explicitly. Spring is probably picking the one created via the context namespace. You could either set 'ignore-unresolvable' on the context tag and remove your propertyConfigurer bean like so:
<context:property-placeholder ignore-unresolvable="true"/>
Or if you need more control over PropertyPlaceHolderConfigurer go the other way and remove the context:property-placeholder tag.

spring dynamic domain in HttpInvokerProxyFactoryBean

I'm new to spring and its bean injection framework and I need advice on understanding how to utilize them. Currently I have the following,
<beans>
<bean id="citationService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl" value="http://localhost:8080/PPDFWeb/hello.htm"/>
<property name="serviceInterface" value="test_client.HelloService"/>
<property name="httpInvokerRequestExecutor">
<bean class="org.springframework.security.remoting.httpinvoker.AuthenticationSimpleHttpInvokerRequestExecutor">
</bean>
</property>
</bean>
</beans>
Now i need the domain name of the service url to be dynamic so I can set it somewhere programmatically in my code. Is there some way to leave the bean intact in the xml and change the serviceUrl of the bean?
Just mark it like:
<property name="serviceUrl" value="{serviceURL}"/>
Edit:
There are just too many solutions available on SO, I didn't do a good search earlier:
reading a dynamic property list into a spring managed bean
HttpInvokerProxyFactoryBean-set-url-dynamically

How to load data from property file into bean property values?

I am following the following article.
http://www.mkyong.com/spring/spring-quartz-scheduler-example/
Everything works fine.
<bean id="simpleTrigger"
class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail" ref="runMeJob" />
<property name="repeatInterval" value="5000" />
<property name="startDelay" value="1000" />
</bean>
I created a property file app.properties which has
repeatInterval = 5000
startDelay = 1000
I want to load these data into bean properties. Right now I have to hard code the values into the xml file.
I want to be able to load the data from property file into the bean properties. Is it possible?
EDIT:
I have
<property name="repeatInterval" value="5000" />
What I am looking for is a way to make it
<property name="repeatInterval" value= "get 5000 from property file" />
To find a file myPropertyFileName.properties that is on your classpath and load it into your spring config, create the following bean:
<bean id="myPropertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:myPropertyFileName.properties"/>
<property name="placeholderPrefix" value="${props:"/>
</bean>
Then use a property name defined like
repeatInterval=5000
like this:
<property name="repeatInterval" value="${props:repeatInterval}"/>
Use Spring propertyPlaceholderConfigurer to achieve this. Follow this guide.
I have run into something similar in the past. I needed to load a bunch of beans using Spring but I wanted them to be user editable bean files. So I didn't want to include them in the jar packaging. What I did was create my user-defined bean files outside the jar but in a know relative location. My packaged bean definition file referenced the beans defined in the user-defined bean file and when I loaded the application context I provided both files (user-defined & packaged).
Bit unorthodox but it worked.

How do I read JVM arguments in the Spring applicationContext.xml

I have a JSF web application with Spring and I am trying to figure out a way to reference the JVM arguments from the applicationContext.xml. I am starting the JVM with an environment argument (-Denv=development, for example). I have found and tried a few different approaches including:
<bean id="myBean" class="com.foo.bar.myClass">
<property name="environment">
<value>${environment}</value>
</property>
</bean>
But, when the setter method is invoked in MyClass, the string "${environment}" is passed, instead of "development". I have a work around in place to use System.getProperty(), but it would be nicer, and cleaner, to be able to set these values via Spring. Is there any way to do this?
Edit:
What I should have mentioned before is that I am loading properties from my database using a JDBC connection. This seems to add complexity, because when I add a property placeholder to my configuration, the properties loaded from the database are overridden by the property placeholder. I'm not sure if it's order-dependent or something. It's like I can do one or the other, but not both.
Edit:
I'm currently loading the properties using the following configuration:
<bean id="myDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc.mydb.myschema"/>
</bean>
<bean id="props" class="com.foo.bar.JdbcPropertiesFactoryBean">
<property name="jdbcTemplate">
<bean class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="myDataSource" />
</bean>
</property>
</bean>
<context:property-placeholder properties-ref="props" />
You can use Spring EL expressions, then it is #{systemProperties.test} for -Dtest="hallo welt"
In your case it should be:
<bean id="myBean" class="com.foo.bar.myClass">
<property name="environment">
<value>#{systemProperties.environment}</value>
</property>
</bean>
The # instead of $ is no mistake!
$ would refer to place holders, while # refers to beans, and systemProperties is a bean.
May it is only a spelling error, but may it is the cause for your problem: In the example for your command line statement you name the variable env
(-Denv=development, for example...
But in the spring configuration you name it environment. But both must be equals of course!
If you register a PropertyPlaceholderConfigurer it will use system properties as a fallback.
For example, add
<context:property-placeholder/>
to your configuration. Then you can use ${environment} in either your XML configuration or in #Value annotations.
You can load a property file based on system property env like this:
<bean id="applicationProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="false" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="searchSystemEnvironment" value="false" />
<property name="locations">
<list>
<value>classpath:myapp-${env:prod}.properties</value>
</list>
</property>
</bean>
If env is not set default it to production otherwise development and testing teams can have their flavor of app by setting -Denv=development or -Denv=testing accordingly.
Use #{systemProperties['env']}. Basically pass the propertyName used in the Java command line as -DpropertyName=value. In this case it was -Denv=development so used env.
Interestingly, Spring has evolved to handled this need more gracefully with PropertySources:
http://spring.io/blog/2011/02/15/spring-3-1-m1-unified-property-management/
With a few configurations and perhaps a custom ApplicationInitializer if you are working on a Web app, you can have the property placeholder handle System, Environment, and custom properties. Spring provides PropertySourcesPlaceholderConfigurer which is used when you have in your Spring config. That one will look for properties in your properties files, then System, and then finally Environment.
Spring 3.0.7
<context:property-placeholder location="classpath:${env:config-prd.properties}" />
And at runtime set:
-Denv=config-dev.properties
If not set "env" will use default "config-prd.properties".

Categories