582

I'm a little confused as to how the inversion of control (IoC) works in Spring.

Say I have a service class called UserServiceImpl that implements UserService interface.

How would this be @Autowired?

And in my Controllers, how would I instantiate an instance of this service?

Would I just do the following?

UserService userService = new UserServiceImpl();
Mahozad
  • 18,032
  • 13
  • 118
  • 133
Blankman
  • 259,732
  • 324
  • 769
  • 1,199

11 Answers11

789

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 of UserService, 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.
Matt
  • 23,363
  • 39
  • 111
  • 152
Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • your last point, so in the implmentation of the interface, UserServiceImpl, I annotate with @Service correct? Great answer, REALLY cleared things up for me. – Blankman Jul 01 '10 at 00:37
  • is UserService userService the interface? – Blankman Jul 01 '10 at 02:36
  • 8
    yes, UserServiceImpl is annotated with Service, and UserService is the interface – Bozho Jul 01 '10 at 05:24
  • 1
    It's been more than 3 years since last post on this thread, I just jumped on it when looking for similar question. One query i have is, at context instantiation time, it will create only one bean object (Pls correct me if i am wrong). What if i am autowiring same bean twice in my code, will 2nd object be lazily insantiated? – Tarun Kumar Jan 22 '13 at 06:52
  • 21
    the default scope is singleton, so you will have only one instance of the bean, which is injected in multiple places. If you explicitly define the scope to be "prototype", then multiple instances will exist, possibly lazy (depending on configuration) – Bozho Jan 22 '13 at 11:23
  • 5
    Thanks a lot for your post, it really cleared things up for me. Regarding 'Since it will be the only implementor or UserService, it will be injected.' - what if there's multiple classes that implement Userservice? How does Spring know which implementation it should use? – Shishigami Aug 06 '13 at 08:08
  • 9
    if there's one designated as "primary", it uses it. Otherwise it throws an exception – Bozho Aug 06 '13 at 08:24
  • 1
    @Bozho, So everytime the function `login` is called, is a new `userService` being created? Does autowiring in spring relieve the coder from creating a Singleton object? – LifeAndHope May 27 '15 at 19:56
  • 3
    no, userService is created only once, it's in singleton-scope – Bozho Jun 29 '15 at 16:53
  • 1
    True, we've compiled some of there in our [Spring Autowiring](https://octoperf.com/blog/2018/02/08/spring-autowiring/) article. – Jerome L Apr 26 '18 at 14:40
70

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.

Kulasangar
  • 9,046
  • 5
  • 51
  • 82
Ben J
  • 5,811
  • 2
  • 28
  • 32
  • 3
    So what is the use of defining `bean id` in `applicationContext.xml` . We will have to define the `userService` variable with `UserService` type. So why make entry in `xml` file. – viper May 24 '16 at 10:05
  • @viper he is talking about interfacing it i believe – Madhu Nair Oct 22 '21 at 10:10
23

@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(););
    }
}
Hearen
  • 7,420
  • 4
  • 53
  • 63
mohit bansal
  • 267
  • 2
  • 3
  • 12
    This won't compile and is generally incorrect. `@Autowired` does not mean that "you can use all the function(method) and variable in `B` class from class `A`". What it does is brings an instance of `A` into instances of `B`, so you can do `a.getId()` from `B`. – Dmitry Minkovsky Jan 14 '15 at 21:42
  • @dimadima So if he does System.out.println("Value of id form A class" + a.getId());, and not as he has actually done it will be more correct. Please do reply, as this one is intuitively clear to me and as per my current level of understanding is explaining Autowiring. – John Doe May 28 '15 at 13:27
  • autowired annotation is introduced in spring 2.5 http://docs.spring.io/spring-framework/docs/2.5.x/api/org/springframework/beans/factory/annotation/Autowired.html – SpringLearner Aug 27 '15 at 08:08
  • 2
    For better understadin as I am new to this, will @autowired instantiate the Class A using the default constructor? IF not, how to values get instantiated in a bean or service if we use autowired. I guess if it calls default constructor, why use autowiring in the first place, just do A a = new A(). Please clarify? – Sameer Oct 04 '16 at 18:48
  • 1
    @Sameer By Autowiring dependencies you can save a lot of boilerplate code in your Unit Tests and also Controller, Service and Dao Classes, because the instantiation of the fields come with it automatically. No need to call the constructor. – kiltek Jul 26 '17 at 07:25
  • Class A is not a Spring bean. How are you auto-wiring it in Class B? – AbhishekB May 15 '19 at 11:17
10

How does @Autowired work internally?

Example:

class EnglishGreeting {
   private Greeting greeting;
   //setter and getter
}

class Greeting {
   private String message;
   //setter and getter
}

.xml file it will look alike if not using @Autowired:

<bean id="englishGreeting" class="com.bean.EnglishGreeting">
   <property name="greeting" ref="greeting"/>
</bean>

<bean id="greeting" class="com.bean.Greeting">
   <property name="message" value="Hello World"/>
</bean>

If you are using @Autowired then:

class EnglishGreeting {
   @Autowired //so automatically based on the name it will identify the bean and inject.
   private Greeting greeting;
   //setter and getter
}

.xml file it will look alike if not using @Autowired:

<bean id="englishGreeting" class="com.bean.EnglishGreeting"></bean>

