Using Spring annotations to autowire dependencies, I'm getting a org.springframework.beans.factory.NoUniqueBeanDefinitionException because I have a class with a private constructor and a public static get-method, both of which return instances of the class.
That class is annotated with the #Service annotation, and the static get method is annotated with #Bean.
I know that I can use the #Qualifier annotation at the injection point to disambiguate, and if I just remove the #Bean annotation, Spring uses the constructor without issue.
But I'd prefer Spring to use the static method -- maybe the method does some setup (Yes, I know that Spring beans are by default singleton -- still, maybe I have a reason to want to force all construction to go through my method, rather than directly to my constructor.)
Is there a way to tell Spring, as a general policy, to prefer public methods to non-public ones (in this case, the private constructor) when satisfying dependencies?
Or, less appealingly,
Is there a way (some annotation) to explicitly exclude the constructor in the #Service class from Spring's consideration?
Related
Let's say
I have integration tests, therefore there is an ApplicationContextIntegrationTests class that contains dummy beans (dependencies on other services) for initializing the app context for integration profile like this:
#Bean
public MyService myService(Proc proc) {
return new MyServiceImp();
}
I have an interface MyInterfaceA with 20 methods (the code is autogenerated based on the definition in api.yaml), I cannot implement it and I don't have access to the implementation. This interface (well, it is an implementation) also should be inserted in the application context. Obviously, I need to implement all interface methods in order to insert that bean and it leads to messy code with default methods implementations on 50 lines. Moreover, I need to insert 3 interfaces.
Is there a way to avoid that huge amount of code?
I have found that Lombok provides a #Delegate annotation which is used in similar situations, but it is appliable only on fields, whereas I need to deal with methods (bcs of #Bean).
Is this generated class that implements MyInterfaceA also a bean? If so, you can use #MockBean to mock its implementation in the test. This way, wherever a bean of type MyInterfaceA is used, the mock will be injected in its place, and you can have the mock do whatever you want.
I have created Spring MVC application that has 3 user types. I've created separate controllers for each of them. Now in each of them, I have to inject service classes so I have done it like this:
#Controller
#RequestMapping("teacher")
public class TeacherController {
#Autowired
private StudentService studentService;
#Autowired
private GradeService gradeService;
#Autowired
private SubjectService subjectService;
#Autowired
private StudentGroupService studentGroupService;
#Autowired
private NewsService newsService;
#GetMapping("/index")
public String indexPage(Model theModel) {
List<News> tempNewsList = newsService.getNews();
theModel.addAttribute("theNewList", tempNewsList);
return "teacher/index";
}
This code is using field injection. Which is, as I now learned, a solution that should be avoided and replaced with constructor injection. So I've Autowired a constructor with all of these fields like this:
#Autowired
public TeacherController(StudentService studentService, GradeService gradeService, SubjectService subjectService, StudentGroupService studentGroupService, NewsService newsService) {
this.studentService = studentService;
this.gradeService = gradeService;
this.subjectService = subjectService;
this.studentGroupService = studentGroupService;
this.newsService = newsService;
}
Is this a good solution, creating such verbose constructor in such simple code? And what if I had even more services in my code? Is this even acceptable or in this case should I refactor my code, e.g. delegate services to other services or create more controllers?
You answered this well yourself! Spring addresses exactly this concern in the docs here in the box titled Constructor-based or setter-based DI?:
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. Furthermore,
constructor-injected components are always returned to the client
(calling) code in a fully initialized state. As a side note, a large
number of constructor arguments is a bad code smell, implying that the
class likely has too many responsibilities and should be refactored to
better address proper separation of concerns.
That is, you should ideally refactor. Used SOLID principles and think "what is the one job of the class I'm creating?".
In conclution, according to the documentation if exist many DI you can evaluate every one and try to use set based and/or contructor based. The documentations eplain which one to use below:
Constructor-based or setter-based DI?
Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the #Required annotation on a setter method can be used to make the property be a required dependency.
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. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.
Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection.
Use the DI style that makes the most sense for a particular class. Sometimes, when dealing with third-party classes for which you do not have the source, the choice is made for you. For example, if a third-party class does not expose any setter methods, then constructor injection may be the only available form of DI.
I would really like to have even a basic understanding of how is #autowired
implemented in Spring.
Reflection should be somehow implied in its implementation, but I cannot figure out how.
Can you help ?
Autowiring through #Autowired is performed by a BeanPostProcessor implementation, specifically org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.
This BeanPostProcessor processes every bean, will scan its class (and superclasses) for any #Autowired annotations, and, depending on what is annotation (a constructor, field, or method), it will take appropriate action.
For constructors
Only one constructor (at max) of any given bean class may carry this
annotation with the 'required' parameter set to true, indicating the
constructor to autowire when used as a Spring bean. If multiple
non-required constructors carry the annotation, they will be
considered as candidates for autowiring. The constructor with the
greatest number of dependencies that can be satisfied by matching
beans in the Spring container will be chosen. If none of the
candidates can be satisfied, then a default constructor (if present)
will be used. An annotated constructor does not have to be public.
For fields
Fields are injected right after construction of a bean, before any
config methods are invoked. Such a config field does not have to be
public.
For methods
Config methods may have an arbitrary name and any number of arguments;
each of those arguments will be autowired with a matching bean in the
Spring container. Bean property setter methods are effectively just a
special case of such a general config method. Config methods do not
have to be public.
All of this is done through reflection.
Further reading:
How do I invoke a Java method when given the method name as a string?
Is it possible in Java to access private fields via reflection
According to #Autowired javadoc:
Marks a constructor, field, setter method or config method as to be autowired
by Spring's dependency injection facilities. Only one constructor (at
max) of any given bean class may carry this annotation, indicating the
constructor to autowire when used as a Spring bean. Such a constructor
does not have to be public. Fields are injected right after
construction of a bean, before any config methods are invoked. Such a
config field does not have to be public. Config methods may have an
arbitrary name and any number of arguments; each of those arguments
will be autowired with a matching bean in the Spring container.
Bean property setter methods are effectively just a special case of such a
general config method. Such config methods do not have to be public.
In the case of multiple argument methods, the 'required' parameter is
applicable for all arguments. In case of a Collection or Map
dependency type, the container will autowire all beans matching the
declared value type. In case of a Map, the keys must be declared as
type String and will be resolved to the corresponding bean names. Note
that actual injection is performed through a BeanPostProcessor which
in turn means that you cannot use #Autowired to inject references into
BeanPostProcessor or BeanFactoryPostProcessor types. Please consult
the javadoc for the AutowiredAnnotationBeanPostProcessor class (which,
by default, checks for the presence of this annotation).
My questions are:
What is meant by config methods?
And also, let's say I have a setter method with #Autowired and some arbitrary methods with #Autowired. I assume that setter method is invoked by spring automatically after the bean instantiation, while random-named #Autowired methods won't be invoked, am I right?
Also how does spring understand which #Autowired method should be invoked after the instantiation (setters), while others shouldn't? And how does this correlate with a statement from javadoc, saying that:
Bean property setter methods are effectively just a special case of
such a general config method
One final question: where I can read about it? since spring documentation doesn't have any information on that and I wasn't able to find the exact logic used by spring in its javadoc.
#Autowired annotation can be used with constructor, setter method or just any other method.
Whenever Spring finds #Autowired annotation it will try to find beans matching to method parameters and will invoke that method. If multiple methods (setter or non-setter) have #Autowired annotation, all will be invoked by Spring after bean instantiation.
A config method is a factory-like method, which in this case would get the paramaters autowired:
#Autowired
public SomeObject initSomeObject(Object1 o1, Object2 o2, ...) {
#Autowired merely ensures that Spring will (attempt to) provide the needed parameters.
Config-method in this context refers to methods that you would specify under init-method or #PostConstruct
Setter as you already know is like setXXX
So obviously there is no difficulty in finding which is which.
At the same time note that spring can not autowire based on parameter names.
I have a cglib proxied class because the impl uses both the #Repository #Transactional annotations.
I would like to use spring's reflection utils to set the field value for mocking out one of the fields.
But when reflection utils can not find the field in my class.
How can i get this to work? So then i can mock out the field (collaborator).
CGLIB extends your class and adds the transactional logic in the extended class. Have you tried to use protected fields instead of private?