Spring Error - NoSuchBeanDefinitionException:SessionFactory - java

I am quite new to Spring and Java world. I am trying to write a web app looking at petclinic application provided in the samples. However, I am hitting this roadblock since yesterday. It will be great if someone can point me in right direction. I looked up many links on google, but none of the solutions worked for me.
Here is the error root cause
org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [org.hibernate.SessionFactory] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:949)
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:818)
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:730)
org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:795)
org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:723)
org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:196)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1049)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:953)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:490)
.
.
.
Here is my web.xml in WEB-INF
<display-name>Game's List</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/applicationContext-hibernate.xml</param-value>
</context-param>
<session-config>
<session-timeout>10</session-timeout>
</session-config>
<servlet>
<servlet-name>gamelist</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>gamelist</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Here is the applicationContext-hibernate.xml
<!-- ========================= RESOURCE DEFINITIONS ========================= -->
<!-- import the dataSource definition -->
<import resource="applicationContext-dataSource.xml"/>
<!-- Configurer that replaces ${...} placeholders with values from a properties file -->
<!-- (in this case, Hibernate-related settings for the sessionFactory definition below) -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<context:annotation-config />
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
p:dataSource-ref="dataSource" p:mappingResources="gamelist-hibernate.xml">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.generate_statistics">${hibernate.generate_statistics}</prop>
</props>
</property>
<property name="eventListeners">
<map>
<entry key="merge">
<bean class="org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener"/>
</entry>
</map>
</property>
</bean>
<!-- central data access object: Hibernate implementation -->
<bean id="gameDataStore" class="com.gamelist.datastore.GameItemDataStore"/>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory"/>
<!-- ========================= BUSINESS OBJECT DEFINITIONS ========================= -->
<!--
Activates various annotations to be detected in bean classes:
Spring's #Required and #Autowired, as well as JSR 250's #Resource.
-->
<context:annotation-config/>
<!--
Instruct Spring to perform declarative transaction management
automatically on annotated classes.
-->
<tx:annotation-driven/>
<!--
Exporter that exposes the Hibernate statistics service via JMX. Autodetects the
service MBean, using its bean name as JMX object name.
-->
<context:mbean-export/>
This is gamelist-servlet.xml
<context:component-scan base-package="com.gamelist"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
This is the controller class
public class GameLibraryController {
private IDataStore gameDataStore;
#Autowired
public GameLibraryController(GameItemDataStore gameDataStore){
this.gameDataStore = gameDataStore;
}
#RequestMapping("/addGame")
public String addNewGame(Model model){
model.addAttribute("gameItem",new GameItem());
return "library/addgameform";
}
#RequestMapping("/addGameSubmit")
public void add(#ModelAttribute GameItem gameItem,BindingResult result, SessionStatus status){
this.gameDataStore.add(gameItem);
status.setComplete();
}
}
This is the hibernate implementation class GameItemDataStore
#Repository
#Transactional
public class GameItemDataStore implements IDataStore{
private SessionFactory sessionFactory;
#Autowired
public GameItemDataStore(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public void add(BaseItem newGame){
sessionFactory.getCurrentSession().save(newGame);
}
}
This is the IDataStore interface
public interface IDataStore {
public void add(BaseItem newGame);
}

To avoid any confusion, I am going to assume the configuration you mentioned in the question, and start from there. (Ignoring the changes you may have tried after reading the comments on your question)
First a little background:
There are two contexts at play in a Spring MVC application. The applicationContext which is more accurately referred to as the ROOT WebApplicationContext, which is meant to be available to all Servlet level spring contexts, through an integration with the Servlet Container's lifecycle implementation. The second type of context is loaded for each DispatcherServlet configured in the web.xml lets call it ServletApplicationContext
Now, when the container starts, the Root application context is loaded
When the Servlet is loaded, the Servlet Application Context is loaded. At this point, beans from the Root Application Context are available to the Servlet Application Context.
IF, you do end up loading the same bean definitions in both the contexts, its like overriding beans in the Servlet Context. Very inefficient to load duplicate beans, and can cause weird errors if you are relying on the same instance being available in all context. But, for simple cases like a single servlet deployment, this should not cause your application to break at startup, spring will deal with this.
Now getting to what's wrong with your configuration:
There is no ContextLoaderListener configured in your web.xml. Without a ContextLoaderListener, the ROOT application context is NOT loaded. So none of the beans from /WEB-INF/spring/applicationContext-hibernate.xml are loaded.
When your servlet kicks up, it loads the beans from gamelist-servlet.xml, and cannot locate a sessionFactory bean, because the ROOT Web Application Context was never loaded~!
To confirm this, for a test, comment out all bean definitions from the two context files, just keep empty <beans></beans> tags in them. Start your server, you'll see a log statement at the end that says something like no ROOT Web Application Context found, configure ContextLoaderListener in web.xml
And the fix:
Add the ContextLoaderListener to your web.xml
You may choose to continue your configuration as you have it now, or follow the advice given in earlier comments and include only MVC related definitions in the servlet context and all else in the ROOT application context.
Another, simpler option would be to simply have an empty application context xml for the ROOT Web Application Context, and configure all beans in the servlet context. This is not correct from a purist design point of view, but a practical simple solution, provided you plan on having a single servlet application.
Sorry for the looong description, but I felt some explanation was mandated. Hope this helps.

Get rid of
<bean id="gameDataStore" class="com.gamelist.datastore.GameItemDataStore"/>
which you won't need because of #Repository on your class and
<context:annotation-config />
which you have twice. Then add
<context:component-scan base-package="com.your.package" />
where com.your.package is a top level package that contains the GameItemDataStore class.

Related

Conditionally including beans in XML ArrayList

I was wondering if it's possible to somehow conditionally include spring beans depending on some property.
In my applicationContext.xml I have a list of beans that I setup:
<bean id="server1Config" class="... />
<bean id="server2Config" class="... />
<bean id="server3Config" class="... />
...
Then I include them in a list:
<bean class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="server1Config"/>
<ref bean="server2Config"/>
<ref bean="server3Config"/>
...
</list>
</constructor-arg>
</bean>
I want to conditionally include server1Config, server2Config, server3Config, etc depending on whether ${includeServer1} == true, ${includeServer2} == true etc and if possible, only initialize those beans if they are marked for inclusion.
To clarify, it's a ping service checking if servers are online or not, each bean contains special urls. If I have 5 servers running, I'd like to set in my config includeServer1=true ... includeServer5=true ... includeServer6=false, if I shutdown server2, I'd like to change includeServer2=false before shutting down the server to not get bombarded with SMSe telling me server2 is offline.
As your names refer to different stages or enviroments, spring profiles might be helpful to use. You can define beans like this inside your context.xml
<beans profile="dev">
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
<jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
</jdbc:embedded-database>
</beans>
<beans profile="production">
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
</beans>
In the example [1] you see the usage of two profiles called "dev" and "production".
Spring will always load every bean without a profile
Depending on the profiles (yes, you can load multiple profiles at once) all the related beans will be loaded
Loading a profile in Java:
ctx.getEnvironment().setActiveProfiles("dev");
Loading two profiles
ctx.getEnvironment().setActiveProfiles("profile1", "profile2");
Loading from CMD Line declaratively:
-Dspring.profiles.active="profile1,profile2"
Usage in web.xml (can be comma-separated)
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>spring.profiles.active</param-name>
<param-value>production</param-value>
</init-param>
</servlet>
#Comment: If you want to do it using properties and you are able to use newer spring elements, annotations etc. please have a look at this tutorial [2] to make it work with properties file as you commented below.
[1] http://spring.io/blog/2011/02/11/spring-framework-3-1-m1-released/
[2] http://kielczewski.eu/2013/11/setting-active-profile-and-property-sources-in-spring-mvc/
This is almost an add-on to #swinkler's answer.
He gave the first part of the solution which is usage of Spring 3.1+ profiles.
The second part would be to use a kind of automatic registration :
<bean class="java.util.ArrayList" id="serverConfigList"/>
<beans profile="server1">
<bean id="server1Config" class="... />
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject"><ref local="serverConfigList"/></property>
<property name="targetMethod"><value>add</value></property>
<property name="arguments"><ref local="server1Config/></property>
</bean>
</beans>
That way you create an empy list and only add relevant configs to it.
Your code shouldn't change based on environment. If your aim is to use different settings for each environment then load them as properties at start up.
Refer this for 'external configuration'
This can be done in Spring framework 3.1 onwards using a built in Spring environment profiles.
Here's a few resources:
http://java.dzone.com/articles/spring-31-environment-profiles
Hope this helps.

What is the best practise for invoking service method in spring controller?

I have created a spring-config.xml file.In that file I have created all beans for service class and DAO class.Now I want to call the bean in my Spring controller.The method I already know is
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
SeviceClassName objService = (SeviceClassName) context.getBean("BeanName");
But the problem is I have put the file in WEB-INF folder.
To metigate the problem I have used
ApplicationContext context = new FileSystemXmlApplicationContext("C:/Users/xyz/Desktop/HelloWeb/WebContent/WEB-INF/spring-config.xml");
It's working fine.
But it doesn't seem to be a good practise.
Then I have tried to initialize the DispatcherServlet by spring-config.xml.
<servlet>
<servlet-name>HelloWeb</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
But I don't konw how to call the bean in controller.
I tried to use #Autowired in my spring controller.But it is not working.
Whenever I try this (#Autowired) and try to excecute a jsp file of the same application in eclipse it shows 'requested resource not avaliable".
Can any one suggest me how to solve the problem.
Or
Can anyone suggest me a better approach by which I can invoke a bean of service class which I have created in spring-config.xml.
Or
any other approach for invoking service class methods in spring controller.
I am using spring 3.0.
I have created a Dynamic Web Project in Eclipse.In my WEB-INF folder I have put 4 xml file
--web.xml,spring-config.xml,HelloWeb-servlet.xml .
My HelloWeb-servlet contains
<mvc:annotation-driven />
<context:annotation-config />
<context:component-scan base-package="com.tutorialspoint" />
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="html" value="text/html"/>
<entry key="json" value="application/json"/>
</map>
</property>
</bean>
<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jacksonMessageConverter"/>
</list>
</property>
</bean>
My spring-config contains all the bean configuration.In the spring controller I just to invoke the service method which are written in the service class for which I have already created bean in spring-config.xml.
Check this Stackoverflow answer. It is probably a much more detailed answer than what you are looking for, but it will definitely help you go through the basics.
Essentially, a root context established via a Spring context loader listener, and a servlet context established via the corresponding servlet parameter. The param name for both are contextConfigLocation(former is a listener context-param and the latter is a servlet init-param).
#Autowired or #Inject can be used to inject the service bean in the controller. Make sure that the service bean is annotated with #Service or #Resource so the bean is picked up during component scanning.

Spring Autowiring Service doesn't work in my Controller

i've problems in order to autowire a service in my controller. I've this error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private es.unican.meteo.service.UserService es.unican.meteo.controller.MyController.userService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [es.unican.meteo.service.UserService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
It seems that the userService is not registered, so that, the controller can't get the bean. I thought that my config was ok because it works with the tests. In the tests i have this:
ClassPathXmlApplicationContext("/WEB-INF/app-config.xml");
and i can get the bean ok from the ApplicationContext.xml
My package structure is the following:
es.unican.meteo.controller
|---- MyController.java
es.unican.meteo.service
|---- UserService.java
es.unican.meteo.service.impl
|---- UserServiceImpl.java
.....
WebContent/WEB-INF
|---- MyDispatcherServlet-servlet.xml
|---- app-config.xml
|---- web.xml
.....
The clases:
== UserServiceImpl.java ==
#Service
public class UserServiceImpl implements UserService{
#Autowired
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
== MyController.java ==
#Controller
public class MyController {
#Autowired
private UserService userService;
#RequestMapping(method=RequestMethod.GET, value="/home")
public String handleRequest(){
return "welcome";
}
#RequestMapping(method=RequestMethod.GET, value="/getUsers")
public #ResponseBody List<User> getUsersInJSON(){
return userService.getUsers();
}
}
== web.xml ==
<display-name>Spring MVC</display-name>
<servlet>
<servlet-name>MyDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyDispatcherServlet</servlet-name>
<url-pattern>*.go</url-pattern>
</servlet-mapping>
</web-app>
== app-config.xml ===
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<!-- Scans the classpath of this application for #Components to deploy as beans -->
<context:component-scan base-package="es.unican.meteo" />
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="org.apache.derby.jdbc.EmbeddedDriver"
p:url="jdbc:derby:C:\tools\derbydb"
p:connectionProperties=""
p:username="APP"
p:password="" />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="/mybatis-config.xml" />
</bean>
<bean id="usersMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="es.unican.meteo.dao.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<bean id="rolesMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="es.unican.meteo.dao.RoleMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
</beans>
== MyDispatcherServlet.xml ==
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<!-- Enabling Spring beans auto-discovery -->
<context:component-scan base-package="es.unican.meteo.controller" />
<!-- Enabling Spring MVC configuration through annotations -->
<mvc:annotation-driven />
<!-- Defining which view resolver to use -->
<bean class= "org.springframework.web.servlet.view.InternalResourceViewResolver" >
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
Spring mvc logger trace:
19:38:54,119 DEBUG http-8080-1 support.DefaultListableBeanFactory:430 - Creating instance of bean 'myController'
19:38:54,170 DEBUG http-8080-1 annotation.InjectionMetadata:60 - Found injected element on class [es.unican.meteo.controller.MyController]: AutowiredFieldElement for private es.unican.meteo.service.UserService es.unican.meteo.controller.MyController.userService
19:38:54,174 DEBUG http-8080-1 support.DefaultListableBeanFactory:504 - Eagerly caching bean 'myController' to allow for resolving potential circular references
19:38:54,206 DEBUG http-8080-1 annotation.InjectionMetadata:85 - Processing injected method of bean 'myController': AutowiredFieldElement for private es.unican.meteo.service.UserService es.unican.meteo.controller.MyController.userService
19:38:54,224 DEBUG http-8080-1 support.DefaultListableBeanFactory:217 - Creating shared instance of singleton bean 'userServiceImpl'
19:38:54,226 DEBUG http-8080-1 support.DefaultListableBeanFactory:430 - Creating instance of bean 'userServiceImpl'
19:38:54,234 DEBUG http-8080-1 annotation.InjectionMetadata:60 - Found injected element on class [es.unican.meteo.service.impl.UserServiceImpl]: AutowiredFieldElement for private es.unican.meteo.dao.UserMapper es.unican.meteo.service.impl.UserServiceImpl.userMapper
19:38:54,237 DEBUG http-8080-1 support.DefaultListableBeanFactory:504 - Eagerly caching bean 'userServiceImpl' to allow for resolving potential circular references
19:38:54,256 DEBUG http-8080-1 annotation.InjectionMetadata:85 - Processing injected method of bean 'userServiceImpl': AutowiredFieldElement for private es.unican.meteo.dao.UserMapper es.unican.meteo.service.impl.UserServiceImpl.userMapper
19:38:54,268 INFO http-8080-1 support.DefaultListableBeanFactory:433 - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#56088b29: defining beans [myController,roleService,userServiceImpl,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0,org.springframework.format.support.FormattingConversionServiceFactoryBean#0,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0,org.springframework.web.servlet.handler.MappedInterceptor#0,org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0,org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0,org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0,org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,org.springframework.web.servlet.view.InternalResourceViewResolver#0,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy
19:38:54,279 ERROR http-8080-1 servlet.DispatcherServlet:457 - Context initialization failed
I've reviewed some questions about this topic but i don't find a solution to my problem. Maybe i'm skipping something but i don't know certainly. I tried to change the component-scan with no results.
When i try to access to /SPRING-MVC/getUsers.go appears those errors.
I don't know if the beans must be placed in app-config (applicationContext) or in the servlet.xml because it is a little bit confusing...
Thank you
Your configuration is very strange...
First rule out the obvious
I don't see root web application context configuration in your web.xml. Could it be that you forgot to add this piece of code?
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
WEB-INF/app-config.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Now a little bit of theory
Bit of Spring theory - Spring uses application context hierarchy for web applications:
top level web application context is loaded by ContextLoaderListener
then there are separate contexts for each DispatcherServlet instances
When a new bean is being instantiated, it can get dependencies either from the context where it is being defined or from parent context. This makes possible to define common beans in the root context (services, DAO, ...) and have the request handling beans in servlet application contexts as each servlet can have its own set of controllers, view handers, ...
Last, but not least - your errors
You are configuring MVC in your root context. That is just wrong. Remove the <mvc: context from there.
You are also registering your controllers in the root context via the <context:component-scan> on your base package. Make the component scan just on the services package or separate your classes into two top level packages core (for the root beans) and servlet (for servlet beans).
Make sure that your UserServiceImpl is in same package as defined in context:component-scan. If it's not, spring will not be able to detect it. Also, try removing value attribute from UserServiceImpl definition, since there is only 1 bean of that type. Spring will be able to autowire it by type.
You need to change the way you have autowired the service in the controller.
Change the following code
#Autowired
private UserService userService;
with following
#Resource(name="userService")
private UserService userService;
Because in the UserServiceImpl you have defined the #Service annotation with alias "userService".
I hope this would resolve your problem. :)
when ever you face such kind of problem kindly check, what is the path for context:component-scan basepackage
it should be root name Like if I am taking com.mike as package name & which contain bean,controller,dao,service folder in its structure then, in such condition you have to follow Like ----context:component-scan basepackaage="com.mike.*"
where * means all the folder (bean,service,dao,controller and theie corresponding classes) will be scaned.
You can use the #Qualifier annotation as follows:
#Autowired
#Qualifier("userService")
private UserService userService;
On first glance the config seems ok, yet there may be some smaller tripwires that might be not that obvious.
a) implemented UserService interface, is it the same as the controller needs? Dumb question, I know, but just be on the safe side.
b) bean name: Try eradicating the value-value (ba-da-tush) from the #Service annotation, its superflous anyway. Or be more specific with the help of an #Qualifier.
c) package scanning: Double check if your implemented service is really within es.unican.meteo. Sometimes its the small things.
Add #Component annotation on your service. It should work fine

