Where do you define spring bean configuration files - java

I am separating my spring bean configuration files as follows:
myapp-service.xml
myapp-servlet.xml
However I am getting the error;
Error creating bean with name 'beanName' defined in ServletContext resource [/WEB-INF/myapp-servlet.xml]: Cannot resolve reference to bean 'beanService' while setting bean property 'beanService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'beanService' is defined
All I need to do (I think) is figure out how to tell Spring to read the myapp-service.xml file where the path to beanService is defined.
Which file/location is that done in?
Thanks

It's defined in your web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
Alternatively in myapp-servlet.xml you could put:
<import resource="myapp-service.xml"/>

if you like to include more applicationContext files and are indeed developing a web application:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext-1.xml,
/WEB-INF/applicationContext-2.xml
</param-value>
</context-param>
also wildcarding works, applicationContext* will have the same effect here.
if you are bootstrapping spring context by hand e.g from code:
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] { "applicationContext-1.xml", "applicationContext-2.xml" });

Related

Create bean in spring context

<bean id="configuration" class="com.mypackage.util.Configuration" factory-method="getInstance">
<property name="path" value="${path.props.app.dev}"></property>
</bean>
Then I have the following in my class
Configuration.getInstance();
Whereas the spring application context is loaded in another class Factory like this
private Factory() {
context = new ClassPathXmlApplicationContext("META-INF/spring.xml");
}
The problem is that before Factory class is accessed the context does not load and the configuration object gives null for path whereas when Factory is accessed and after that path property is accessed it gives the correct path.
Please tell me how to do it correctly? That is how can i get my member variable path with correct data without accessing Factory class.
Assuming that you are using Spring WebMVC. There are 2 ways:
Putting you bean configurations to dispatcher config XML (mvc-dispatcher-servlet.xml)
Remain your spring.xml and specify it in web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>spring.xml</param-value>
</context-param>
In both cases, you will no longer need a class like Factory. Besides, because of that Spring creates beans in singleton scope by default, you do not need to implement a getInstance() method for your com.mypackage.util.Configuration class.

Better understanding of error : Scope 'session' is not active for the current thread

I have been putting efforts in understanding this error. I have gone through most of the questions related to this and I am not clear as most of them addressed how to solve it. I want to understand what error is and why is it coming . Please help me in understanding below :
Why does spring look into current thread for the scope "session" ? Does spring store all the request attributes and session attributes in the thread context ?
2.I recieve this error inconsistently. If it is an issue, it should come all the times.
Below is my code snippet.
-- Application context
<bean id="location" class="com.mindtree.ruc.cmn.utils.LoginLocation" scope="session">
<aop:scoped-proxy/>
</bean>
<bean id="homePageRH" class="com.rsaame.pas.home.ui.HomePageRH">
<property name="location" ref="location" />
</bean>
-- web.xml
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
-- logs:
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.rsaame.pas.dao.cmn.PASStoredProcedure]: Constructor threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.location': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:141)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:108)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:280)
... 42 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.location': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:341)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:192)
at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:33)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.getTarget(Cglib2AopProxy.java:653)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:604)
The Problem is that the session scope is only available in Spring Contexts that run in a Web Context. -- But in a normal web application you have two Spring Contexts!! One that is started by
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
and a second that is started by:
<servlet>
<servlet-name>SpringProject-DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/webmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
In the first context (loaded by the ContextLoaderListener) it does not run in a "WebContext", therefore do not have a session scope!
Easyest solution When possible: Move that sesson scoped been to the web context (webmvc-config.xml in the example above)
Maybe this helps a bit: ContextLoaderListener or not?
The answer to your first question lies in your configuration itself. The bean scope is defined as session and you have specified <aop:scoped-proxy/> as well. This means that this particular bean is to be used within a thread which mandatorily has a HTTP session associated with it. If in case no session is available you get the mentioned error.Answer to second question is that it seems you are referring this bean from at least two other beans; one which has HTTP session associated with it while the other doesn't. Hence the issue is intermittent.To get rid of it you need to analyse your bean definitions and ensure that bean in question is used / injected such that a HTTP session is available while invocation.

Java, Spring Tests, how do I configure logging normally defined in web.xml?

