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
Related
Suppose I have several components that depend on one service:
public interface MyService { ... }
// in package1
#Component
public class Package1Component1 {
#Autowired
private final MyService myService;
}
public class Package1Component2 {
#Autowired
private final MyService myService;
}
// in package 2
public class Package2Component1 {
#Autowired
private final MyService myService;
}
public class Package2Component2 {
#Autowired
private final MyService myService;
}
And I have two implementations of MyService:
#Service
public class MyServiceImpl1 implements MyService { ... }
#Service
public class MyServiceImpl2 implements MyService { ... }
And I want MyServiceImpl2 to be injected into all components in package2 and MyServiceImpl1 everywhere else
I don't want to use #Qualifier to resolve ambiguity as it will require to always specify it when you need to inject MyService and to change a lot of files when I need to switch to single implementation everywhere (MyServiceImpl2 is temporary implementation that should be used only in specific scope).
Is there any way to specify bean for scope (java package?), like in Angular I can override module providers (AuthService in this case):
#NgModule({
declarations: [LoginComponent, UserInfoComponent],
providers: [
{
provide: AuthService,
useClass: FacebookAuthService,
},
],
})
export class AuthModule {}
You can introduce your meta-annotation annotated with #Qualifier and use it.
Once you are ready to change, just change Qualifier on your meta annotation.
I think it's not really correct to co-relate Angular specificities with Spring, as they are simply two radically different infrastructures, in all aspects.
Why don't you want to use #Qualifier? for what reason? because, the problem you describe is exactly why people came up with #Qualifier implementation.
I don't want to use #Qualifier to resolve ambiguity as it will require to always specify it when you need to inject MyService and to change a lot of files when I need to switch to single implementation everywhere.
Not really. You can provide ID for your bean definition, and disregarding of what implementation you'll use later, same bean, with that same ID, will be injected wherever you'll qualify it to be injected. You will only swap the implementation class.
Also, package in Java, is not a scope for Beans. Package is facility for grouping a logically similar classes, and it can be considered as a scope, but for class and its members' accessibility/visibility, not for the beans.
Bean scopes have a different semantics, and you can read about them here.
The is another way to specify, that the bean should qualify as a candidate, if there are more than one implementations of a type you're injecting. It's #Primary; however, this #Primary will always override any other candidates, while with #Qualifier you can leverage more fine-grained control on what to inject where.
I have a question that I can't answer myself - at least not well.
Imagine following code:
#Service
public class ServiceA {
public void doService() {
System.out.println("Doing ServiceA");
}
}
#Service
public class ServiceB {
#Autowired
ServiceA serviceA;
public void doService() {
serviceA.doService();
}
}
It works, but is it considered bad practice? If you want to decouple these classes or test them, you have no way to ever manually set the dependencies.
Also, how exactly is Spring handling it? Is there created a proxy class with an added constructor for the property?
If it is a bad practice or not depends for the era in which you write this code. In the era of EJB it is a best practice, the container provide you all the feature of the lifecycle and even in Spring it is good even if some time even in Spring this is quite rigid model java config or xml is a more flexible solution.
However in the 20xx era especially in a TDD and Agile model, I can say that it is a real BAD PRACTICE. Those beans are not testable out of the Spring container and the annotation couple you at Spring even in compile time. a more best solution may be a code like below
class ServiceA {
public void doService() {
System.out.println("Doing ServiceA");
}
}
class ServiceB {
private final ServiceA serviceA;
ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void doService() {
serviceA.doService();
}
}
#Configuration
class ServiceConfig{
#Bean
public ServiceA serviceA(){
return new ServiceA();
}
#Bean
public ServiceB serviceB(ServiceA serviceA){
return new ServiceB(serviceA);
}
}
In this way ServiceA and ServiceB classes are two totally Spring free bean and especially for the business logic it is a best practice, the bean are testable because the our dependencies are explicit.
Imagine of provide a test of the ServiceB class writing the code in this way you can stub or mock the serviceA dependency and the ServiceB bean can be tested in isolation.
For the proxy story do not worry about it since that we provide a configuration class ServiceA and ServiceB are two beans like the annotated class, Spring manage a java config bean like an annotated bean. The difference is that now we can benefit of an explicit composition and we can provide a more flexible configuration scenario. we can benefit again of the magic aop of Spring because like said before an Spring bean configured in Java config is totally equivalent respect to an annotated bean.
I suggest you to use java config like the example.
I hope that it can help you
update:
to reply to:
Also, how exactly is Spring handling it? Is there created a proxy class with an added constructor for the property?
I can say: with the component-scan feature let's say #ComponentScan, spring find all the bean that are annotated with a sterotype annotation like #Component, #Service, #Repository and so on some of this annotation are useful because trigger some feature, for example #Repository if we implement a JPA repository and register a PersistanceExceptionTraslatorPostProcessor that translate the SQL native exception in an Exception of DataAccessException hierarchy, but other annotation are just a way for register a spring bean with annotation #Component, #Service are example.
Spring by relfection create the bean and inject the field annotated with #Autowired, if you use #Autowired on field by reflection set directly the field otherwise use the setter, in xml for instance the setter or the constructor are required.
In case of two constructor for you it is transparent, Spring will use the empty constructor and then will provide the #Autowired property by reflection, you can even do like below:
#Service
class ServiceA {
public void doService() {
System.out.println("Doing ServiceA");
}
}
#Service
class ServiceB {
private ServiceA serviceA;
public ServiceB() {
}
#Autowired
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void doService() {
serviceA.doService();
}
}
In this case spring recognize that it have use the annotated constructor with #Autowired in order to create the bean and provide the dependency. In any case the best practice is definitely the first snippet of code in my answer. It is explicit in the dependencies, clean and Spring Free in your business code base
If you dont like autowired (me either). You can used Constructor Dependency Injection.
You should not used depencendy for class byt for interface and spring will server correct implementation (decoupling)
public interface ServiceA {
public void doService();
}
#Service
public class ServiceAImpl implement ServiceA {
public void doService() {
System.out.println("Doing ServiceA");
}
}
#Service
public class ServiceBImpl implements ServiceB {
private final ServiceA serviceA;
public ServiceBImpl(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void doService() {
serviceA.doService();
}
}
I have the service MyStaticService which is doing some calculations using a DAO.
How can I inject the MyDao object into the class field?
I've tried to implement the setter with #Autowired but when I call doCalculations(..) the DAO is null. What am I doing wrong?
public class MyStaticService
{
private static MyDao dao;
public static int doCalculations(..){
dao.doSmth()
// omitted
}
}
First of all you cannot Autowire Spring beans inside classes that are not managed by Spring.
Hence in your example even if you DAO is a valid Spring managed bean, you cannot inject that in your MyStaticService. Of course it will always be null. Spring wouldn't be able to know what dependencies to scan and inject if your static service class is itself not a Spring Component
Spring dependency injection is meant to work only in classes managed by the Spring IOC container.
Your StaticService class makes more sense to be of a Singleton Class, hence there is no harm in declaring it as a Spring component.
#Component
public class MyStaticService
Then you can Autowire your DAO classes.
Service classes should ideally be Singletons with other singletons dependencies like your DAOs.
You need initialize your object for you to access the functions of MyDao() class like this:
dao = new MyDao();
or while you create the instance
private static MyDao dao = new MyDao();
else it will always show null
I have the following classes:
public interface Emailer {}
#Named
public class RealEmailer implements Emailer {}
#Named
public class NoOpEmailer implements Emailer {}
And my service class uses the real emailer:
public class SomeService {
#Inject
private Emailer emailer;
}
The question is, in my service test class (SomeServiceTest), how do I inject the Emailer in the service to use NoOpEmailer ? I'm using Spring for the DI framework.
If you can use Spring 3.1 you can use Profiles. This would allow you to provide two different implementations of the same bean (Emailer and NoOpEmailer). Then in your test you can use the #Profile("test") annotation to activate the test profile and your no op bean will be injected.
Have you considered the possibility of making the field package scope rather then private as this would make it a lot simpler to set this field during your unit test (assuming your test class is in the same package as your subject).
If not, it seems to do this with Spring you would use ReflectionTestUtils#setField(Object target, String name, Object value) to inject this value into your class
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