Explain how the #service in Spring work - spring-boot

I following my teacher but i have some confused. This is a interface extends CrudRepository from Spring data
import org.springframework.data.repository.CrudRepository;
public interface TaskRepository extends CrudRepository<Task,Integer>{
}
and this is class Service use that interface:
#Service
#Transactional
public class TaskService {
private final TaskRepository taskRepository;
public TaskService(TaskRepository taskRepository) {
this.taskRepository = taskRepository;
}
public List<Task> findAll(){
List<Task> tasks = new ArrayList<>();
for(Task task : taskRepository.findAll()) {
tasks.add(task);
}
return tasks;
}
}
I confused that when an Controller want to use instance of TaskService. It just declare like this:
#Autowired
private TaskService taskService;
Who can explain me how it work? The init of TaskService have TaskRepository as argument. but I don't find any where init TaskRepository

Once you mark your class with #Component or any variation of it such as #Service/#Repository/#Controller, you delegate it's object management to spring.
By doing
#Autowired
private TaskService taskService;
you are telling spring that, while creating an object of the controller, first create the object of TaskService and assign it to taskService variable declared in the controller.
Then spring will try to create object of TaskService but while creating, it sees the constructor
public TaskService(TaskRepository taskRepository) {
this.taskRepository = taskRepository;
}
So, it will now try to create object of TaskRepository because without that, TaskService object can't be created.
Now, TaskRepository is an interface that extends CrudRepository and interfaces cannot be instantiated. Spring creates a proxy that implements TaskRepository, creates the object and injects it into taskRepository of the TaskService constructor.
So far, spring has built the TaskRepository, TaskService objects. It will simply inject TaskService object into autowired taskService variable of the controller.

Spring boot will automatically initialize JPA Repositoriy interfaces if found.
By default, Spring Boot will enable JPA repository support and look in the package (and its subpackages) where #SpringBootApplication is located. If your configuration has JPA repository interface definitions located in a package not visible, you can point out alternate packages using #EnableJpaRepositories and its type-safe basePackageClasses=MyRepository.class parameter.
https://spring.io/guides/gs/accessing-data-jpa/
In addition since Spring Framework 4.3 if there is a single constructor it will be attempted for autowiring.
https://spring.io/blog/2016/03/04/core-container-refinements-in-spring-framework-4-3

For your example you can omit the #Autowired for your constructor, because your Service has only one constructor.
JPA Repositoriy interfaces, TaskRepository will be automatically initialized by spring boot.

Related

Autowiring of Service and Service Implementation class

Following are my code
#RestController
public class EmployeeController {
#Autowired
EmployeeService empService;
public EmployeeController (EmployeeService Impl empServiceImpl) {
super();
this.empService = empServiceImpl;
}
}
#Service
public interface EmployeeService {
public List<EmployeeDTO> getAllEmployeeDetails()
}
public class EmployeeServiceImpl {
public List<EmployeeDTO> getAllEmployeeDetails(){
//methods business logic and repo call goes here
}
}
When I start my server I am getting below error.
Parameter 1 of constructor in
com.app.in.controller.EmployeeController required a bean of type
'com.app.in.service.EmployeeServiceImpl' that could not be found
My understanding might be wrong. If I annotate the EmployeeSeriveImpl class also with #Service then it working.Is that is the correct way to do it ? My question is the service interface is annotated with #Service still why its implementation is also required to annotation. Please let me know if I miss something in that ? What is the standard method to solve this issue ?
You can get your dependency injected using a constructor. And #Autowired is optional in this case.
This is your example, but with a few corrections:
#RestController
public class EmployeeController {
// private final is a good practice. no need in #Autowire
private final EmployeeService empService;
// this constructor will be used to inject your dependency
// #Autowired is optional in this case, but you can put it here
public EmployeeController (EmployeeService empServiceImpl) {
this.empService = empServiceImpl;
}
}
I assume you have an interface EmployeeService and class EmployeeServiceImpl which implements that interface and is Spring Bean.
Something like this:
#Service
public class EmployeeServiceImpl implements EmployeeService {}
Why this #Service is needed? When you put this annotation on your class, Spring knows this is a bean that Spring should manage for you (container will create an instance of it and inject it wherever it is needed).
Check Spring docs to get more details about Dependency Injection.
The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null.

How to use #Autowired annotation two or more different Component class for same service?

For example, have a class like as follows.
First XService service in class A is not null but second XService service in AmountValidator is null.I get NullPointerException I try to create bean new it works and then I get same exception when call AmountValidateService outsideRestService in XService.
How can I use XService everywhere that I use #Autowired annotation.
My main class:
#Service
class A extends AbstractA implements IA {
#Autowired
XService service; //first autowired definition. code go to check() method. service not null now.
public doSometing(){
validator.check();
service.methodA();
super.AbstractMethod();
}
}
Validator class used in class A :
class Validator<T> implements IValidator<T> {
public void check(){
rule.check(); // rule have a implements IValidator eg: amountValidator, dateValidator class
}
}
AmountValidator added to rule in class Validator.
#Component
class AmountValidator implements IValidator<T>{
#Autowired
XService service; // code comes here service is null. same service class mentioned above class A.
#Override
public void check(){
service.validateAmount(); // nullPointerException.
}
}
My main Service
#Component
class XService {
#Autowired
AmountValidateService outsideRestService;
public validateAmount(){
outsideRestService.validate(); // nullPointer when create XService with the `New` keyword
}
}
You have an error cause you are trying to create components/beans/services yourself. As i mentioned in comment when you create components yourself it - #Autowired doesn't work - thats you've got NPE
All classes annotated with #Component, #Service are considered special classes which are instantiated by Spring automatically via DI, instantiating them with new defeats the purpose of DI.
These special classes are named Spring Beans.
Every time the application starts, the framework instances all Spring Beans, and all #Autowired fields are injected by Spring automatically. But the Spring Beans must be defined somewhere in the class path. Else you will receive a NoSuchBeanDefinitionException
As an attempt to answer the question, since I don't have a stack trace nor all the Spring Bean definitions:
When you instantiate XService using new XService() your new instance will not actually initialize the field AmountValidateService outsideRestService, effectively leaving it as null.
You may set the field yourself but as I mentioned earlier, it defeats the purpose of DI
Your question is not complex, it is incomplete.

