I am trying to find a better way to access beanFactory in Spring3 Web App. Right now I setup a config.xml file with all my services that my system is going to use and in the controller I ad a line of code like:
private static XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("config.xml"));
in each controller.. Does anyone know of any better way to do this?
If you're using Spring MVC, presumably you've defined a servlet in web.xml to handle the requests, like:
<servlet>
<description></description>
<display-name>dispatcher</display-name>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
In which case you should have a Spring config file named something like dispatcher-servlet.xml in your web-inf directory. Put your bean definitions in there and they will get defined and be available when the servlet starts up.
EDIT:
Importing one bean configuation file into another, from section 3.2.2.1 of the Spring reference:
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
Autowiring bean example in controller:
#Controller
public class MyController {
#Autowired
private MyBeanClass myBeanName;
...
}
Related
I'm working on a spring-mvc project built by someone else. Everything works fine when running with Tomcat on localhost using Eclipse. I have also committed some code and they have been deployed by the supervisor successfully.
However, when I run a JUnit test which is basically as follows:
package com.my.package.test;
...
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath*:*/applicationContext.xml")
public class DataSynchronizationTest {
#Autowired
SomeMapper someMapper;
//some tests
}
I'm suddenly getting the error:
... org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.company.project.dao.SomeMapper] found for dependency: ...
This seems weird to me because that's exactly how someMapper is injected in the web application. For example, the following works just fine:
package com.my.package.controller;
...
#Controller
#RequestMapping("/foo")
#Scope("session")
public class FooController extends BaseController {
#Autowired
SomeMapper someMapper;
//...
}
I think I'm loading ApplicationContext correctly in this JUnit test because if I remove that #ContextConfiguration line or change it to #ContextConfiguration(locations = "/applicationContext.xml") then I would get the following error:
java.lang.IllegalStateException: Failed to load ApplicationContext
So if I'm using the same ApplicationContext (there is only one. I didn't create another one for testing), why does the injection works fine on server, but fails in JUnit test? Any help is appreciated.
Edit:
As M. Deinum said in the comment, I do have a ContextLoaderListener and a DispatcherServlet, both of which are defined in web.xml. Here is the relevant part of web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
However, someMapper lives in the applicationContext.xml (which is loaded by ContextLoaderListener) and apparently has nothing to do with the DispatcherServlet part. Here is the part of applicationContext.xml that is responsible for loading someMapper:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:com/company/project/dao/*.xml" />
<property name="configLocation" value="classpath:MyBatis-Configuration.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.company.project.dao" />
</bean>
SomeMapper.java and SomeMapper.xml are located in classpath:com/company/project/dao/, of course.
Consider the below code snippet:
#Controller
public class RestController {
#Scheduled(cron = "0 0 */* * * ?") // run every hour
public void runMeHourly() {
LOGGER.debug("RestController#runMeHourly triggered to run at: " + System.currentTimeMillis());
// Do your hourly work here
}
}
When I deploy this controller in a J2EE web server I see that the method RestController#runMeHourly() in triggered twice every hour.
I found a reference to something like this here on spring docs scheduling.
It says:
Make sure that you are not initializing multiple instances of the same #Scheduled annotation class at runtime, unless you do want to schedule callbacks to each such instance. Related to this, make sure that you do not use #Configurable on bean classes which are annotated with #Scheduled and registered as regular Spring beans with the container: You would get double initialization otherwise, once through the container and once through the #Configurable aspect, with the consequence of each #Scheduled method being invoked twice.
Is this related? Does this mean I need to Schedule the method runMeHourly() from outside the RestController?
[Edit 1: Looks like the #Configurable is something else and not contributing to the problem, and I have not used it anywhere. So there must be some other reason that is causing this behaviour]
[Edit 2:
My web.xml:
<web-app>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>com.company.module.ModuleContextListener</listener-class>
</listener>
</web.xml>
mvc-dispatcher-servlet.xml
<beans>
<mvc:annotation-driven />
<task:annotation-driven />
<context:component-scan base-package="com.company" />
<import resource="module/module-servlet.xml"/>
</beans>
module/module-servlet.xml
<beans>
<context:component-scan base-package="com.company.module"/>
</beans>
]
The com.company.module.ModuleContextListener is forcing the DispatcherServlet to look for a root application context, and since the root application context is same as mvc-dispatcher-servlet.xml its being loaded twice. Once as root context and again under DispatcherServlet with the name mvc-dispatcher.
Renaming the root context xml mvc-dispatcher-servlet.xml to applicationContext.xml and adding an empty mvc-dispatcher-servlet.xml solves the problem.
Thanks to #6ton for pointing this out.
I am new here, I am working on a project using hibernate and spring dependency injection and SOAP web service.
My problem is when I run my project in the console using this class:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
IServicesPharmacie pharmacieService = (IServicesPharmacie) context.getBean("service");
context.close();
Endpoint.publish("http://localhost:3597/Pharmacies", pharmacieService);
System.out.println("The service has been published with success!");
my project work fine, because with these 3 lines:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
IServicesPharmacie pharmacieService = (IServicesPharmacie) context.getBean("service");
context.close();
I can tell about my spring dependancy injection.
BUT i don't know how to run my project on a glassfish server, and tell him about my spring dependancy injection, I guess that I most have a web.xml!!!!
My spring-beans.xml is like that :
<bean class="dao.PharmImpl" id="dao"></bean>
<bean class="metier.PharMetier" id="metier">
<property name="phardao" ref="dao"></property>
</bean>
<bean class="services.ServicesPharmacie" id="service">
<property name="servmetier" ref="metier" />
</bean>
</beans>
You need to configure a ContextLoaderListener to bootstrap spring in your application. like below:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Perhaps if you are using springMVC its done as below:
<servlet>
<servlet-name>springServlet</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Please note URL-pattern is based on your requirement.
I am developing spring-mvc application.
I am not able to access beans in my filter. I am getting below exception
org.springframework.beans.factory.NoSuchBeanDefinitionException : No qualifying bean of type [com.abc.app.SessionValue] is defined
I went throw https://stackoverflow.com/a/11709272/3898076, but not able to find the problem.
I have below entry in my web.xml
<servlet>
<servlet-name>myapp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring_xyz-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
And spring_xyz-servlet.xml contains component-scan entry.
<context:component-scan base-package="com.abc.app" />
<context:annotation-config />
<context:spring-configured />
Filter code:
WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(fConfig.getServletContext());
springContext.getBean(SessionValue.class);
Is there any configuration issue in this?
Thanks.
If there is no other constraints you should try to use Spring MVC Handler Interceptors, because you are in Spring context, and handlers are almost similar to Filters.
http://docs.spring.io/spring/docs/3.0.x/javadoc-api/org/springframework/web/servlet/HandlerInterceptor.html
Example:
http://www.journaldev.com/2676/spring-mvc-interceptors-example-handlerinterceptor-and-handlerinterceptoradapter
I have a question here, how beans defined in "applicationContext.xml" could be available to controllers defined in let's say "spring-servlet.xml", so i can skip this kind of errors i have.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name '/home' defined in ServletContext resource [/WEB-INF/mmapp-servlet.xml]: Cannot resolve reference to bean 'equipementService' while setting bean property 'equipementService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'equipementService' is defined
applicationContext.xml
<?xml version="1.0" ?>
<!DOCTYPE beans PUBLIC
"-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="equipementService"
class="mmapp.service.SimpleEquipementService" />
<bean name="equipement1"
class="mmapp.domain.Equipement" />
</beans>
mmapp-servlet.xml
<?xml version="1.0" ?>
<!DOCTYPE beans PUBLIC
"-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="/home" class="mmapp.web.HelloController">
<property name="equipementService" ref="equipementService" />
</bean>
</beans>
A Spring based web-application normally has multiple runtime Spring application contexts -
A root application context(which is loaded up during the start-up of the servlet container), here is where you normally put your beans for your services - the root application context is loaded up by using a ContextLoaderListener, typically using these entries in your web.xml file:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
One or more web application contexts, which is considered a child of the root application context, holding the beans related to the UI - controllers etc. This is configured by using a Dispatcher Servlet, a special servlet provided by Spring that knows to delegate the calls appropriately to the Spring Container. The beans in the root application context are visible to the beans defined here, BUT not the other way around - this way providing a level of separation between the UI layer and the services layer . This is a typical configuration entry in web.xml file:
<servlet>
<servlet-name>lovemytasks</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/mmapp-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
If you have defined the beans this way, the equipementService should be visible to your controller.
I'm not an expert and I'm not sure if this might be a problem, but I have a suggestion.
Could you post your web application descriptor (web.xml)? Does it contain the context-param?
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>