I have a question about trying to inject an environment variable into my spring mvc controller.
I have an environment variable as follows...
POS_MANAGER_SERVER_REPORTING=myserver
In my spring application context I have ...
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:systemPropertiesModeName="SYSTEM_PROPERTIES_MODE_OVERRIDE"
p:searchSystemEnvironment="true"/>
<bean name="posManagerController"
class="com.mycompany.reporting.controller.PosManagerController"
p:posManagerServer="${POS_MANAGER_SERVER_REPORTING}" />
When I do not define the system variable in websphere the application does not start up properly. When I add the variable it does. But for some reason the value being injected into my controller is null.
Can someone help me with what might be going wrong here? i.e. Why the environment variable is not loaded properly?
Just to give you some more information, the Controller is loaded in the child context (-servlet.xml) using the #Controller annotation but in the parent context (applicationContext.xml) I also have the controller defined as appeared above. My understanding is that spring is smart enough to be able to handle this. I've listed this information just in case this might be the cause of the issue.
thanks
Quote from documentation:
Also, BeanFactoryPostProcessors are scoped per-container. This is only relevant if you are using container hierarchies. If you define a BeanFactoryPostProcessor in one container, it will only be applied to the bean definitions in that container. Bean definitions in one container will not be post-processed by BeanFactoryPostProcessors in another container, even if both containers are part of the same hierarchy.
So, you need a PropertyPlaceholderConfigurer in -servlet.xml file to make it work.
Related
If I have a bean defined in an xml file like so :
<bean id="myBean" class="com.myClass">
</bean>
Should "myBean" be autowired, ie should the class "com.myClass" be initialized by Spring ?
I have no Spring annotations in "com.myClass" but the class still seems to be initialized because it is declared in an xml file.
Yes, it is normal that your class to be initialised even though auto-wiring is not stated. The reason for this is:
Declared Spring beans have a life-cycle and the first step in this life-cycle is for Spring to initialise the bean.
The basic life-cycle is as follows:
Initialise Bean
Insert values
Calling certain methods depending on which interfaces you implement. This is useful for further custom initialisation and configuration.
Now your bean is ready for use by your application and will stay in the application context until your application context is destroyed.
Finally, if you implement the DisposableBean interface, the destroy method is called for any de-initialisation process that you may require.
This depends on whether you have any other beans that want Spring to inject myBean into them. If no one uses your bean, you can omit it.
I'm new to Spring and trying to figure out the best way to handle the following scenario:
We have an application where for local development and testing, all configuration values are pulled from a Properties file. When the app is deployed on to the App Server (Websphere in this case), instead of properties file we use JNDI resource properties.
Is there an accepted way of handling this in Spring? For a non-Spring application I probably would have done something like this using a good ol' factory pattern to decide the config source. For Spring, I've seen examples that use different context XML files per environment (sounds messy), or make use of Spring "Profiles".
Is there a generally accepted practice for this scenario?
Spring profiles are rather new and they were added precisely to address your problems. Moreover they should deprecate all other workarounds like different context XML files you mention.
For the sake of completeness here is an example:
<beans profile="test">
<context:property-placeholder location="/foo/bar/buzz.properties" />
</beans>
<beans profile="prd">
<jee:jndi-lookup id="properties" jndi-name="foo/bar/name"/>
</beans>
Depending on which profile you choose during deployment/startup, only one of the beans above will be instantiated.
Another approach I've never tried but seems to fit your case is default-value attribute in jee namespace:
<jee:jndi-lookup id="properties" jndi-name="foo/bar/name" resource-ref="true"
default-value="classpath:foo.properties"/>
Not sure if this will help you though.
Assuming Spring 3.1, try using profiles like Tomasz suggested, but instead of setting individual JNDI values for production, use
<beans profile="prd">
<context:property-placeholder/>
</beans>
In Spring 3.1, ContextLoaderListener apparently pulls in JNDI props as a PropertySource by default, so with property-placeholder, when you need to access a value you can just use ${some/jndi/name} in applicationContext.xml or a #Value annotation.
To make sure the webapp gets the values from JNDI, add
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>prd</param-value>
</context-param>
to web.xml.
In your tests, set the system property 'spring.profiles.active' to 'test', and you'll get the values from the props file.
one way to go is you use jndi also for local dev and testing. You could define the same jndi name. I don't know what's your testing server, in practice we use jetty, and maven-jetty plugin to test. It is lightweight and can run from your ide.
another way is like what you said in your question. Making use of Spring profile. Then you could declare different transactionManager beans with same id/name. of course they should be in different profiles. At runtime you could decide which profile should be activated, that is, which bean should be used.
Our application contains struts and spring. Struts action classes are also configured as spring beans in applicationContext.xml. Spring class references are wired to action classes using 'property'.
For Ex.,
applicationContext.xml
<bean id="sampleAction" class="com.arizona.sample.action.SampleAction">
<property name="sampleManager" ref="sampleManager" />
</bean>
In SampleAction, I got to write a static method where it uses 'sampleManager' reference. So, I have configured 'sampleManager' as static variable. At runtime I got a NullPointerExcpetion at the place where 'sampleManager' is used. I have concluded that 'sampleManager' ain't get initialized.
Can anyone please help me in this regard?
P.S.: I have provided setSampleManager(..) and also tried with #Autowired.
If you find yourself trying to interact with an inherently non-static object (sampleManager) from a static context (method), then your design has some fundamental flaw in it. Go back and refactor your solution to employ proper OO design, don't try to fix it with some ugly hack.
A typical use-case: I'm having applicationContext.xml and dispatcher-servlet.xml. In the parent context (applicationContext.xml) I have:
<context:property-placeholder location="classpath:application.properties" />
However, the properties loaded by it are not accessible to the web context - neither in xml, nor using #Value. (They are just not resolved and the expression (${varName}) is set as value instead)
I worked it around by adding the <context:property-placeholder> to dispatcher-servlet.xml as well, but I wondered whether:
This is expected behaviour
There isn't a better way to expose the properties to the child context.
Yes, this is an expected behaviour. <context:property-placeholder> creates a BeanFactoryPostProcessor which is applied at per-context basis. So, you'll need a postprocessor in the child context anyway.
I have a use case where I need to call a (non-static) method in the bean only-once at the ApplicationContext load up. Is it ok, if I use MethodInvokingFactoryBean for this? Or we have a some better solution?
As a side note, I use ConfigContextLoaderListener to load the Application Context in web application. And want, that if bean 'A' is instantiated just call methodA() once.
How can this be done nicely?
To expand on the #PostConstruct suggestion in other answers, this really is the best solution, in my opinion.
It keeps your code decoupled from the Spring API (#PostConstruct is in javax.*)
It explicitly annotates your init method as something that needs to be called to initialize the bean
You don't need to remember to add the init-method attribute to your spring bean definition, spring will automatically call the method (assuming you register the annotation-config option somewhere else in the context, anyway).
You can use something like:
<beans>
<bean id="myBean" class="..." init-method="init"/>
</beans>
This will call the "init" method when the bean is instantiated.
There are three different approaches to consider, as described in the reference
Use init-method attribute
Pros:
Does not require bean to implement an interface.
Cons:
No immediate indication in source code that this method is required after construction to ensure the bean is correctly configured.
Implement InitializingBean
Pros:
No need to specify init-method, or turn on component scanning / annotation processing.
Appropriate for beans supplied with a library, where we don't want the application using this library to concern itself with bean lifecycle.
Cons:
More invasive than the init-method approach.
Use JSR-250 #PostConstruct lifecyle annotation
Pros:
Useful when using component scanning to autodetect beans.
Makes it clearer that a specific method is to be used for initialisation. Intent is closer to the code.
Cons:
Initialisation no longer centrally specified in configuration.
You must remember to turn on annotation processing (which can sometimes be forgotten)
Have you tried implementing InitializingBean? It sounds like exactly what you're after.
The downside is that your bean becomes Spring-aware, but in most applications that's not so bad.
You could deploy a custom BeanPostProcessor in your application context to do it. Or if you don't mind implementing a Spring interface in your bean, you could use the InitializingBean interface or the "init-method" directive (same link).
To further clear any confusion about the two approach i.e use of
#PostConstruct and
init-method="init"
From personal experience, I realized that using (1) only works in a servlet container, while (2) works in any environment, even in desktop applications. So, if you would be using Spring in a standalone application, you would have to use (2) to carry out that "call this method after initialization.