Spring MongoDB and Apache Shiro

I am attempting to use Apache Shiro with Spring and MongoDB. I am using Spring Data Repositories which are autowired. I have created my own custom realm for Shiro which uses a Spring Data repository to talk to Mongo:
public class PlatformRealm extends AuthorizingRealm {
#Autowired(required = true)
protected UserRepository userRepository = null;
#Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
...
}
}
The problem I'm seeing is the userRepository isn't being autowired. I get the following line in my console output referring to the PlatformRealm:
INFO org.springframework.web.context.support.XmlWebApplicationContext - Bean 'platformRealm' of type [class com.resonance.platform.core.security.PlatformRealm] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
This is because of the Apache Shiro ShiroFilterFactoryBean. What is happening is this bean and all of its dependencies are being loaded up immediately when the container is started. It doesn't wait for my persistence beans to be initialized prior to resolving dependencies. This causes the repository reference to be null.
The following bean configurations are loaded via the contextConfigLocation parameter:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/web-platform-persistence.xml,
/WEB-INF/web-platform-services.xml
</param-value>
</context-param>
Services bean configuration:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<bean id="userSession"
class="com.resonance.platform.web.core.services.ShiroUserSessionService" />
<!-- Shiro (Security) -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/login" />
<property name="successUrl" value="/" />
<!-- The 'filters' property is not necessary since any declared javax.servlet.Filter
bean -->
<!-- defined will be automatically acquired and available via its beanName
in chain -->
<!-- definitions, but you can perform instance overrides or name aliases
here if you like: -->
<!-- <property name="filters"> <util:map> <entry key="anAlias" value-ref="someFilter"/>
</util:map> </property> -->
<property name="filterChainDefinitions">
<value>
# some example chain definitions:
/admin/** = passThruFilter, roles[admin]
/** = passThruFilter
</value>
</property>
</bean>
<bean id="passThruFilter"
class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter" />
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- Single realm app. If you have multiple realms, use the 'realms' property
instead. -->
<property name="realm" ref="platformRealm" />
<!-- By default the servlet container sessions will be used. Uncomment
this line to use shiro's native sessions (see the JavaDoc for more): -->
<!-- <property name="sessionMode" value="native"/> -->
</bean>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor" />
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
<!-- Define the Shiro Realm implementation you want to use to connect to
your back-end -->
<!-- security datasource: -->
<bean id="platformRealm" class="com.resonance.platform.core.security.PlatformRealm" />
Persistence bean config:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<mongo:mongo id="mongo" />
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongo" />
<constructor-arg value="platform" />
<property name="writeConcern">
<util:constant static-field="com.mongodb.WriteConcern.SAFE" ></util:constant>
</property>
</bean>
<mongo:repositories base-package="com.resonance.platform.core.data.repositories" />
User Repository:
package com.resonance.platform.core.data.repositories;
import org.bson.types.ObjectId;
import org.springframework.data.repository.CrudRepository;
import com.resonance.platform.core.entities.User;
/**
* A repository used to manage User entities.
* #author Kyle
*/
public interface UserRepository extends CrudRepository<User, ObjectId> {
/**
* Gets a user by the specified login.
* #param login
* #return
*/
User getByLogin(String login);
}
My question is, how can I get the userRepository dependency to resolved properly? I understand that the ShiroFilterFactoryBean has to be initialized before the other dependencies and whatnot, but there must be a way to get the userRepository dependency to be resolved.
EDIT: Added User Repository code.
I am running into the same problem described here.
I am noticing two spring factories.
from the dispacher-servlet.xml which loads #Service #Repository classes due to component-scan defined at an base package level so I can #Autowire Service class into Controller.
from application context doesn't seem to #Autowire classes marked as #Service because they are not loaded.
If I understand you right you should be able to create a subclass of ShiroFilterFactoryBean which implements org.springframework.beans.factory.InitializingBean. In InitializingBean.afterPropertiesSet() you would then add some code that gets the UserRepository and sets it to that field. Not the most elegant solution, but this looks like an exceptional case.
I've had this problem too. It has something to do with the order of bean initialization in the Spring container. The workaround is not to autowire the repository but have your realm implement ApplicationContextAware and get the needed beans straight from the context. It's not elegant, but it'll work.
I am not too sure if this is helpful, but you may check this question from me for an alternative solution.
But, the core issue probably still stays open.
Concrete problem explanation taken from ShiroFilterFactoryBean-and-a-spring-data-mongodb-realm:
The problem is that spring-data-mongodb requires a spring
ApplicationEventMulticaster to have been initialised before it can be
used.
ShiroFilterFactoryBean is a beanPostProcessor, and as such, during
initialisation, spring attempts to configure its realms(and hence my
realm and spring data mongo based userDao). it fails because
ApplicationEventMulticaster has not yet been created.
After I've tried several suggested ways to solve this problem, like the InitializingBean, ApplicationContextAware or BeanPostProcessor interfaces (each resulting in a premature invocation, hence before initializing my necessary service/repository stuff), I came up with the following solution:
Let spring create your shiro context without any automatic bean resolution to your services/repositories.
Let spring create your service/repository context, including mongodb
Create a simple class which will take care of your shiro-service coupling and configure it accordingly in your spring config. This class will be invoked after your shiro and service context has been successful set up.
To (1), sth. like this:
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="filterChainDefinitions">
<value>
<!-- Your definitions -->
</value>
</property>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"
p:realm-ref="myShiroRealm" />
<bean id="myShiroRealm" class="com.acme.MyShiroRealm"
<!--no bean refs here-->
/>
To (2), sth. like this:
<bean id="myService" class="com.acme.MyService"
c:myRepository-ref="myRepository" />
...
<!-- Ask Spring Data to scan our repositories -->
<mongo:repositories base-package="com.acme.repository.impl.mongodb" />
To (3):
public class ShiroRealmServiceBridge {
public static void postInject( MyShiroServerRealm realm, MyService service ) {
realm.setService( service );
}
}
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass"><value>com.acme.ShiroRealmServiceBridge</value></property>
<property name="targetMethod"><value>postInject</value></property>
<property name="arguments">
<list>
<ref bean="myShiroRealm" />
<ref bean="myService" />
</list>
</property>
Advantages:
It works xD
No additional burden/dependencies on your shiro stuff
Complete spring configuration and setup, resulting in a consistent state after initialization
Disadvantage:
One time overhead setup
May result in an inconsistent state, which will complain at runtime rather than at startup, if you forget or bump the glue-configuration
The ShiroFilterFactoryBean implements the BeanPostProcessor and, since it has dependencies on the security manager w/ its own dependencies on data stores, data access objects, etc. it can cause a whole slew of Bean X of type Y is not eligible for getting processed by all BeanPostProcessors messages.
The worst part is that it seems to be just a way to see the Filter implementations that Spring is instantiating in order to track and possibly inject properties into AuthorizationFilters.
Frankly I don't need that headache just for filter tracking, so I created a custom version that did not include the BeanPostProcessor. I'm now forced to manually wire in Filter implementations to the beans "filters" property, but at least I don't have to deal with that error and the questionable status of my security manager and related beans.

