Reputation: 1503
I'm using Spring and am trying to autowire (using annotations) a DAO into a Service, which is then wired into a controller. Having
@Autowired
Movie movieDao;
on its own doesn't work, as I think the new
method gets called, so that DAO isn't managed by Spring. The following does work, but it will look messy if I have to copy and paste that context configuration into each method
@Autowired
MovieDao movieDao;
@Override
public List<Movie> findAll() {
GenericXmlApplicationContext context = new GenericXmlApplicationContext();
context.load("classpath:app-context.xml");
context.refresh();
MovieDao movieDao = (MovieDao) context.getBean("movieDao", MovieDao.class);
return movieDao.findAll();
}
where this code is in my Service class. Is there a more elegant way to ensure that my DAO is initialised properly, rather than copying and pasting the first 4 lines of that method into each Service method?
[edit] The class that contains the code above is a class called MovieServiceImpl, and it essentially corresponds to the DataServicesImpl class in the architecture described on this page. (I'll add a summary/description of that architecture and what I'm trying to do soon). This is the code: http://pastebin.com/EiTC3bkj
Upvotes: 2
Views: 6272
Reputation: 2591
I think that the main problem is that you want to instantiate your service directly (with new
) and not with Spring:
MovieService movieService = new MovieServiceImpl();
When you do this, your MovieServiceImpl
instance is constructed but not initialised (the field @Autowired MovieDao
is null
).
If you want to instantiate properly your object with field injection, you need to use Spring. As explained in the documentation or in this example, you can automatically detect all your annotated beans and initialize them in your context with the component scanning.
In your case, using annotiations on (@Component
, @Service
, etc) and in (@Autowired
, @Inject
, etc) your beans, your project could look like this:
app-context.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Use component scanning to auto-discover your beans (by annotation) and initialize them -->
<context:component-scan base-package="com.se325.a01" />
<!-- No need to declare manually your beans, because beans are auto-discovered thanks to <context:component-scan/> -->
</beans>
App.java
package com.se325.a01;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.se325.a01.model.Movie;
import com.se325.a01.service.MovieService;
public class App {
public static void main(String[] args) {
// Let's create the Spring context based on your app-context.xml
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"app-context.xml"});
// Now your context is ready. All beans are initialised.
// You can retrieve and use your MovieService
MovieService movieService = context.getBean("movieService");
Movie matrixMovie = new Movie("Matrix");
movieService.create(matrixMovie);
}
}
In fact, when you are using Spring, it is really important to understand how the context is initialized. In the example above, it can be sum up as:
App#main
is called.app-context.xml
is loaded by ClassPathXmlApplicationContext
.com.se325.a01
is scanned thanks to the line <context:component-scan base-package="com.se325.a01" />
. All annotated beans (@Component
, @Service
, etc) are contructed but not yet initialised.@Autowired
annotations which mark the dependencies are also discovered thanks to the line <context:component-scan ... \>
.All this answer explains how you can use component scanning and annotations to use Spring in a main
entry point. However, if you are developing a server application, the entry point is the WEB-INF/web.xml
.
As @chrylis said, field injection is error prone. Prefer using constructor-based injection.
Upvotes: 1