How is dependency injection helpful when we have multiple implementing classes? - java

I have been using dependency injection using #Autowired in Spring boot. From all the articles that I have read about dependency injection, they mention that dependency injection is very useful when we (if) decide to change the implementing class in the future.
For example, let us deal with a Car class and a Wheel interface. The Car class requires an implementation of the Wheel interface for it to work. So, we go ahead and use dependency injection in this scenario
// Wheel interface
public interface Wheel{
public int wheelCount();
public void wheelName();
...
}
// Wheel interface implementation
public class MRF impements Wheel{
#Override
public int wheelCount(){
......
}...
}
// Car class
public class Car {
#Autowired
Wheel wheel;
}
Now in the above scenario, ApplicationContext will figure out that there is an implementation of the Wheel interface and thus bind it to the Car class. In the future, if we change the implementation to say, XYZWheel implementing class and remove the MRF implementation, then the same should work.
However, if we decide to keep both the implementations of Wheel interface in our application, then we will need to specifically mention the dependency we are interested in while Autowiring it. So, the changes would be as follows -
// Wheel interface
public interface Wheel{
public int wheelCount();
public void wheelName();
...
}
#Qualifier("MRF")
// Wheel interface implementation
public class MRF impements Wheel{
#Override
public int wheelCount(){
......
}...
}
// Wheel interface implementation
#Qualifier("XYZWheel")
public class XYZWheel impements Wheel{
#Override
public int wheelCount(){
......
}...
}
// Car class
public class Car {
#Autowired
#Qualifier("XYZWheel")
Wheel wheel;
}
So, now I have to manually define the specific implementation that I want to Autowire. So, how does dependency injection help here ? I can very well use the new operator to actually instantiate the implementing class that I need instead of relying on Spring to autowire it for me.
So my question is, what are the benefit of autowiring/dependency injection when I have multiple implementing classes and thus I need to manually specify the type I am interested in ?

You don't have to necessarily hard-wire an implementation if you selectively use the qualifier for #Primary and #Conditional for setting up your beans.
A real-world example for this applies to implementation of authentication. For our application, we have a real auth service that integrates to another system, and a mocked one for when we want to do local testing without depending on that system.
This is the base user details service for auth. We do not specify any qualifiers for it, even though there are potentially two #Service targets for it, Mock and Real.
#Autowired
BaseUserDetailsService userDetailsService;
This base service is abstract and has all the implementations of methods that are shared between mock and real auth, and two methods related specifically to mock that throw exceptions by default, so our Real auth service can't accidentally be used to mock.
public abstract class BaseUserDetailsService implements UserDetailsService {
public void mockUser(AuthorizedUserPrincipal authorizedUserPrincipal) {
throw new AuthException("Default service cannot mock users!");
}
public UserDetails getMockedUser() {
throw new AuthException("Default service cannot fetch mock users!");
}
//... other methods related to user details
}
From there, we have the real auth service extending this base class, and being #Primary.
#Service
#Primary
#ConditionalOnProperty(
value="app.mockAuthenticationEnabled",
havingValue = "false",
matchIfMissing = true)
public class RealUserDetailsService extends BaseUserDetailsService {
}
This class may seem sparse, because it is. The base service this implements was originally the only authentication service at one point, and we extended it to support mock auth, and have an extended class become the "real" auth. Real auth is the primary auth and is always enabled unless mock auth is enabled.
We also have the mocked auth service, which has a few overrides to actually mock, and a warning:
#Slf4j
#Service
#ConditionalOnProperty(value = "app.mockAuthenticationEnabled")
public class MockUserDetailsService extends BaseUserDetailsService {
private User mockedUser;
#PostConstruct
public void sendMessage() {
log.warn("!!! Mock user authentication is enabled !!!");
}
#Override
public void mockUser(AuthorizedUserPrincipal authorizedUserPrincipal) {
log.warn("Mocked user is being created: " + authorizedUserPrincipal.toString());
user = authorizedUserPrincipal;
}
#Override
public UserDetails getMockedUser() {
log.warn("Mocked user is being fetched from the system! ");
return mockedUser;
}
}
We use these methods in an endpoint dedicated to mocking, which is also conditional:
#RestController
#RequestMapping("/api/mockUser")
#ConditionalOnProperty(value = "app.mockAuthenticationEnabled")
public class MockAuthController {
//...
}
In our application settings, we can toggle mock auth with a simple property.
app:
mockAuthenticationEnabled: true
With the conditional properties, we should never have more than one auth service ready, but even if we do, we don't have any conflicts.
Something went horribly wrong: no Real, no Mock - Application fails to start, no bean.
mockAuthEnabled = true: no Real, Mock - Application uses Mock.
mockAuthEnabled = false: Real, no Mock - Application uses Real.
Something went horribly wrong: Real AND Mock both - Application uses Real bean.