Spring bean management using #Autowired

I have a messaging call that will process my payload which starts from MyClass. In load test i see that the first payload is getting over written by the next. All my classes are spring managed by #Autowired. Obviously the bean scope is singleton and thats why this is happening. But i do not want to use new operator and want it to be spring annotation configured. Is there any way to fix this issue of losing data ?
UPDATE
My configuration looks like below :
Public class MyClass {
...
#Autowired
public MyService myService;
...
}
#Component
#Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class MyService{
#Autowired
public Aone one;
#Autowired
public Atwo two;
...
}
#Component
#Scope(value="prototype")
public class Aone {
}
I am attempting this configuration after suggestions from net. For every call i get in MyClass a new instance of MyService will be created and from there on all other instances like Aone / Atwo should have new instance, will this configuration be ok ?

How to autowire SimpleJpaRepository in a spring boot application?

I'm working on a project that uses SpringBoot 2.0.5 version, Spring Data JPA to persists and retrieve records using JPA. I autowired SimpleJpaRepository in the service layer. But while starting my application, it failed with
"NoSuchBeanDefinitionException"- No qualifying bean of type
'org.springframework.data.jpa.repository.support.SimpleJpaRepository<?, ?>'
available: expected at least 1 bean which qualifies as autowire candidate.
My controller, service and DAO are like below
Controller class:
#Controller
public class MyController{
#Autowired
private MyService<Person,PersonPK> service;
Service layer as
public interface MyService<V,K>{
methods defined
}
#Service("service")
public class MyServiceImpl<V,K> implements MyService<V,K>{
#Autowired
private SimpleJpaRepository<V,K> repository; // This dependency is failing
}
Application as :
#SpringBootApplication (exclude = {SecurityAutoConfiguration.class})
#EnableJpaRepositories
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
Is my approach incorrect? Is that not the correct way of autowiring the SimpleJpaRepository.
There is no need for me to extend SimpleJpaRepository as Spring provided JPARepository is good for me, for now.
Thanks
You still need to create a repository interface that extends JpaRepisitory, or the spring repository type of your choice.
To quote the spring data documentation:
1.2.1 Defining repository interfaces
As a first step you define a domain class-specific repository interface. The interface must extend
Repository and be typed to the domain class and an ID type. If you
want to expose CRUD methods for that domain type, extend
CrudRepository instead of Repository.
Once you do create a new repository type, you will autowire by that type rather than the SimpleJpaRepository.
One way to get an implementation of the SimpleJpaRepository is by using a Configuration class to create an instance as a bean that you will use inside your service.
#Configuration
public class PersistanceConfiguration {
#PersistenceContext
private EntityManager entityManager;
#Bean
public SimpleJpaRepository<YourEntity, Long> getYourEntitySimpleRepository() {
return new SimpleJpaRepository<>(YourEntity.class, entityManager);
}
}
And inject it to your service as you would do with a JpaRepository, for example:
#Service
public class YourEntityServiceImpl<YourEntity, Long> implements YourEntityService {
private JpaRepository<YourEntity, K> repository;
private SimpleJpaRepository<YourEntity, K> simpleRepository;
#Autowired
public YourEntityServiceImpl(YourEntityRepository repository, SimpleJpaRepository<YourEntity, Long> simpleRepository) {
this.repository = repository;
this.simpleRepository = simpleRepository;
}
}
You should create a repository interface that extending JpaRepisitory.
#Repository
public interface MyRepository extends JpaRepisitory<T, ID> {
//
}
And the you should Autowired in your service class.
#Service("service")
public class MyServiceImpl<V,K> implements MyService<V,K>{
#Autowired
private MyRepository myRepository;
}

Spring #Autowired annotaion

Spring #Autowired
I have a doubt on Spring #Autowired annotation.Please Help...
In Spring mvc ,when I tried #Autowired in this order
Controller--->Service--->Dao
ie,In Controller I autowired Service Class Object , In Service Class Autowire Dao Object.
This Injection chain works perfectly.
Similliarly In strutrs2+Spring ,I applied #Autowired Annotation in this way
Action--->Service-->Dao
This Injection chain also works fine.
If I call a funtion from outside this chain (eg:Custom Taglib class (from jsp)) to funtion in Service class Then in this Service class the Autowired dao object is null(ie,this call braks the chain).
My questions is
Is this #Autowired works in a Injection chain Only?
Beans that have #Autowired fields only have them set if they are sent through the Spring Bean Postprocessor -- that is, like you said, if you autowire them yourself. That is a big reason that constructor injection is much more preferred than field injection. Instead of doing
#Service
public class MyService {
#Autowired
private MyDao dao;
...
}
you should do
#Service
public class MyService {
private final MyDao dao;
#Autowired
public MyService(MyDao dao) {
this.dao = dao;
}
}
That way, when you're in a situation where you can't rely on a service to be post-processed (as in your case of using the jsp tag library), you can simply instantiate a new instance with a MyDao object and be on your merry way.

Resources