<bean id="greeting" class="com.bean.Greeting">
   <property name="message" value="Hello World"/>
</bean>

If still have some doubt then go through below live demo

How does @Autowired work internally ?

Ihor Patsian
  • 1,288
  • 2
  • 15
  • 25
6

You just need to annotate your service class UserServiceImpl with annotation:

@Service("userService")

Spring container will take care of the life cycle of this class as it register as service.

Then in your controller you can auto wire (instantiate) it and use its functionality:

@Autowired
UserService userService;
Ihor Patsian
  • 1,288
  • 2
  • 15
  • 25
Jitender Chahar
  • 204
  • 2
  • 6
4

Spring dependency inject help you to remove coupling from your classes. Instead of creating object like this:

UserService userService = new UserServiceImpl();

You will be using this after introducing DI:

@Autowired
private UserService userService;

For achieving this you need to create a bean of your service in your ServiceConfiguration file. After that you need to import that ServiceConfiguration class to your WebApplicationConfiguration class so that you can autowire that bean into your Controller like this:

public class AccController {

    @Autowired
    private UserService userService;
} 

You can find a java configuration based POC here example.

Ihor Patsian
  • 1,288
  • 2
  • 15
  • 25
AbdusSalam
  • 485
  • 5
  • 13
3

There are 3 ways you can create an instance using @Autowired.

1. @Autowired on Properties

The annotation can be used directly on properties, therefore eliminating the need for getters and setters:

    @Component("userService")
    public class UserService {

        public String getName() {
            return "service name";
        }
    }

    @Component
    public class UserController {

        @Autowired
        UserService userService

    }

In the above example, Spring looks for and injects userService when UserController is created.

2. @Autowired on Setters

The @Autowired annotation can be used on setter methods. In the below example, when the annotation is used on the setter method, the setter method is called with the instance of userService when UserController is created:

public class UserController {

    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
            this.userService = userService;
    }
}

3. @Autowired on Constructors

The @Autowired annotation can also be used on constructors. In the below example, when the annotation is used on a constructor, an instance of userService is injected as an argument to the constructor when UserController is created:

public class UserController {

    private UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService= userService;
    }
}
timwaagh
  • 303
  • 3
  • 14
Mak
  • 1,068
  • 8
  • 19
1

In simple words Autowiring, wiring links automatically, now comes the question who does this and which kind of wiring. Answer is: Container does this and Secondary type of wiring is supported, primitives need to be done manually.

Question: How container know what type of wiring ?

Answer: We define it as byType,byName,constructor.

Question: Is there are way we do not define type of autowiring ?

Answer: Yes, it's there by doing one annotation, @Autowired.

Question: But how system know, I need to pick this type of secondary data ?

Answer: You will provide that data in you spring.xml file or by using sterotype annotations to your class so that container can themselves create the objects for you.

Pratik Gaurav
  • 661
  • 7
  • 8
1

Standard way:

@RestController
public class Main {
    UserService userService;

    public Main(){
        userService = new UserServiceImpl();
    }

    @GetMapping("/")
    public String index(){
        return userService.print("Example test");
    }
}

User service interface:

public interface UserService {
    String print(String text);
}

UserServiceImpl class:

public class UserServiceImpl implements UserService {
    @Override
    public String print(String text) {
        return text + " UserServiceImpl";
    }
}

Output: Example test UserServiceImpl

That is a great example of tight coupled classes, bad design example and there will be problem with testing (PowerMockito is also bad).

Now let's take a look at SpringBoot dependency injection, nice example of loose coupling:

Interface remains the same,

Main class:

@RestController
public class Main {
    UserService userService;

    @Autowired
    public Main(UserService userService){
        this.userService = userService;
    }

    @GetMapping("/")
    public String index(){
        return userService.print("Example test");
    }
}

ServiceUserImpl class:

@Component
public class UserServiceImpl implements UserService {
    @Override
    public String print(String text) {
        return text + " UserServiceImpl";
    }
}

Output: Example test UserServiceImpl

and now it's easy to write test:

@RunWith(MockitoJUnitRunner.class)
public class MainTest {
    @Mock
    UserService userService;

    @Test
    public void indexTest() {
        when(userService.print("Example test")).thenReturn("Example test UserServiceImpl");

        String result = new Main(userService).index();

        assertEquals(result, "Example test UserServiceImpl");
    }
}

I showed @Autowired annotation on constructor but it can also be used on setter or field.

Michu93
  • 5,058
  • 7
  • 47
  • 80
0

The whole concept of inversion of control means you are free from a chore to instantiate objects manually and provide all necessary dependencies. When you annotate class with appropriate annotation (e.g. @Service) Spring will automatically instantiate object for you. If you are not familiar with annotations you can also use XML file instead. However, it's not a bad idea to instantiate classes manually (with the new keyword) in unit tests when you don't want to load the whole spring context.

k13i
  • 4,011
  • 3
  • 35
  • 63
0

Keep in mind that you must enable the @Autowired annotation by adding element <context:annotation-config/> into the spring configuration file. This will register the AutowiredAnnotationBeanPostProcessor which takes care the processing of annotation.

And then you can autowire your service by using the field injection method.

public class YourController{

 @Autowired
 private UserService userService; 

}

I found this from the post Spring @autowired annotation

Ihor Patsian
  • 1,288
  • 2
  • 15
  • 25
David Pham
  • 1,673
  • 19
  • 17