So since I've been using Spring, if I were to write a service that had dependencies I would do the following:
#Component
public class SomeService {
#Autowired private SomeOtherService someOtherService;
}
I have now run across code that uses another convention to achieve the same goal
#Component
public class SomeService {
private final SomeOtherService someOtherService;
#Autowired
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
Both of these methods will work, I understand that. But is there some advantage to using option B? To me, it creates more code in the class and unit test. (Having to write constructor and not being able to use #InjectMocks)
Is there something I'm missing? Is there anything else the autowired constructor does besides add code to the unit tests? Is this a more preferred way to do dependency injection?
Yes, option B (which is called constructor injection) is actually recommended over field injection, and has several advantages:
the dependencies are clearly identified. There is no way to forget one when testing, or instantiating the object in any other circumstance (like creating the bean instance explicitly in a config class)
the dependencies can be final, which helps with robustness and thread-safety
you don't need reflection to set the dependencies. InjectMocks is still usable, but not necessary. You can just create mocks by yourself and inject them by simply calling the constructor
See this blog post for a more detailed article, by one of the Spring contributors, Olivier Gierke.
I will explain you in simple words:
In Option(A), you are allowing anyone (in different class outside/inside the Spring container) to create an instance using default constructor (like new SomeService()), which is NOT good as you need SomeOtherService object (as a dependency) for your SomeService.
Is there anything else the autowired constructor does besides add code
to the unit tests? Is this a more preferred way to do dependency
injection?
Option(B) is preferred approach as it does NOT allow to create SomeService object without actually resolving the SomeOtherService dependency.
Please note, that since Spring 4.3 you don't even need an #Autowired on your constructor, so you can write your code in Java style rather than tying to Spring's annotations.
Your snippet would look like that:
#Component
public class SomeService {
private final SomeOtherService someOtherService;
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
Good to know
If there is only one constructor call, there is no need to include an #Autowired annotation. Then you can use something like this:
#RestController
public class NiceController {
private final DataRepository repository;
public NiceController(ChapterRepository repository) {
this.repository = repository;
}
}
... example of Spring Data Repository injection.
Actually, In my experience, The second option is better. Without the need for #Autowired. In fact, it is wiser to create code that is not too tightly coupled with the framework (as good as Spring is). You want code that tries as much as possible to adopt a deferred decision-making approach. That is as much pojo as possible, so much such that the framework can be swapped out easily.
So I would advise you create a separate Config file and define your bean there, like this:
In SomeService.java file:
public class SomeService {
private final SomeOtherService someOtherService;
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
In ServiceConfig.java file:
#Config
public class ServiceConfig {
#Bean
public SomeService someService(SomeOtherService someOtherService){
return new SomeService(someOtherService);
}
}
In fact, if you want to get deeply technical about it, there are thread safety questions (among other things) that arise with the use of Field Injection (#Autowired), depending on the size of the project obviously. Check this out to learn more on the advantages and disadvantages of Autowiring. Actually, the pivotal guys actually recommend that you use Constructor injection instead of Field Injection
I hope I won't be downgraded for expressing my opinion, but for me option A better reflects the power of Spring dependency injection, while in the option B you are coupling your class with your dependency, in fact you cannot instantiate an object without passing its dependencies from the constructor. Dependency Injection have been invented for avoid that by implementing Inversion of Control,so for me option B doesn't have any sense.
Autowired constructors provides a hook to add custom code before registering it in the spring container. Suppose SomeService class extends another class named SuperSomeService and it has some constructor which takes a name as its argument. In this case, Autowired constructor works fine. Also, if you have some other members to be initialized, you can do it in the constructor before returning the instance to spring container.
public class SuperSomeService {
private String name;
public SuperSomeService(String name) {
this.name = name;
}
}
#Component
public class SomeService extends SuperSomeService {
private final SomeOtherService someOtherService;
private Map<String, String> props = null;
#Autowired
public SomeService(SomeOtherService someOtherService){
SuperSomeService("SomeService")
this.someOtherService = someOtherService;
props = loadMap();
}
}
I prefer construction injection, just because I can mark my dependency as final which is not possible while injecting properties using property injection.
your dependencies should be final i.e not modified by program.
There are few cases when #Autowired is preferable.
One of them is circular dependency. Imagine the following scenario:
#Service
public class EmployeeService {
private final DepartmentService departmentService;
public EmployeeService(DepartmentService departmentService) {
this.departmentService = departmentService;
}
}
and
#Service
public class DepartmentService {
private final EmployeeService employeeService;
public DepartmentService(EmployeeService employeeService) {
this.employeeService = employeeService;
}
}
Then Spring Bean Factory will throw circular dependency exception. This won't happen if you use #Autowired annotation in both beans. And this is understandable: the constructor injection happens at very early stage of Spring Bean initialization, in createBeanInstance method of Bean Factory, while #Autowired-based injection happens way later, on post processing stage and is done by AutowiredAnnotationBeanPostProcessor.
Circular dependency is quite common in complex Spring Context application, and it needs not to be just two beans referring one another, it could a complex chain of several beans.
Another use case, where #Autowired is very helpful, is self-injection.
#Service
public class EmployeeService {
#Autowired
private EmployeeService self;
}
This might be needed to invoke an advised method from within the same bean. Self-injection is also discussed here and here.
There is a way to inject the dependencies through constructor using #RequeiredArgsContructor annotation from Lombok
#RequiredArgsConstructor
#Service
class A {
private final B b // needs to be declared final to be injected
}
In this way you don't need to specify a constructor
Related
But what about this:
#Service
public class DatabaseAccountService implements AccountService {
private final RiskAssessor riskAssessor;
public DatabaseAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
}
// ...
}
This example is from the documentation:
https://docs.spring.io/spring-boot/docs/2.0.x/reference/html/using-boot-spring-beans-and-dependency-injection.html
Maybe I have not understood even the question. Could you comment?
In Spring there are at least 2 different ways for dependency injection: constructor injection and field injection. (leaving setter injection aside for now)
Constructor injection is the recommended way to do dependency injection:
#Service
public class DatabaseAccountService {
private final RiskAssessor riskAssessor;
#Autowired // annotation is not required in recent Spring versions
public DatabaseAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
}
}
The referenced Spring documentation also shows an example for constructor injection, simply because it's the recommended way.
Field injection is used to inject dependencies directly into fields/properties as mentioned in the question.
#Service
public class DatabaseAccountService {
#Autowired // don't do this at home or work
private RiskAssessor riskAssessor;
public DatabaseAccountService() {
// RiskAssessor does not appear as constructor parameter
}
}
With the question in video "Can you use dependency injection against a (private) property?" they want to point exactly to field injection maybe to show the possibilities of Spring.
However, they also say that this is bad practice. The blog post Why field injection is evil explains why this is bad practice.
I'm trying to call a #Cacheable method from within the same class.
And it didn't work. Because of:
In proxy mode (the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation (in effect, a method within the target object that calls another method of the target object) does not lead to actual caching at runtime even if the invoked method is marked with #Cacheable. Consider using the aspectj mode in this case. Also, the proxy must be fully initialized to provide the expected behavior, so you should not rely on this feature in your initialization code (that is, #PostConstruct).
It means, #Cachable(also #Transactional) works by proxy classes which is Spring AOP in. a internal call in the same class make call by 'this' instead of proxy classes.
To solve the problem, I should call a method by proxy or using AspectJ(another AOP).
So, I found 4 solutions.
What is your choice? and why others are not recommended?
Please, share your opinion!
using AspectJ (another AOP)
get the Bean from ApplicationContext and use it
#Service
public class UserService implements Service {
#Autowired
private ApplicationContext applicationContext;
private Service self;
#PostConstruct
private void init() {
self = applicationContext.getBean(UserService.class);
}
}
self-autowiring using #Resource //since Spring 4.3
#Component
#CacheConfig(cacheNames = "SphereClientFactoryCache")
public class CacheableSphereClientFactoryImpl implements SphereClientFactory {
/**
* 1. Self-autowired reference to proxified bean of this class.
*/
#Resource
private SphereClientFactory self;
#Override
#Cacheable(sync = true)
public SphereClient createSphereClient(#Nonnull TenantConfig tenantConfig) {
// 2. call cached method using self-bean
return self.createSphereClient(tenantConfig.getSphereClientConfig());
}
#Override
#Cacheable(sync = true)
public SphereClient createSphereClient(#Nonnull SphereClientConfig clientConfig) {
return CtpClientConfigurationUtils.createSphereClient(clientConfig);
}
}
make the Bean scope of the class as 'prototype' instead of 'singleton'
#Service
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class AService {
private final AService _aService;
#Autowired
public AService(AService aService) {
_aService = aService;
}
#Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
..println("Cache is not being used");
...
}
public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
List<EmployeeData> employeeData = _aService.getEmployeeData(date);
...
}
}
I'm a newbie in spring :)
Actually, I choose the 4th solution, but I felt it isn't a good way. because I just need to call the caching method by proxy, and it make several beans to achieve it.
After reading articles, I think AspectJ is the best choice. It looks cool, Spring recommends it, and many people also recommend too.
But I don't understand how to AspectJ works (I will study) and I also don't know why others is not recommended.
references
Spring Cache #Cacheable - not working while calling from another method of the same bean
Spring cache #Cacheable method ignored when called from within the same class
https://spring.io/blog/2012/05/23/transactions-caching-and-aop-understanding-proxy-usage-in-spring
https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#cache
While looking at an existing Spring application, I stumbled upon a class with field injection, which we all know isn't recommended for various reasons. I have then decided to refactor it to make use of a more appropriate approach: constructor based DI.
Before refactoring
#Component
public class MaintenanceModeInterceptor implements HandlerInterceptor {
private static final String MAINTENANCE_MODE_VIEW = "common/maintenanceMode";
#Autowired
private ApplicationObject applicationObject;
public MaintenanceModeInterceptor() {
// Required by Spring
}
...
}
After refactoring
#Component
public class MaintenanceModeInterceptor implements HandlerInterceptor {
private static final String MAINTENANCE_MODE_VIEW = "common/maintenanceMode";
private ApplicationObject applicationObject;
public MaintenanceModeInterceptor() {
// Required by Spring
}
#Autowired
public MaintenanceModeInterceptor(ApplicationObject applicationObject) {
this.applicationObject = applicationObject;
}
...
}
Maybe it is related to the fact that a default constructor is present. However, if I remove it, I end up having this exception:
Caused by: java.lang.NoSuchMethodError: my.application.web.interceptor.MaintenanceModeInterceptor: method <init>()V not found
So my understanding is that Spring requires a default constructor for interceptors.
Is there any way to achieve construtor based DI in this scenario?
Thank you.
I think you should remove the non #Autowired constructor and do perform a clean build on your project.
I am currently improving my Spring knowledge. I wonder what really happens when I use Spring annotation #Autowire on a field.
Here is a piece of code :
OutputHelper file
#Component
public class OutputHelper {
#Autowired
#Qualifier("csvOutputGenerator")
private IOutputGenerator outputGenerator;
public void setOutputGenerator(IOutputGenerator outputGenerator) {
this.outputGenerator = outputGenerator;
}
// I can focus only on what my code do because my objects are injected
public void generateOutput(){
outputGenerator.generateOutput();
}
}
CsvOutputGenerator file
#Component
public class CsvOutputGenerator implements IOutputGenerator {
public void generateOutput(){
System.out.println("Csv Output Generator");
}
}
Application file
public static void main(String[] args) {
// Create the spring context
ApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring/spring-module.xml");
// Get the configured OutpuHelper from the spring-module.xml
OutputHelper output = (OutputHelper) context.getBean("outputHelper");
// Display output from the output configured
output.generateOutput();
}
My configuration file just contain <context:component-scan base-package="com.xxx.xxx.output"/>
When I execute this code all work fine. But what makes me surprised is when I delete the setOutputGenerator in OutPutHelper file, my piece of code keeps working. I tought that with this configuration, the OutputHelper was first created with default constructor and initialized with setter.
I expected an error because the variable outputGenerator was not be able to be initialized.
Is anyone can help me to understand ?
The idea to have fields #Autowired is questionable. It works, but it will difficult other aspects of your implementation (i.e. testing).
There are 3 types of injections:
fields - basically configured applying reflection (Field.set(Object, Object)) directly to the field:
#Autowired
private MyInterface field;
setters - with this approach the configuration of each dependency goes through a property (spring goes through all methods and execute each one annotated with #Autowired using Method.invoke(Object, Object...), thus its value is configured using its setter as follows:
#Autowired
public void setField(MyInterface value) {
this.field = value;
}
constructors - the last, and my preferable approach, the constructor injection. That one basically annotates an constructor with #Autowired and instead of using methods or fields, you can configure your bean directly on your constructor. For that spring will elect the a constructor to be used to instantiate your #Component, and it will use an #Autowired if existent or a empty params constructor, invoking it using Constructor.newInstance(Object...). Example:
#Component
public class Implementation {
private MyInterface field;
#Autowired
public Implementation(MyInterface value) {
Assert.notNull(value, "value should not be null");
this.field = value;
}
}
One of the ideas behind Inversion of Control (or Dependence Injection) is to be able to isolate a piece of code in order to provide decent test implementation support.
In order to go deeper, it is necessary to comment that during a unit test you want the class in its isolated form, all you will use with that class are basically mocks for its dependencies (injections).
So, what are the results:
If you do field injection, it will be quite costly to every single time set the beans using some reflection to configure the bean during your tests (another logic needs to be introduced to configure the bean to be tested).
With setter injection approach you will be able to use your own bean to configure it with mocks necessary to isolate your implementation and test its functionality.
And finally, with the constructor injection approach you will have not only the support to configure your bean, but you will be able to require its dependencies. This means that for every new dependency a new parameter on your constructor is added, this brings you come advantages on development time, for example, you will be able to see on development time the unit tests affected with the introduction of that new dependency (once your IDE will point it out for your).
Simple answer
Actually, the setter is useless, since the CDI use java Reflection to access fields.
It means that fields are no longer accessed by method calls.
Reflection allow iterating throught all fields of a class and check if there are annoted with a specific annotation.
In this case, if a field in your class is annoted With #Autowired (or #Inject wich is more J2E complient), the container will iterate throught searching if there is a registered bean that fits the current property.
Going deeper
When you context is starting, the container iterate classes and search all field annoted with #Inject or #Autowired.
For these fields, it search an available bean.
Here is the must simple example :
public class SpringClassInChargeOfDependencyInjection {
public void handdleInjections(T objectWithInjectableField) {
Class<T> clazz = objectWithInjectableField.class;
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class) || field.isAnnotationPresent(Inject.class)) {
//find a bean for the type;
Object injectableBean = getAvailablebean(field.getType());
field.setAccessible(true);
//inject the value into the class, this line explain why the setter is not necessary
field.set(objectWithInjectableField, injectableBean);
}
}
}
}
This is a non-working example just to explain how it works.
Tips
You might consider using #Inject instead of #Autowired, the later was created by Spring, #Inject is a part of the the JSR-330. Spring does understand #Inject as well, you just need to add the javax.inject jar dependency to your project. If later you want to switch from spring to something else (guice for example) you won't have to change all your #Autowired annotations
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
I am working with Spring 4.0.7, and with JUnit about testing of course.
About DI Spring offers #Autowired to be used in three locations
constructor
setter
field
I always work through the two first, why never the third option?
Because I remember have read long time ago about field injection should not be used, because it has a negative consequence about Testing. It does JUnit fails.
Note: Only for Testing is the problem. To runtime or production all goes well
Objective: For demonstration/academic purposes I want generate this problem.
I have the following:
Repository
public interface PersonRepository extends JpaRepository<Person, String>{
}
A Service
#Service
#Transactional
#Profile("failure")
public class PersonFailTestServiceImpl implements PersonService {
private static final Logger logger = ...
#Autowired
private PersonRepository personRepository;
Other Service (calling or using the service shown above)
#Service
#Transactional
#Profile("failure")
public class PersonFailTestProcessImpl implements PersonProcess {
private static final Logger logger = ...
#Autowired
private PersonService personService;
How you can see the two services are based on Field Injection.
Now the testing:
How the beans are loaded
#Configuration
#ComponentScan( basePackages={"com.manuel.jordan.server.infrastructure"},
basePackageClasses={PersonProcess.class,PersonRepository.class, PersonService.class})
public class CentralConfigurationEntryPoint {
}
#ContextConfiguration(classes=CentralConfigurationEntryPoint.class)
public class CentralTestConfigurationEntryPoint {
}
Now the two testing classes
#Transactional
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles({"development","failure"})
public class PersonServiceImplDevelopmentFailureTest extends CentralTestConfigurationEntryPoint {
#Autowired
private PersonService personService;
#Test
public void savePerson01(){
Person person01 = PersonFactory.createPerson01();
personService.save(person01);
personService.printPerson(personService.findOne("1"));
}
#Transactional
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles({"development","failure"})
public class PersonProcessImplDevelopmentFailureTest extends CentralTestConfigurationEntryPoint{
#Autowired
private PersonProcess personProcess;
Well all the testing methods pass, all green. I don't know if I am missing something or through Spring 4 the problem has been fixed
If this was your premise or problem
Because I remember have read long time ago about field injection
should not be used, because it has a negative consequence about
Testing. It does JUnit fails.
then you thought wrong. There is nothing inherently wrong with using field injection, definitely nothing that would cause JUnit tests to fail in and of itself. If a bean exists, Spring will be able to inject it whether it's in a constructor, a setter method, or a field.
Since you've activated your failure profile, your PersonFailTestServiceImpl bean will be found.
I think I can help. The example code you've posted here is a good example of a system / integration test, not a UNIT test.
If you were UNIT testing PersonFailTestProcessImpl, you would have to set the personRepository dependency yourself through code. But it is private, so how do you do this? You cannot use a constructor or setter since none is provided. This is what is meant by 'hard to unit test'.
Java 5+ provides a way to set private variables like this via reflection (the so-called privileged accessor). Basically, you obtain the class, get the declared field, call its setAccessible method, then you can set its value directly. There are libraries that will do these steps for you, but the point is that this is a pain compared to X.setSomething();
So there is nothing that 'makes jUnit fails' by using #Autowired on a private field. But building an object model without constructors or setters for establishing dependencies is unnecessarily constraining.