I have 2 XML files called spring-context.xml and spring-view.xml. spring-context.xml is declared inside the context context-param tag in web.xml file.
spring-view.xml file is declared inside the spring servlet init-param in web.xml. I have declared propertyConfigurer bean in spring-context.xml. The following code in spring-view.xml
<bean name="/home" class="com.company.web.controller.view.HomeViewController" >
<property name="msg" value="${message}"></property>
</bean>
${message} not resolved .
If I declare the propertyConfurer bean in spring-view.xml ${message} is resolved and working very fine.
What could be problem here.
If I declare a propertyConfigurer bean in spring-context.xml. This propertyConfigurer bean is accessible in spring-view.xml ?
No... Bean(Factory)PostProcessor operate only on/in the ApplicationContext they are loaded in. The Bean(Factory)PostProcessors in the root context don't operate/modify beans in the child contexts and vice-versa.
You need to declare the beans twice to have placeholders replaced in both contexts.
Related
I have a situation very similar to "Inject a file resource into Spring bean"
I have a controller that uses some .jasper compiled files and I am declaring them as such
//...
#Controller
public class InvoicingController {
private Resource quoteTemplate;
...//
And in my context configuration file
<bean id="invoicingController" class="x.x.InvoicingController">
<property name="quoteTemplate" value="/WEB-INF/jasper/Quote.jasper" />
...
I set a breakpoint on the setQuoteTemplate() function and it is being called and the Resource object is being set properly when I initialize the container. However when I actually hit the controller quoteTemplate is null.
I am under the understanding that Controllers are singletons and unless there is a gap in my understanding I am not sure why the values that are set during the container's initialization become null when I hit a url that the controller handles.
EDIT:
Thanks #Sotirios Delimanolis
I ended up declaring beans as such:
<bean id="quoteFile" class="java.io.File">
<constructor-arg value="resources/jasper/Quote.jasper" />
</bean>
<bean id="quoteTemplate" class="org.springframework.core.io.FileSystemResource">
<constructor-arg ref="quoteFile" />
</bean>
And then #Autowireing the dependencies as such
#Autowired #Qualifier("quoteTemplate") private Resource quoteTemplate;
#Qualifier is used because I have multiple Resource implementation classes declared as beans and this makes sure the correct one gets used.
You can't be using both the #Controller annotation and a <bean> declaration, unless you don't have a component-scan. You will end up with two bean definitions where the last one will overwrite the first one.
In this case, it seems like the component-scanned bean definition comes second and overwrites the bean you created with <bean>.
Choose which bean declaration method you want to use.
I have a root context file (applicationContext.xml) and a child context file (subContext.xml).
I get a NoSuchBeanDefinitionException when I try to access a bean from applicationContext.xml in subContext.xml
subContext.xml bean:
<bean id="myInfo" factory-bean="myInfoFactory"
factory-method="getInstance" scope="request">
<aop:scoped-proxy proxy-target-class="true" />
applicationContext.xml bean:
<bean id="myInfoFactory"
class="org.wcw.factory.MyInfoFactory" />
Error I get is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myInfoFactory' is defined
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
portlet.xml
<portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
<init-param>
<name>contextConfigLocation</name>
<value>/WEB-INF/subContext.xml</value>
</init-param>
If I move the myInfoFactory bean declaration from applicationContext.xml to subContext.xml, it's not throwing that exception anymore. Not sure why it's invisible when declared in applicationContext.xml. I cannot permanently move the bean to subContext.xml because of my environment.
MyInfoFactory Class
public class MyInfoFactory {
private Logger log;
#Autowired
private PortletRequest request;
...
public MyInfo getInstance(PortletRequest request) {
}
...
}
The problem with this is not about the configuration itself, but about where you are trying to recover that particular bean.
If you try to inject that request-scoped bean, defined in the child ApplicationContext (subContext.xml) from within a Bean defined in the Parent application context, the one given by the listener (applicationContext.xml) you won't be able to 'see' that particular been.
This relationship works in the other direction. The child can actually see every been defined in the parent container.
One solution could be to move your request proxies to the parent, since they are proxies you can do that. Though, a runtime will be thrown if no request available when you try to use that particular bean.
I need to access a bean from another bean in Spring. The obvious solution to this, that I know of, is to use the ref tag in the spring config file. But let's say I am not able to modify the spring config file. Is there another way to access beans within other beans?
A few options:
use annotations - #Inject private AnotherBean bean; (or #Autowired) (preferred)
get ahold of the ApplicationContext (for ex. implement ApplicationContextAware) and call .getBean(..)
Java:
class MyBean {
#Autowired
private OtherBean theBeanYouWantToGet;
}
XML:
<beans ...>
<context:annotation-config/>
<import resource="the-other-xml-file-that-you-can't-touch.xml"/>
<bean class="...MyBean"/>
</beans>
I have a need to change the spring applicationContext.xml file that is used based upon a property, this property MUST be defined somewhere outside of the war file (ie. it can't be in web.xml). Currently, I've arrived at the following solution (see my answer below), wondering if there's a better way to do this?
Have you considered using the beanRefContext approach. (ContextSingletonBeanFactoryLocator). This way you can configure your spring config files (and their names) via another spring config file.
Then you can paramaterise that file by whatever means you deem appropriate and switch the file names that way.
The file looks like this:
<beans>
<bean id="businessBeanFactory" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg value="${NameOfBeanConfigFile}" />
</bean>
</beans>
And you can use PropertyPlaceHolderConfigurer to set the value of NameOfBeanConfigFile.
I like this approach as it means I can mix static bean config file names with dynamic bean config file names and thus don't have to duplicate bean config.
When I had to do a similar thing I would parameterise via a config file loaded as a URL resource (via jndi)
there are 4 parts to my solution. first, in web.xml of my application I define the following:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation1</param-name>
<param-value>classpath:applicationContext-1.xml</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation2</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>com.my.package.MyContextLoaderListener</listener-class>
</listener>
Then I extend ContextLoaderListener
package com.my.package;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.ContextLoaderListener;
public class MyContextLoaderListener extends ContextLoaderListener {
#Override
protected ContextLoader createContextLoader() {
return new MyContextLoader();
}
}
and ContextLoader
package com.my.package;
import javax.servlet.ServletContext;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.ContextLoader;
public class LnvContextLoader extends ContextLoader {
private static final String APP_CONTEXT_PROP = "MY_CONTEXT_LOAD_PARAM";
#Override
protected void customizeContext(ServletContext servletContext,
ConfigurableWebApplicationContext wac) {
//check for system property first, if not defined, check for env variable
String appContextParam = System.getProperty(APP_CONTEXT_PROP);
if(appContextParam==null)
{
appContextParam = System.getenv(APP_CONTEXT_PROP);
}
if(appContextParam!=null && !appContextParam.equals("")){
String initParam = servletContext.getInitParameter(appContextParam);
wac.setConfigLocation(initParam);
}
}
}
and finally, in my tomcat startup, I define the environment variable in setenv.bat
set MY_CONTEXT_LOAD_PARAM=contextConfigLocation1
this solution loads it from an environment variable, but the code is flexible and allows it to be set in a system property instead.
If you load your application context through the classpath, you can override it by placing another version of the applicationContext.xml in the server's classpath.
My solution would be to have a very simple applicationContext, that includes the real application context :
applicationContext.xml :
<beans>
<import resource="classpath:realContext.xml"/>
</beans>
If you want another context, add an applicationContext.xml to your server's classpath with :
<beans>
<import resource="classpath:realContext2.xml"/>
</beans>
And have realContext.xml and realContext2.xml packaged in your WAR. No need for fancy context listener.
Just my opinion, but I quite dislike to have WARs that are not self contained. I find it very convinient to have a single unit of deployement. So I would prefer to create 2 different versions of my WAR during the build process, one for each needed configuration.
Another solution, if you want to load a different bean depending on a given property, you can use a PropertyPlaceholderConfigurer and put the name of the bean as a property :
<beans>
<bean id="bean1" .../>
<bean id="bean2" .../>
<bean id="otherBean">
<property name="injectDifferentBean" ref="${property.containing.bean.name" />
</bean>
</beans>
and a property file with :
property.containing.bean.name=bean1
or
property.containing.bean.name=bean2
I have the following defined.
#Autowired
DaoType1<object1> someDao;
#Autowired
DaoType1<object1> someListDao;
and in my bean definitions I have two beans of the same type
<bean id="someDao" class="com.example.DaoType1" />
<bean id="someListDao" class="com.example.DaoType1" />
The second bean is imported from another xml file if that makes a difference. They have different properties being set as well. Why is spring not throwing an error because 2 beans of the same type have been defined. Does it use the variable names since they match the bean ids. The dao's are different and the functionality works as expected if I had used #Qualifiers for the two different beans.
Here is a more concise version. I've left out other beans since I they are not relevant.
applicationContext.xml
<import resource="classpath:dm-services-crud.xml"/>
<bean id="ruleListCrudService" class="com.idna.dm.service.crud.impl.RuleCrudServiceImpl">
<property name="crudDao" ref="ruleListCrudDao" />
</bean>
dm-services-crud.xml
<bean id="ruleCrudService" class="com.idna.dm.service.crud.impl.RuleCrudServiceImpl">
<property name="crudDao" ref="ruleCrudDao" />
<property name="ruleNetworkOfNodesCrudService" ref="ruleNetworkOfNodesCrudService" />
<property name="elementMappingsCrudService" ref="elementMappingsCrudService" />
<property name="ruleCrudDao" ref="newRuleCrudDao"/>
</bean>
default-autowire is not present in any of my xml files at all.
This appears to be expected behaviour. The documentation says:
byName
Autowiring by property name. Spring looks for a bean with the same name as the property that needs to be autowired. For example, if a bean definition is set to autowire by name, and it contains a master property (that is, it has a setMaster(..) method), Spring looks for a bean definition named master, and uses it to set the property.
I guess this means you have specified default-autowire="byName" in your applicationContext.xml.
However, refactoring may affect this in an unpredictable way. That's why (I think) it is advisable to switch to autowiring by type, and disambiguate the beans by the use of
#Qualifier (as you noted)
#Resource rather than #Autowired (as skaffman noted)
The #Autowired annotation behaves slightly differently to the "autowire by type" specification on xml based bean definitions.
When using annotations you're not technically doing an auto wire... you're setting the value based on the annotation. The autowire annotation has the same function as the xml property element.