I am using spring dependency injection,where i can inject object dependency through some external xml file.
My question is :
Is it fine to use spring DI without using interfaces?
Because with DI,we want to achieve one thing :
If a class is being replaced by some other class having same methods but different definitions,then we don't need to make any change in code where this class is being referenced.
This is fine if i am using interface as interface can point any class which is implementing this interface but if i am directly injecting class object through DI then there is no meaning of DI because in this case if class get replaced,i have to change my code also where it is being referenced.
Please let me correct if something is wrong.
Let's say i have
Class Datasource{
String url;
String user;
String database;
}
Now i am using it without DI as
Class Abc{
Datasource datasource = new Datasource();
}
what's the problem in this and what are the benefits i can get if i use DI.
Is getting singleton object only goal of DI?
Dependency Injection isn't about interfaces or classes or enums or... It is about Inversion of Control.
Imagine the following class.
public class PersonService {
private PersonRepository repository = new PersonRepository();
}
Apparently there is nothing wrong with this. However what if PersonRepository needs other dependencies, what if it takes another complex object as construct argument. Suddenly the PersonService is burdend with the logic on how to construct an object and all of its dependencies. Whereas it only wants to use the object.
public class PersonService {
private PersonRepository repository;
public PersonService() {
InitialContext ctx = new InitialContext();
repository = ctx.lookup("java:comp/env/repositories/person");
}
}
The code above is tied to JNDI, how are you going to test it (easily) of course you can construct your own Mock JNDI service and pre configure that with a constructed or mocked repository but that is quite cumbersome.
public class PersonService {
private final PersonRepository repository;
public PersonService(PersonRepository repository) {
this.repository=repository;
}
}
The above makes basically everything possible, there is no burder on the PersonService on how to construct the PersonRepository it is just handed one, where it comes from it doesn't matter. Is it the actual class or a (class-based) proxy, is doesn't care.
Hence dependency injection, you want to hand the PersonRepository to use to the PersonService it shouldn't matter to it where it comes from, how it is constructed or if it is a proxy to an actual object. It just needs a PersonRepository.
Related
I am trying to instantiate a class passing a parameter by constructor drMessage, I am using the #RequiredArgsConstructor annotation, and some dependency injections using #Autowired as I show below, the problem is that when using the #RequiredArgsConstructor annotation it implements the default constructors internally, and I tried to build the constructors manually but the IDE tells me that the variable of those constructors has not been initialized, how could I solve it? Thanks
#RequiredArgsConstructor
#Service
public class ServiceImpl implements IService {
#Autowired
private final DtoMapper dtoMapper;
#Autowired
private final CDtoMapper cDtoMapper;
private DrMessage drMessage;
**other sentences**
}
Constructor Injection With Lombok
With Lombok, it's possible to generate a constructor for either all class's fields (with #AllArgsConstructor) or all final class's fields (with #RequiredArgsConstructor). Moreover, if you still need an empty constructor, you can append an additional #NoArgsConstructor annotation.
Let's create a third component, analogous to the previous two:
1.Example
#Component
#RequiredArgsConstructor
public class ThankingService {
private final Translator translator;
public String produce() {
return translator.translate("thank you");
}
}
The above annotation will cause Lombok to generate a constructor for us:
2.Example
#Component
public class ThankingService {
private final Translator translator;
public String thank() {
return translator.translate("thank you");
}
/* Generated by Lombok */
public ThankingService(Translator translator) {
this.translator = translator;
}
}
#Service annotated classes are Spring managed beans. You don't manually instantiate these classes. Spring does it for you.
These #Service annotated beans have default singleton scope. Which means this bean is only initialize once. So they are called stateless beans, or says they have a shared state. You do not crate a state or change the state of these kind of beans.
Note: Read this document about bean scopes.
In your ServiceImpl you only have two final state variables. Which means are the only required filed when ServiceImpl initialize, so only they will be included in #RequiredArgsConstructor.
Lombok works at compile time while Spring works at runtime.
So when you place a Lombok annotation of the constructor (#AllArgsConstructor, #RequiredArgsConstructor, etc) on your class (it can be a regular java class, spring bean, whatever), Lombok creates a constructor for you.
In this case, it will create a constructor for all final fields (see the documentation
As you see lombok doesn't take into consideration the #Autowired annotation,
Since you haven't placed #NonNull annotation on drMessage (check the documentation) it won't generate a constructor parameter for it, so your class will look like:
#RequiredArgsConstructor
#Service
public class ServiceImpl implements IService {
#Autowired
private final DtoMapper dtoMapper;
#Autowired
private final CDtoMapper cDtoMapper;
private DrMessage drMessage;
public ServiceImpl(DtoMapper dtoMapper, cDtoMapper cDtoMapper) {
this.dtoMapper = dtoMapper;
this.cDtoMapper = cDtoMapper;
}
**other sentences**
}
So if you want the lombok to generate a parameter for DrMessage make it final, or put a #NonNull annotation on it.
At this point the job of Lombok is done, in fact, you can exclude it from being available at runtime at all. Now regarding the spring part:
First of all, you say that you by yourself are trying to create the instance of ServiceImpl class, why? It's a spring bean (you've put a #Service annotation on it), so let Spring manage this class.
With this definition, placing #Autowired on the final field won't work in spring.
See this thread, so you should not place #Autowired on these fields.
Luckily Spring in its recent versions is smart enough to understand that if the class has a single constructor (in your case the one that you've generated with Lombok) spring will call it to create the instance of your class, so instead of field injection, you'll use constructor injection.
I have a postgres database which stores (as a String) the relevant class to use dependent on the information coming in from the user.
e.g. user has input Name, the database has the value NameFinder() stored against this and the code needs to create an instance of NameFinder().
I was wondering if there was a way of using reflection to instantiate this class as an #Autowired component, and then call the relevant function.
I can't seem to find a guide that uses #Autowired classes so any help would be appreciated.
For autowiring to work you need the class which uses #Autowired to be a #Component (or a child like #Service ...). https://www.baeldung.com/spring-autowire
For Spring to know what to inject, you need to define a #Bean in your Configuration
https://www.baeldung.com/spring-bean
As for the reflective instantiation in the bean:
#Bean
public Name getName(Database db) {
String nameFqn = db.getConfigTable().getNameFQN();
return (Name) Class.forName(nameFqn).getConstructor().newInstance();
}
Note this uses a no-arg public constructor. FQN means fully-qualified name, i.e. com.some.pkg.NameFinder
assuming:
package com.some.pkg;
class NameFinder implements Name {
public NameFinder(){}
}
I feel like a Spring Bean should be configurable also directly from a FQN without using reflection but I don't know how. Try reading up on a BeanFactory or something similar. Usually reflection is to be avoided.
suppose under situation,
i have spring component that access database and get some data from database
#Component
public class SomeComponent {
#Autowiried
private Datasource datasource;
...
public SomeModel getModel() {
....
return result;
}
}
and i have a Factory structure that generate instance with some parameter. and this structure is not Spring Component
public class MyFactory {
public static MyObject newObject(...) {
... // in this scope(A), many classes are used to generate MyObject;
return MyObject;
}
}
this structure wants to access database, because it have to check data from database to generate proper Object
very simple solution that i think is this.
in some service layer
#Component
public class SomeService {
#Autowired
private SomeComponent someComponent;
public MyObject getMyObject() {
return MyFactory.newObject(someComponent);
}
}
my question is is this anti pattern in Spring usage?
in this solution, Non spring context Class get Spring Components through method parameter, and use them
if for some reason it is anti pattern, please guide to me solve this situation
I suggest you adopt the KISS principle here:
public class MyFactory {
public static MyObject newObject(SomeComponent someComponent /* and other parameter if needed */) {
... // in this scope(A), many classes are used to generate MyObject;
return MyObject;
}
}
Provide your factory construction method with the required parameters, including the autowired variable which gives you the required info from the DB, and call the Factory method directly whenever you need your new object.
The class you suggested is an overcomplication since it is a de-facto wrapper on your existing factory, with hard coding of a single DB related object, which is provided to your factory. This is a rigid implementation - what if you want to use a different instance of this object with your factory?
References:
Spring DI patterns review
Understanding Spring autowired usage
Which classes should be autowired by spring (when to use dependency injection)
I'm using 2 common packages, Immutables and
Guice. The very first thing that happens at runtime is I load setting from environment and other sources into settings into a singleton, non-Immutable config class, let's call it MyConfig, that for example, exposes a public getSettingX() method.
MyConfig myConfig = MyConfig.intialize().create();
String settingX = myConfig.getSettingX();
I have one abstract Immutable class, call it AbstractImmutable. that at instantiation needs to set a field based on the myConfig.getSettingX().
#Value.Immutable
abstract class AbstractImmutable {
abstract String getSettingX(); // Ideally set
}
Now, typically I inject MyConfig into classes using Guice, and would liket to figure a way to do this for implementations of the AbstractImmutable class (to avoid manually having to inject the MyConfig class every time I build an object--whole reason using juice to begin with, to manage my DI). However, since the concrete Immutables classes are generated at compile, it doesn't to work with the usual Guice injection annotations.
There's indication on the Immutables site of using the builder package to annotate a static factory method, but I can't seem to figure how to add this to the abstract immutable class.
Anyone have any suggestions?
To my knowledge, there is no way to do this on the generated Immutables class itself (though there may be some funny stuff you could do with #InjectAnnotation), so you may be out of luck there.
Even though you are asking under the guise of Guice, what you are asking for reminds me of the pattern that AutoFactory uses, and should be similarly applicable. In essence, take advantage of the Factory Pattern by injecting into the factory and then the factory will create the Immutable object.
For example, specifically referring to your case,
#Value.Immutable
abstract class ValueObject {
MyConfig getMyConfig();
#Value.Derived
String getSettingX() {
getMyConfig().getSettingX();
}
String getAnotherProperty();
class ValueObjectFactory {
#Inject MyConfig myConfig;
ValueObject create(String anotherProperty) {
return ImmutableValueObject.builder()
.setMyConfig(this.myConfig)
.setAnotherProperty(anotherProperty)
.build();
}
}
}
Then, in the application code, you would inject the ValueObjectFactory directly and call create on it as
class SomeApplicationClass {
#Inject ValueObjectFactory factory;
void someMethod() {
ValueObject = factory.create("myString");
// ... do something with the ValueObject
}
}
Similarly, you could define your factory as a builder, but that will be a decision you will have to make based on the number of parameters you have.
My data model consists of three objects, let's call them A, B and C. A has a one-to-many relationship to B, and B to C. They are only modeled as interfaces.
To get concrete versions of them, I have interfaces AProvider, BProvider and CProvider which provide create, retrieve, and delete operations.
I am now doing an implementation using Spring-JPA and Hibernate by the means of spring-boot-starter-data-jpa. For this, I have three #Entitys InternalA, InternalB and InternalC which do not implement the A, B and C interfaces, but are used as transfer objects only. To access them, I use the autogenerated repositories from Spring (see CrudRepository).
For creating the "real" objects, I have implementations of the XProvider interfaces which inject their necessary dependencies. This structure is the following (I prefer javax.inject style injection):
#Component
public class AProviderImpl implements AProvider {
#Inject
private InternalARepository _aRepository;
// implementation
}
#Component
public class BProviderImpl implements BProvider {
#Inject
private InternalBRepository _bRepository;
#Inject
private AProvider _aProvider;
// implementation
}
#Component
public class CProviderImpl implements CProvider {
#Inject
private InternalCRepository _cRepository;
#Inject
private BProvider _bProvider;
// implementation
}
I figure out that this should work, and the AutowireCapableBeanFactory correctly figures out what to instantiate first. But this only works up to the BProviderImpl, e.g., when removing the CProviderImpl. As soon as CProviderImpl exists, initialization fails with No qualifying bean of type [com.somewhere.BProvider] found.
It makes no difference if I use #Autowired instead of #Inject.
I stepped through the initialization process with a debugger and the CProvider is indeed initialized first, i.e., the bean factory does not correctly figure out that it needs the BProvider which in turn needs the AProvider first.
My current workaround is using #DependsOn like this:
#Component("myAProvider")
public class AProviderImpl implements AProvider { ... }
#Component("myBProvider")
#DependsOn("myAProvider")
public class BProviderImpl implements BProvider { ... }
#Component("myCProvider")
#DependsOn("myBProvider")
public class CProviderImpl implements CProvider { ... }
This works, but I read elsewhere that this is a code smell and should be avoided because it introduces implicit dependencies. Currently, this is all local to one module, so it is no problem there, but later my model will grow and I will have model elements and providers spread over multiple modules, so I cannot use #DependsOn until kingdom come.
Is there a better way to tackle this?
You can use the #Order annotation, this will enable to prioritize Bean loading and doesn't pollute your loading hierarchy as with #DependsOn. With this you can certainly modularize your design later without a problem. Lowest order value has highest priority.
#Component("myAProvider")
#Order(1)
public class AProviderImpl implements AProvider { ... }
#Component("myBProvider")
#Order(2)
public class BProviderImpl implements BProvider { ... }
#Component("myCProvider")
#Order(3)
public class CProviderImpl implements CProvider { ... }
I found another workaround: Lazy initialization. Since initialization of my XProviders are not long-running, I just added the #Lazy annotation. That way, Spring creates uninitialized instances and adds them to the registry, and when at a later point an injected dependency is accessed, it is initialized.
I don't know if this is the best solution, but I think it is better than using #DependsOn and it should be working over module boundaries.