I have the following defined for my test:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration("/App/webapp")
#ContextConfiguration({
"classpath:/config/AConfig.xml",
"classpath:/config/BConfig.xml",
"classpath:/config/CConfig.xml",
"classpath:/config/DConfig.xml"
})
public class MyTests{
...
}
In web.xml I use the same configuration plus additional configuration, for instance to configure filters and listeners. How can I enable these when doing tests?
It would be great if Spring just used the same web.xml but I guess that might not be an option.
I have this defined in web.xml:
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:/config/log4j.properties</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
Is there a way to configure logging from a a contextConfig.xml ( bean definition ) instead?
http://codebyexample.info/2012/03/31/how-log4j-and-junit-became-friends/
that may be helpful, in particular the part where the author does:
Logger.getRootLogger().addAppender(someAppender)
You should be able to access Logger.getRootLogger() and configure it there.
If you want to use the properties file, you can do:
PropertyConfigurator.configure("/config/log4j.properties");
How to configure log4j.properties for SpringJUnit4ClassRunner?
or manually configure it like:
Logger rootLogger = Logger.getRootLogger();
rootLogger.setLevel(Level.INFO);
rootLogger.addAppender(new ConsoleAppender(
new PatternLayout("%-6r [%p] %c - %m%n")));
These configurations should be done once before all classes are run, though I don't think they harm too much if you do them in a #Before method.

Difference Between web-app's context-param and servlet's init-param?

I'm using Spring MVC. In a Controller class, I want to use the #Value annotation to inject a value that comes from a properties file:
#Value("${upload.dir}")
private String uploadDir;
So I need to put a property-placeholder somewhere.
The web.xml is typical:
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/mvc-dispatcher-servlet.xml</param-value>
</init-param>
...
</servlet>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/business-context.xml</param-value>
</context-param>
First, I put the placeholder in business-context.xml. It doesn't work: "Could not autowire field".
Then I put it in mvc-dispatcher-servlet.xml, it works.
So I'm confused about these two contexts, are they the same one or different? Because the beans I defined in business-content.xml can be autowired, but the #Value doesn't work.
I don't want to put the placeholder in both xml files 'cause I have a long 'location' property. Also the business-context.xml will be used by some jobs, so it cannot be omitted.
Any way to make placeholder defined in business-context.xml become visible in mvc-dispatcher-servlet.xml as well?
A BeanFactoryPostProcessor which is what the property-placeholder is will only operate (and be visible) to the application context it is defined in. This is by design. So no you cannot make a property-placeholder from a parent visible to a child context (well with some nasty hacks you could).
As a work around you could do the following in your business-context.xml
<util:properties id="applicationProperties" location="path-to-your-very-long-location" />
<context:property-placeholder properties-ref="applicationProperties" />
and this in your mvc-dispatcher-servlet.xml.
<context:property-placeholder properties-ref="applicationProperties" />
Define the same <context:property-placeholder ../> in both xml context and simply reference the already loaded properties. Added advantage the properties are only loaded once.

Bean in DispatcherServlet accessing sibling bean

We have a web application with both a root application context (applicationContext.xml) and a dispatcher servlet (dispatcher-servlet.xml) defined in our web.xml like so:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
...
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
Due to the access restrictions, we obviously cannot access any of the DispatcherServlet beans from the root parent context.
But, what we'd like to be able to do is access the sibling beans. For example, in our dispatcher-servlet.xml we have:
<bean id="firstController" class="org.springframework.web.servlet.mvc.multiaction.MultiActionController">
...
</bean>
<bean id="secondController" class="org.springframework.web.servlet.mvc.multiaction.MultiActionController">
...
</bean>
How can we access the secondController from inside firstController, without requiring that it be passed in as a constructor-arg, or set as a property?
We're using WebApplicationContextUtils.getWebApplicationContext(...) to access siblings in the root applicationContext.xml, but we'd like to do the same thing in the child context. (From within one of the children.)
you can get an ApplicationContext object using
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("dispatcher-servlet.xml")
This is assuming dispatcher-servlet.xml is in class path. context object has to be cached.
Then use context.getBean() to access beans from any where.
Other option seems to be , use overloaded method where we can pass the context attribute name. I have not used it.
WebApplicationContextUtils.getWebApplicationContext(ServletContext sc, String attrName)

Categories