The best way (I think) to understand Dependency Injection (DI) is like this :
DI is a mecanism that allows you to dynamically replace your
#autowired interface by your implementation at run time. This is the
role of your DI framework (Spring, Guice etc...) to perform this
action.
In your Car example, you create an instance of your Wheel as an interface, but during the execution, Spring creates an instance of your implementation such as MRF or XYZWheel.
To answer your question:
I think it depends on the logic you want to implement. This is not the
role of your DI framework to choose which kind of Wheel you want for
your Car. Somehow you will have to define the interfaces you want to
inject as dependencies.
Please any other answer will be useful, because DI is sometimes source of confusion. Thanks in advance.

Related

Is passing a service as a parameter bad practice?

Suppose I want to use a service in a POJO class, like an implementation of some sort, can I just pass this service as a parameter to this POJO? Or would that be bad practice?
#Service
public class MyService {
// Inject AnotherService in this service
public MyService(AnotherService anotherService) {
// Now pass that service in a POJO
SomeImplementation impl = new SomeImplementation(anotherService);
}
}
public class SomeImplementation {
public SomeImplementation(AnotherService anotherService) {
// start using the AnotherService here...
}
}
For this example I used Java and Spring, but this question applies to all languages with dependency injection.
I would say that it's just not making use of the framework you're operating within. That's exactly what DI is for: letting the container handle the components and their relations (eg. if you inject sth multiple times, DI helps you avoid multiple instantiations).
Now, in your case, you can use the #Configurable annotation, which adds a POJO component to the Spring context, and so lets you inject stuff into it.

SPRINGBOOT - Auto resolve which dependency to inject Globally

I usually like to do(I do this in JS/TS) the injection based on a Interface,and "register a token" pointing to a default Implementation.So If I someday need to create a new Implementation I don't need to change the whole code, I only need to change that Token to another implementation.
I was trying to do the same in Spring. However I'm still learning about its IOC and DI, and I could not find something like this.
So my question is, in my controller when I'm injecting the Interface, I need to use a "#Qualifier", or specify which one is a "#Primary" in my implementation so the #Autowired can Inject the correct implementation. The strategy with #Qualifier() is good because it allows me to specify it by name, but I still would need to change in the Whole project if someday the implementation needs to be changed.
But I was wondering if there's some way to globally define a configuration pointing to a default injection point to a single implementation?
Thanks in advance. Sorry if my explanation is not clear,please let me know
Controller Method
#Autowired
private IOrdinaryService iOrdinaryService;
#GetMapping("/")
void getMethodHangler() {
iCreateProjectService.execute(newEmployee);
}
Interface
package com.example.demo.modules.projects.services;
import com.example.demo.modules.projects.entities.Projects;
public interface IOrdinaryService{
void execute();
}
Implementation 1
#Service
public class OldWayOrdinaryService implements IOrdinaryService {
#Override
public void execute() {
System.out.println("foo");
}
}
Implementation 2
#Service
public class NewWayOrdinaryService implements IOrdinaryService {
#Override
public void execute() {
System.out.println("bar");
}
}
You can achieve this with configuration classes of Spring framework:
#Configuration
public class InjectionConfiguration {
#Bean
public IOrdinaryService ordinaryService() {
return new OldWayOrdinaryService();
}
}
This way, you don't need to use #Service annotation on the implementations, so remove it, and you will get the instance you need in your controller class with #Autowired.
When you want to change the implementation of a IOrdinaryService, you just change the above configuration method.
You can externalize implementation class name as a system property that you can use in configuration method to inject or autowire.

DI & Autowiring vs instantiation in Spring [duplicate]

I've started to use Spring recently. And I'm making spring mvc project. So my question is if it's preferred to make interfaces and autowire it with particular implementation by spring or just use class instances in case when I have only one implementation of that interface?
For example:
#Controller
public class MyController {
#Autowired
MyService myService;
#RequestMap("/")
public String mainPage() {
...
}
}
or
#Controller
public class MyController {
#RequestMap("/")
public String mainPage() {
MyService myService = new MyServiceImpl();
...
}
}
if there is only one implementation of MyService interface?
In most cases you should go with injection because:
It eases unit testing (you can inject mock or different implementation)
Spring can inject some dependencies into MyServiceImpl as well because it manages this object
You are not coupling your controller with particular implementation
Even if your service does not have an interface, because of the second reason you should consider injection.
The only case when you might want to skip Spring is when the class does not have any dependencies and is stateless. But most likely such a class is a utility that does not need any an instance at all because it has only static members.
It will depend on whether MyService is a bean that holds a state or not. If MyService does not hold state, then you don't need to create new instances and you can let Spring to inject it having the advantages above described

