This question already has answers here:
What's the difference between #Component, #Repository & #Service annotations in Spring?
(31 answers)
Closed 4 years ago.
When to use service or component in spring?
For example, is a module responsible for sending email or common business logic a "service" or a "component"?
and what's the difference?
Is a service able to call the other services?
Is there any transaction problem? or a service should call the components only?
Someone told me that a service should never call the other services and should only call the components instead, which means Controller->Service->Component->DAO, but I found many people share the concept of Controller->Service->DAO with no component.
Is there any system design criteria about this topic in Spring?
In order to "configure" Spring so it can provide you with the instances of the classes you need, you are supposed to tell Spring what objects are involved and how they are built. To do this you can use an xml configuration file or through annotations
In case you take the annotation approach (IMHO a much better and simpler one) you can use #Component to annotate the class. This is like telling Spring: "Hey! I want you to know that you may need an instance of this class. Maybe because I request it, maybe because something I requested needs it". So annotating a class with #Component just let Spring know that it exists
There are other annotations that do the same:
#Controller (and #RestController)
#Service
#Repository
They all inform Spring that the class is involved in the DI context. But they also have semantic meaning:
#Controller = #Component belonging to Presentation Layer
#Service = #Component belonging to Service/Use Case Layer
#Repository = #Component belonging to Persistence Layer
You can find more info in this question
Should a service be able to call the other services?
I don't see any problem with that. If any of your services requires to do some actions that are already performed by other you surely want to avoid code duplication. As long as you respect the architecture layers dependency (never going up) you'll be fine.
About this you can check this article about Clean Architecture
#Component is generic for other stereotypes.
So you can replace
#Repository, #Service, #Controller with #Component and nothing will change. But for better readability you should use #Repository, #Service, #Controller
Related
How does constructor method dependency injection work if I'm not even initializing the class anywhere or passing in arguments. Does Spring take care of this somewhere for me? Would really like to know more about this, if anyone wouldn't mind sharing/teaching me. How does this work on the heap? Would there be a reference to the class being constructed and the dependency so I would have two instances of different objects or just one? I found this answer How does constructor dependency injection work?, but it doesn't really answer my question in great detail.
Example:
#Controller
#RequestMapping
public class SampleController{
private final SomeRepository someRepository;
pulbic SampleController(SomeRepository someRepository) throws Exception{
// will someRepository ever be null?
if(someRepository == null)
throw new Exception("I told you it wouldn't work!");
this.someRepository = someRepository;
}
Answering your question: yes. Spring manages all the Beans on your behalf. You can declare a Bean in multiple ways:
XML (the old way);
Using #Bean (but in this case you would actually instantiate the Bean);
Using #Component, #Service, #Repository or #Controller (the later 3 are basically specializations of the first).
In your case, you have annotated SampleController with #Controller, so now Spring knows that it will need to provide this Bean for you by managing it in the Spring IoC container. However, so that Spring can create the Bean it will also understand that it needs another Bean to be available, in your case SomeRepository. If such a Bean already exists in Spring IoC Container then Spring provides it to your SampleController constructor. For this to work, SomeRepository must also be a Spring-managed Bean, and thus defined by one of the previous three ways.
It is worth mentioning that if for example you would have multiple SomeRepository Beans in your application (imagine an interface having multiple implementations, being each one a different Bean), you would need to "tell" Spring which one you want to be used in SampleController, otherwise you would get an error. There are multiple ways to do this:
Using #Qualifier annotations;
Using #Primary on one of the implementations to mark it as the "default" in case you don't explicitly "say" which one you want.
You can check examples in https://www.baeldung.com/spring-qualifier-annotation.
This is a very high-level description, but you can find some good articles online about this or even check the reference documentation.
I've a newb to Java coming from C++ / C#.
My project is currently set up like this:
org.blah.config
HibernateConfig.java
org.blah.customer
Customer.java
CustomerController.java
CustomerService.java
HibernateConfig sets up the hibernate stuff and exposes the LocalSessionFactoryBean bean.
CustomerController is the REST entry point, it doesn't really have much logic, it sort of just wraps the CustomerService.java (or should I call it CustomerRepository?).
CustomerService.java (or CustomerRepository?) wraps the DB stuff. This is where I have:
#Autowired
private SessionFactory sessionFactory;
In my CustomerController, if I do:
private CustomerService customerService = new CustomerService();
it doesn't inject the sessionFactory.
From some samples I've found, people seem to create a CustomerService bean inside of HibernateConfig and then inject that into the constructor of the controller. Is that a good practice? Would I then rename my HibernateConfig to something more specific like CustomerHibernateConfig, etc.
Just trying to get an understanding of how/where to put the config & create the service / repo instance so it can be injected into the controller.
This is quite a hard question to answer in a few words. You are asking for a whole architecture that will depend a lot on the chosen design pattern, but considering you have controllers and services, let me put it this way. MVS is just a simplification and it's not a perfect approach. This will raise so many more questions like.
How much logic should go into a controller?
Should a model contain any logic?
Should a view contain logic?
Questions like these are very hard to answer, since these are very subjective. Still, I have been using Spring for a while and will give you my advise.
The controller's function is to validate inputs and a redirect to views when needed or to respond to clients' requests. If you got domain logic (aka business logic, business rules, and domain knowledge), the logic that makes business-critical decisions, then it shouldn't be on the controller, it should be on the services.
Now, I would say that you are missing a layer on your architecture, I would definitely add a DAO, which is a design pattern that defines a way to decouple the persistence layer of your application. Which is what you would understand as a Repository.
With that said, you only need one HibernateConfiguration and do the corresponding mappings in each model or XML file related to that model. I would advise to use annotations instead of XML files.
If you want to learn how to implement a Spring project that uses Hibernate, you can see how easy it is by following this Baeldung's tutorial. That page does have the best guides regarding the usage of Spring.
From a software design perspective, when should we use #Component instead of a traditional Java class (that needs to be explicitly instantiated by 'new')? For example, if we need to create a class that is one of the following patterns:
Adapter
Bridge
Façade
Strategy
Translator
Should the class have the #Component annotation (or any Spring derivative annotation such as #Repository/#Controller/#Service)?
Spring applies the Inversion of Control principle, which drills down to that the framework handles stuff for you, so you don't have to worry about it.
By using #Component on the class you let Spring create a bean for you.
This way Spring can, for example, inject this bean on runtime when you need it. (For example by Autowiring your constructor).
It is up to you to decide if you want to make use of this functionality for your class. A facade for example could very well be a Spring component, this way you could possibly inject an API implementation that is exposed via a facade on runtime, without the need to think about the dependency injection implementation.
I would not recommend using this annotation on a DTO or model class for example. These classes mostly consist of data and don't fit the need to be managed by Spring.
Other interesting related questions that can help you decide when to create a component:
What's the difference between #Component, #Repository & #Service annotations in Spring?
Spring: #Component versus #Bean
How would you extract something prior 2.5 version from .xml config? It bothers me because if #Autowired is removed from my arsenal I would not really know what to do.
Say I want to use some DAO implementation.
In service class I usually write:
#Autowired
someDaoInterface generalDao;
Then I typically call
generalDao.someInterfaceMethod(someParam param);
How would I extract implementation from config in Spring 2.0 to use this method?
Is it as dumb as just: new ApplicationContext(pathToXml) and then use .getBean or there is other way?
Why do I ask for taking bean out from configuration file?
Because in Spring MVC how can you perform your logic without getting beans out from the application context.
If you have #Controller handler then you need to make calls to the service classes' methods? So they should be somehow retrieved from the context and the only way so far is using #Autowired? Then I would also want to populate Service classes as I stated in previous example with DAO classes and they also need to be retrieved from the application context, so I would be able to write logic for service classes themself. How would people do it in the past?
I see the #Autowired as the only mean of taking something out, not because it is convenient to wire automatically - I am perfectly ok with XML.
You still have option to wire it explicitely via property or constructor parameter. (Anyway, autowired is not going to work if there is ambiguity in your container )
Of course, you can use application context and getBean() in your java code, but it violates DI pattern and makes all the spring stuff useless. Purpose of DI is to decouple your business loginc from implementation details - it's not business logic it's how and where it dependencies come from. Dependencies are just there.
By using ApplicationContext.getBean() you are breaking this pattern, and introduce dependency to:
spring itself
your configuration names
After you done this, you can as well drop use of DI and spring because you just voided all the advandages DI is providing to you. (BTW, #Autowired also introduces dependency to spring, and violates DI pattern, it also implies that there is only one instance available)
Also, answer is: in ideal case there shall be no reference to spring in your code at all.
No imports, no annotations - just interfaces of collaborating entities.
Can an annotated Spring MVC Controller also be annotated with #Component/#Service type of annotations and be used both as a controller and as a bean?
Edit: placing more emphasis on the software design aspect, and updating the API link to SpringV3
As mentioned in other answers, this is not an ideal approach to Spring MVC, but nevertheless the controller will already be available for autowiring in your ApplicationContext.
It's already a Bean in your ApplicationContext, so you can auto-wire it by type. There's no need to add an #Component annotation.
From the Spring API Docs: "This annotation serves as a specialization of #Component, allowing for implementation classes to be autodetected through classpath scanning."
http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/stereotype/Controller.html
The same holds true for #Service.
Although I've done it myself, I would not normally recommend this design approach.
If possible, refactor the required functionality into a separate bean, which can then be (auto-)wired into both the #Controller, and any other bean, as required.
If, as you have commented, you are 'cornered' into this decision (as I was, by previous design choices), then so be it.
HTH
It can but it shouldn't. A web controller should be an entry point, nothing else.
Any reusable logic it performs should be in a dedicated service layer, not in the controller itself
No, sounds like it's doing too much. One or the other, not both. I don't know if it's possible (I doubt it), but I'm sure it's not advisable.
I think that you should hear more about patterns like Front Controller, MVC, DAO and Multitier architecture and so on.