How does autowiring work in Spring?
@Autowired
is an annotation introduced in Spring 2.5, and it's used only for injection.
For example:
class A {
private int id;
// With setter and getter method
}
class B {
private String name;
@Autowired // Here we are injecting instance of Class A into class B so that you can use 'a' for accessing A's instance variables and methods.
A a;
// With setter and getter method
public void showDetail() {
System.out.println("Value of id form A class" + a.getId(););
}
}
First, and most important - all Spring beans are managed - they "live" inside a container, called "application context".
Second, each application has an entry point to that context. Web applications have a Servlet, JSF uses a el-resolver, etc. Also, there is a place where the application context is bootstrapped and all beans - autowired. In web applications this can be a startup listener.
Autowiring happens by placing an instance of one bean into the desired field in an instance of another bean. Both classes should be beans, i.e. they should be defined to live in the application context.
What is "living" in the application context? This means that the context instantiates the objects, not you. I.e. - you never make new UserServiceImpl()
- the container finds each injection point and sets an instance there.
In your controllers, you just have the following:
@Controller // Defines that this class is a spring bean
@RequestMapping("/users")
public class SomeController {
// Tells the application context to inject an instance of UserService here
@Autowired
private UserService userService;
@RequestMapping("/login")
public void login(@RequestParam("username") String username,
@RequestParam("password") String password) {
// The UserServiceImpl is already injected and you can use it
userService.login(username, password);
}
}
A few notes:
- In your
applicationContext.xml
you should enable the<context:component-scan>
so that classes are scanned for the@Controller
,@Service
, etc. annotations. - The entry point for a Spring-MVC application is the DispatcherServlet, but it is hidden from you, and hence the direct interaction and bootstrapping of the application context happens behind the scene.
UserServiceImpl
should also be defined as bean - either using<bean id=".." class="..">
or using the@Service
annotation. Since it will be the only implementor ofUserService
, it will be injected.- Apart from the
@Autowired
annotation, Spring can use XML-configurable autowiring. In that case all fields that have a name or type that matches with an existing bean automatically get a bean injected. In fact, that was the initial idea of autowiring - to have fields injected with dependencies without any configuration. Other annotations like@Inject
,@Resource
can also be used.
Depends on whether you want the annotations route or the bean XML definition route.
Say you had the beans defined in your applicationContext.xml
:
<beans ...>
<bean id="userService" class="com.foo.UserServiceImpl"/>
<bean id="fooController" class="com.foo.FooController"/>
</beans>
The autowiring happens when the application starts up. So, in fooController
, which for arguments sake wants to use the UserServiceImpl
class, you'd annotate it as follows:
public class FooController {
// You could also annotate the setUserService method instead of this
@Autowired
private UserService userService;
// rest of class goes here
}
When it sees @Autowired
, Spring will look for a class that matches the property in the applicationContext
, and inject it automatically. If you have more than one UserService
bean, then you'll have to qualify which one it should use.
If you do the following:
UserService service = new UserServiceImpl();
It will not pick up the @Autowired
unless you set it yourself.