Can Spring add a bean to context based on class (name) and inject it?

I have a Spring application consisting of multiple modules. One of these modules requires certain Spring beans to be present in the context (it cannot run standalone as it does not have a complete context itself).
This module provides basic functionality that needs to be shared amongst many applications that customize this module by making the correct beans available (singleton or request scoped, depending on needs).
This works perfectly and we're very happy with this setup as it provides a seperation between core functionality and business specific logic.
My question is now, I have a class that can optionally be used to satisfy one of the depedencies. It is not annotated with #Component to prevent it being scanned, however I would like the projects to be able to choose to use this class or supply their own implementation.
The core module looks like this:
public interface AProvider;
#Component
public class AService {
#Inject private AProvider aProvider;
}
And it provides this implementation that can optionally be used:
public class DatabaseBasedAProvider implements AProvider {
#Inject private SomeOtherDependency dependency; // <-- this needs to be injected still if used!
}
An example project that uses the core module then must make sure that one bean of type AProvider is present on the context. This can be achieved like:
#Configuration
public class Configuration {
#Bean
AProvider getAProvider() {
return new OurOwnAProviderImplementation();
}
}
What I would like though is something like:
#BeanClass // <-- some annotation I made up
Class<AProvider> getAProviderClass() {
return DatabaseBasedAProvider.class; // <-- have spring inject this!
}
What I don't want is:
#Bean
AProvider getAProvider() {
return new DatabaseBasedAProvider( ... add dependencies here myself ... );
}
I have solved a case similar to yours (if I understand correctly), using the #Primary annotation. Might be something for you.
public interface AProvider { }
For every module to have some implementation of the interface, create a default implementation that is shared.
#Service
public class DefaultAProvider implements AProvider {}
Then, if some module wishes to use its own implementation, "override" the bean using #Primary.
#Primary
#Service
public class MyVerySpecialAProvider implements AProvider {}
Then, anytime you inject AProvider, Spring will pick the #Primary implementation.
An alternative will be to use #Profile, another alternative would be to annotate your AProvider classes with #Component in combination with #ConditionalOnProperty and document the different choices to your consumers.
Example
#Component
#ConditionalOnProperty(name = "my.aprovider.choice", havingValue = "database")
public class DatabaseBasedAProvider implements AProvider {
#Inject private SomeOtherDependency dependency; // <-- this needs to be injected still if used!
}
I've found a solution that allows me to decide at the client what class I want to use for AProvider.
It is not super nice, but it does mean I don't need to make specific changes to the code in the core module (as this module is supposed to be generic).
In a #Configuration class in the client's config I'm now doing this:
#Component
static class MyDatabaseBasedAProvider extends DatabaseBasedAProvider {
// No implementation
}
This makes Spring construct the class and handle all the injections. It could be shorter and it does require the class to be non-final but it works.
The client is now alerted if the bean is missing, is free to make their own implementation and free to pick one of the existing implementations if one suits their needs, without the core module having to decide before hand how AProvider might be supplied.

Autowiring vs instantiating in Spring

I've started to use Spring recently. And I'm making spring mvc project. So my question is if it's preferred to make interfaces and autowire it with particular implementation by spring or just use class instances in case when I have only one implementation of that interface?
For example:
#Controller
public class MyController {
#Autowired
MyService myService;
#RequestMap("/")
public String mainPage() {
...
}
}
or
#Controller
public class MyController {
#RequestMap("/")
public String mainPage() {
MyService myService = new MyServiceImpl();
...
}
}
if there is only one implementation of MyService interface?
In most cases you should go with injection because:
It eases unit testing (you can inject mock or different implementation)
Spring can inject some dependencies into MyServiceImpl as well because it manages this object
You are not coupling your controller with particular implementation
Even if your service does not have an interface, because of the second reason you should consider injection.
The only case when you might want to skip Spring is when the class does not have any dependencies and is stateless. But most likely such a class is a utility that does not need any an instance at all because it has only static members.
It will depend on whether MyService is a bean that holds a state or not. If MyService does not hold state, then you don't need to create new instances and you can let Spring to inject it having the advantages above described

Categories