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.
Related
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.
I would like to use jsf annotations and some spring
annotations to inject a spring bean/service into a jsf managed bean.
(on the jsf bean i only want to use jsf annotations)
I dont want to use annotations like #named / #inject.
I have tried to find a solution on the net but without any luck.
Example
#ManagedBean
#ViewScoped
public class MyBean {
#ManagedProperty(value = "#{mySpringBean}")
private MySpringBean mySpringBean;
public void setMySpringBean(MySpringBean mySpringBean) {
this.mySpringBean = mySpringBean;
}
public void doSomething() {
//do something with mySpringBean
}
}
Is something like this possible without the use of xml. For example,
I would NOT like to use something like
FacesContextUtils.getWebApplicationContext(context).getBean("MySpringBean");
or in faces-config.xml
<managed-bean>
<managed-bean-name>myBean</managed-bean-name>
<managed-bean-class>com.mytest.MyBean</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
<managed-property>
<property-name>mySpringBean</property-name>
<value>#{mySpringBean}</value>
</managed-property>
</managed-bean>
Is something like the above possible with annotations and without
defining all the jsf beans/properties and the spring beans/properties for
every bean in the config xml files?
If you already have Spring container why not use its #Autowired annotation. For that, Update your faces-config.xml as suggested by Boni. Then add these listeners to your web.xml after this
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
Then add these to your applicationContext.xml
<context:component-scan base-package="com.examples" />
Now you can use Spring annotations and your bean will be something like this:
package com.examples;
#Component
#Scope(value="request")
public class MyBean {
#Autowired
private MySpringBeanClass mySpringBean;
}
Annotate your MySpringBeanClass with #Service
See Also:
#Scope("request") not working
Put this code in your faces-config.xml
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
</faces-config>
Then in your ManageBean Constructor call;
WebApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
mySpringBean = ctx.getBean(MySpringBean.class);
MySpringBean mean your Spring Bean Class
Assuming you have configured Spring properly in web.xml and applicationContext.xml.
Make the following entry in faces-config.xml
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
Your sample code given above seems fine. What will happen with above entry is Managed Property will be first looked in beans managed by JSF if not found will be searched in beans managed by Spring. Your spring bean should have proper annotations marked and name given in #ManagedProperty should match with default/name given to bean.
As mentioned by #Boni that is not required it is auto injected. I have used settings as you desire.
A side note: Since you are opting for view scope please have a look at this link The benefits and pitfalls of #ViewScoped
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 two Spring contexts declared in my application - one for Spring-MVC requests, and another for Flex/BlazeDS messagebroker requests, mapped to different url-patterns:
<servlet-mapping>
<servlet-name>spring-mvc</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>flex</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>
There's a common context configuration declared, (/WEB-INF/applicationContext.xml) and then each of the two contexts have their own configurations declared in spring-mvc-servlet.xml and flex-servlet.xml respectively.
Inside flex-servlet.xml I have beans declared which are specific to the flex context. However, when a call comes in to http://localhost/messagebroker/* I'm getting errors that those beans aren't available.
The code in question is inside a custom Spring component, so directly references the WebApplicationContext in order to access the declared beans:
public ISerializer getSerializer(Object source,boolean useAggressiveSerialization)
{
ServletContext ctx = FlexContext.getServletContext();
WebApplicationContext springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(ctx);
String serializerBeanName = springContext.getBeanNamesForType(ISerializer.class);
}
This approach works when I'm running with a single context. However it needs to also support where there are multiple contexts running.
Setting a breakpoint, I see that the value of springContext is the root context, with a single configLocation - /WEB-INF/applicationContext.xml
I'm asssuming that this is the problem - as the ISerializer that the above code requires is declared in flex-servlet.xml.
How do I modify the above code to support both scenarios? (Single context, and multiple contexts)?
EDIT:
The code shown above sits inside a ManageableComponentFactoryBean, which appears to operate as a custom bean factory. It seems that the ApplicationContextAware interface is not honoured on generated classes. Eg:
<bean id="dpHibernateRemotingAdapterComponentFactory"
class="org.springframework.flex.core.ManageableComponentFactoryBean">
<constructor-arg
value="org.dphibernate.adapters.RemotingAdapter" />
<property name="properties">
<value>
{"dpHibernate" :
{
"serializerFactory" : "org.dphibernate.serialization.SpringContextSerializerFactory"
}
}
</value>
</property>
</bean>
The code quoted above sits inside the org.dphibernate.serialization.SpringContextSerializerFactory. Making this SpringContextSerializerFactory implement ApplicationContextAware has no impact.
If flex is a DispatcherServlet, and for some reason you can't follow Tomás Narros's suggestion, you can obtain a context associated with the current DispatcherServlet using RequestContextUtils.getWebApplicationContext(request).
There is also a convenience method RequestContextUtils.getWebApplicationContext(request, ctx), which returns the root context if DispatcherServlet's one is not available.
Declare your custom componente as Spring Context aware:
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public MyCustomBean implements ApplicationContextAware {
private ApplicationContext springContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
springContext = applicationContext;
}
public ISerializer getSerializer(Object source,boolean useAggressiveSerialization)
{
String serializerBeanName = springContext.getBeanNamesForType(ISerializer.class);
}
}
At the bean initialization, Spring will access the setApplicationContext method of your bean, passing as an argument the context in wich it's being created. There, you can keep it an use it whenever you need.
Hrmmmm.....I have nearly that exact sort of declaration in my Spring/Flex app, using Spring/Flex integration and there is only one application context. Could that be the problem? You have beans declared in the Flex context file that aren't in the MVC context file, and they aren't really getting loaded?
I am integrating Spring MVC into an existing project I have been working on. By integrating, I mean I am rewriting the project using Spring, and using much of my old code. I have already setup the environment and have began working on it. I will refer to this project as ProjectX.
I have already setup and configured my ProjectX-servlet.xml that holds the view-resolver bean, and the controller beans, etc. I want to set up an applicationContext.xml file that I can place all my DAO beans in such as ...
<bean id="MemberDAO" class="com.xxx.xxx.MemberDAO"/>
<bean id="ProductDAO" class="com.xxx.xxx.ProductDAO"/>
I want these values to be in the applicationContext.xml so that in my controllers I can do the following.
public SomeController extends SimpleFormController{
private MemberDAO memberDao;
private ProductDAO productDao;
...getter/setter methods for memberDao;
...getter/setter methods for productDao;
and the values will be available(injecting them into the controllers)
I have configured the controllers in the ProjectX-servlet.xml like the following definition.
<bean name="/SomeController.thm" class="com.xxx.xxx.controllers.SomeController">
<property name="memberDao" ref="MemberDAO"/>
<property name="productDao" ref="ProductDAO"/>
</bean>
I believe I need to configure something such as the following in my web.xml so that it knows to load the application context.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
My question is, what do I have to do following creating an applicationContext.xml file, to be able to do what I showed above and inject beans such as the ProductDAO and MemberDAO into my controlellers which are configured in the ProjectX-servlet.xml
I have been using Spring MVC for a contract for a couple months and am comfortable with how to use it, but I am new to configuring it on my own, for my own use, so I would appreciate if any advice or answers were explained a little easier for me.
Thank you
By convention, the name you give to your instance of DispatcherServlet will be associated with {name}-servlet.xml. This context will be a child to applicationContext.xml as you described, meaning it will have access to beans in applicationContext.xml.
Try the following in your web.xml:
<servlet>
<servlet-name>ProjectX</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ProjectX</servlet-name>
<url-pattern>/projectx/*</url-pattern>
</servlet-mapping>
You don't have to do anything special. You can continue injecting beans defined in applicationcontext.xml into the beans defined in xx-servlet.xml as if all of them are declared in same file. Do remember to use the attribute ref instead of ref-local as below.
<bean id="mycontroller" class="x.y.z.CustomerController>
<property name="service" ref="myservice"/><!--myservice defined in applicationcontext-->
</bean>
Unless I'm misunderstanding, the solution you're looking for is to use an import statement in your applicationContext.xml. This effectively combines the two XML files into a single context, allowing you to reference beans in either.
Ex:
<import resource="classpath:foo/bar/ProjectX-servlet.xml" />
You may or may not want to use "classpath." See section 3.2.2.1 in the Spring docs for more details.