Spring Security 3: Problem autowiring UserDetailsManager/JdbcUserDetailsManager

I'm working through Peter Mularien's Spring Security 3, and am having a problem setting up the UserDetailsManager.
I create the JdbcUserDetailsManager bean as follows:
<bean id="jdbcUserService" class="org.springframework.security.provisioning.JdbcUserDetailsManager">
<property name="dataSource" ref="mySqlDb" />
<property name="authenticationManager" ref="authenticationManager" />
</bean>
and autowire its UserDetailsManager interface in my controller like so:
#Autowired
public UserDetailsManager userDetailsManager;
When I start up the app to test it out, I get the following exception:
Error creating bean with name 'changePasswordController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.security.provisioning.UserDetailsManager com.ebisent.web.ChangePasswordController.userDetailsManager; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.springframework.security.provisioning.UserDetailsManager] is defined: expected single matching bean but found 2: [org.springframework.security.provisioning.JdbcUserDetailsManager#0, jdbcUserService]
I searched through my project to see if I might have set up (Jdbc)UserDetailsManager elsewhere, but I don't appear to have done so. If I remove the "id" attribute in the bean definition, then the ambiguity is between JdbcUserDetailsManager#0 and JdbcUserDetailsManager#1.
My web.xml references app-config.xml in two places:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/app-config.xml</param-value>
</context-param>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/app-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
There was definitely a problem with specifying app-config.xml twice, but that's not the answer to the problem originally stated.
It appears that Spring autowires based on type. The bean is defined with the class JdbcUserDetailsManager, which implements UserDetailsManager.
In my controller, I am autowiring the interface UserDetailsManager. Spring finds the interface twice, and complains that it doesn't know which to pick.
Adding the #Qualifier annotation fixes the problem. Here's how it looks now:
#Autowired
#Qualifier("jdbcUserService") // <-- this references the bean id
public UserDetailsManager userDetailsManager;
Robert,
Yes. What your web.xml says is to create a web app context of app-config.xml pointing to a parent of app-config.xml. That means you have two copies of each bean - which as you've noticed is incorrect.
this seems to do the trick:
Comment the "jdbcUserService"
Insert:
<authentication-manager alias="authenticationManager">
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"/>
</authentication-provider>
</authentication-manager>
Create a datasource:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/secureApp"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
Create the nessecary config depending on witch datasource you are using (MySQL in this case). Create any additional config if you are using hibernate or jpa ...
Run the server.
I was able to reproduce this today. The database got updated with the changed password. It seems that the authentication-manager already instantiates a JdbcUserDetailsManager ??

Categories

Resources