-2

In the official website of Spring framework, there's an example which shows how Spring decouple a class from an interface, or better to say, an implementation if an interface.

Here's the code:

Interface:

package hello;

public interface MessageService {
    String getMessage();
}

Component Class:

package hello;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MessagePrinter {

    final private MessageService service;

    @Autowired
    public MessagePrinter(MessageService service) {
        this.service = service;
    }

    public void printMessage() {
        System.out.println(this.service.getMessage());
    }
}

Application:

package hello;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;

@Configuration
@ComponentScan
public class Application {

    @Bean
    MessageService mockMessageService() {
        return new MessageService() {
            public String getMessage() {
              return "Hello World!";
            }
        };
    }

  public static void main(String[] args) {
      ApplicationContext context = 
          new AnnotationConfigApplicationContext(Application.class);
      MessagePrinter printer = context.getBean(MessagePrinter.class);
      printer.printMessage();
  }
}

What I currently understand about dependency injection is that when a class named A need another class named B for processing what ever it must do, B is a dependency and A is dependent. If B is an interface, then A is dependent on some implementation of B.

So, in the above code, how MessagePrinter is decoupled from MessageService implementation ?

we still have to implement MessageService, If we don't implement it, can MessagePrinter function properly?

Regards

Debosmit Ray
  • 5,228
  • 2
  • 27
  • 43
HMD
  • 468
  • 1
  • 5
  • 21
  • I think you are looking for `@Qualifier`, see [Autowiring spring bean by name using annotation](https://stackoverflow.com/q/11831261/2970947) – Elliott Frisch Feb 11 '18 at 18:03
  • @ElliottFrisch I don't know what is `@Qualifier`. I just started studying spring and the example is in the first page of website. I can't understand how `MessagePrinter` is decoupled from implementation of `MessageService` – HMD Feb 11 '18 at 18:04
  • 1
    Click the link I provided. In your example code, **how** is `MessagePrinter` *tied* to a **specific** `MessageService`? Note the `@Autowired` annotation. That is how. – Elliott Frisch Feb 11 '18 at 18:09
  • @ElliottFrisch I'm so confused! what do you mean _tied_? you mean how `MessagePrinter` is dependent to `MessageService`?!! let me ask a question, the term _decoupling_, does it mean `MessagePrinter` doesn't need an implementation of `MessageService` anymore ? If not, then I haven't understood it yet! – HMD Feb 11 '18 at 18:12
  • It **does not** mean that. It mean it is not coupled (tied, linked, hardcoded to use) to a ***specific*** implementation; you could replace one `MessageService` with any other implementation of `MessageService`. Or a mock `MessageService` as in your example. – Elliott Frisch Feb 11 '18 at 18:14
  • No, it won't function anyway. – Roman C Feb 11 '18 at 18:20
  • @ElliottFrisch I understand. If we have several implementation of `MessagePrinter`, then we can give `MessageService` whichever we want. But we can do this without Spring either, can't we?! – HMD Feb 11 '18 at 18:44

1 Answers1

0

Yes, you must have a MessageService in your context. Without it, dependency injection caused by @Autowired annotation will fail during context initialization.

If I understand the terminology correctly, MessagePrinter cannot be decoupled from MessageService because the former uses the latter in its code directly. But it can be decoupled from MessageService implementations.

It is decoupled from MessageService implementations, because it only depends on MessageService interface; it does not know anything about implementing classes.

If you happen to have MessageServiceImpl1 and then change it to MessageServiceImpl2, MessagePrinter will not have to be changed at all (if both implementations behave the same contract-wise, of course).

Roman Puchkovskiy
  • 11,415
  • 5
  • 36
  • 72
  • Thank you. But I've read without using Spring, `MessagePrinter` **IS** dependent to some implementation of `MessageService`. Spring just makes it possible that it doesn't happen. So my question is still consistent. – HMD Feb 11 '18 at 18:50
  • By using an interface (`MessageService`), you already decouple from its implementations. A test is simple: does `MessageService` know anything about the implementations? The answer is 'no' (you don't even have them!). To achieve this, you just program with interfaces and use dependency injection. Spring is not a requirement (although it allows to use this pattern easily by constructing your application context for you). – Roman Puchkovskiy Feb 11 '18 at 19:07
  • I'm so confused. is `mockMessageService()` part of Spring or not? – HMD Feb 11 '18 at 19:47
  • Spring is a framework. In this case I believe you mean Spring IoC container which builds application context from your `@Configuration`-annotated class and injects dependencies. `mockMessageService()` is a method producing `MessageService` instance for this context; it is a part of your application and is not a part of Spring. – Roman Puchkovskiy Feb 12 '18 at 06:10