Where is the #Autowired annotation supposed to go - on the property or the method? - spring

Which is more correct?
This (with the #Autowired annotation on the method)?
#Controller
public class MyController
{
private MyDao myDao;
#Autowired
public MyController(MyDao myDao)
{
this.myDao = myDao;
}
This (with the #Autowired annotation on the property)?
#Controller
public class MyController
{
#Autowired
private MyDao myDao;
public MyController(MyDao myDao)
{
this.myDao = myDao;
}
Where is the #Autowired annotation supposed to go?

According to the Javadoc for Autowired, the annotation can be used on "a constructor, field, setter method or config method". See the full documentation for more details.
I personally prefer your first option (constructor injection), because the myDao field can be marked as final:
#Controller
public class MyControllear {
private final MyDao myDao;
#Autowired
public MyController(MyDao myDao) {
this.myDao = myDao;
}
Constructor injection also allows you to test the class in a unit test without code that depends on Spring.
The second option would be better written as:
#Controller
public class MyControllear {
#Autowired
private MyDao myDao;
MyController() {
}
With field injection, Spring will create the object, then update the fields marked for injection.
One option you didn't mention was putting #Autowired on a setter method (setter injection):
#Controller
public class MyControllear {
private MyDao myDao;
MyController() {
}
#Autowired
public void setMyDao(MyDao myDao) {
this.myDao = myDao;
}
You do not have to choose one or another. You can use field injection for some dependencies and constructor injection for others for the same object.

The annotation goes with the property, because that's what's being autowired; the property to be automatically set. This tutorial has a nice example. This more advanced example shows how to use qualifiers to disambiguate the wiring.

Related

#ConfigurationProperties, #Value not Working YET Passing the Tests

I have a strange problem reading configuration, none of solutions I've seen seem to work. Here is my code:
#SpringBootApplication
#EnableConfigurationProperties
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Here is my properties class
#Component
#ConfigurationProperties(prefix = "my")
#Data
#ToString
#NoArgsConstructor
#AllArgsConstructor
public class MyProperties {
private String host;
private int port;
}
I then use MyProperties class in my class using #Autowired:
#Autowired
private MyProperties props;
However, I'm getting null for my props object.
Strangely, this is passing the tests just perfectly:
#SpringBootTest
class ApplicationTests {
#Autowired
private MyProperties props;
#Test
void test_configuration() {
Assertions.assertEquals(props.getHost(), "xx.xx.xx.xx");//pass!
Assertions.assertEquals(props.getPort(), xxxxxx);//pass!
}
}
It has totally refused to work, and so has #Value injection. What could I be missing?
EDIT
Here's complete code of how I'm using #Autowired on MyProperties (I've included #Value which is also not working)
#Slf4j
#Component //also tried #Configurable, #Service
public class MyService {
#Autowired
private MyProperties props;
#Value("localhost")
public String host;
public void post() {
log.info(host + props);// =null and null
}
}
EDIT2
However, I've noticed that on the controller, it works perfectly okay:
#Slf4j
#RestController
#Service
public class Main {
#Autowired
private MyProperties props;
#Value("localhost")
private String host;
#GetMapping("/post")
public void post() {
log.info(host + props);//=it's perfect!
new MyService().post();// calling MyService - where #Autowired or #Value is failing
}
}
The reason this isn't working is because the MyService you're using isn't a Spring bean, but an instance you created by yourself (using new MyService()).
To make this work, you should autowire MyService, in stead of creating your own instance:
#Slf4j
#RestController
public class Main {
#Autowired // Autowire MyService
private MyService myService;
#GetMapping("/post")
public void post() {
myService.post(); // Use the myService field
}
}
For more information, look at this Q&A: Why is my Spring #Autowired field null.
UPDATE:
new MyService() is not a "spring bean", thus can't be auto-wired with anything!;)
1. Lombok
Some people use Project Lombok to add getters and setters automatically. Make sure that Lombok does not generate any particular constructor for such a type, as it is used automatically by the container to instantiate the object.
With "such a type" ConfigurationProperties is referred in Externalized Configuration (one of my favorite chapters;) More Exact: 2.8.1. JavaBean properties binding, at the bottom of second "Note!" ;)
So this could be a reason (for strange behavior).

What will happen if i remove #Autowired from field/constructor injection but injecting that bean in another class

Suppose i have a class as,
#Repository
public class StudentServiceDao{
private final StudentClient client;
private final StudentValidator validator;
#Autowired <----
public StudentServiceDao(StudentClient studentClient){
client = studentClient;
validator = new StudentValidator(studentClient.getIdentifier());
}
public List<Student> getStudent(Request request){
StudentRS studentRS= client.getStudentList(request);
validator.validate(studentRS);
return StudentMapper.map(studentRS);
}
}
Now i have another class as,
#Component
public class StudentServiceDaoImpl{
#Autowired
private StudentServiceDao studentServiceDao;
public list<Student> retrieveStudent (Request request){
return studentServiceDao.getStudent(request);
}
}
Now if i remove #Autowired from StudentServiceDao what will happen and why ?
Autowiring can happen multiple ways.
For a few years now (currently 2020) all of these are valid ways to autowire dependencies:
Explicit constructor autowire annotation:
#Repository
public class StudentServiceDao {
private final StudentClient client;
private final StudentValidator validator;
#Autowired
public StudentServiceDao(StudentClient studentClient){
client = studentClient;
validator = new StudentValidator(studentClient.getIdentifier());
}
}
Implicit constructor autowire:
#Repository
public class StudentServiceDao {
private final StudentClient client;
private final StudentValidator validator;
public StudentServiceDao(StudentClient studentClient){
client = studentClient;
validator = new StudentValidator(studentClient.getIdentifier());
}
}
Explicit field autowire:
#Repository
public class StudentServiceDao {
#Autowired
private final StudentClient client;
#Autowired
private final StudentValidator validator;
}
Pick which ever one makes the most sense for you. I personally like implicit constructor. I think it makes instantiating the bean for testing easier with mocks. All types are valid.
5 or 6 years ago, before java config took over, there were other requirements like getters/setters needing to be present, xml files needing to specify all the beans, etc. But those are mostly gone and if you are working on a modern spring app you won't encounter them.
As to why, I have no idea, this is just how it is.

Spring MVC Repository Factory

Approach 1:
Below are the two service classes which are using same 2 repositories.
#org.springframework.stereotype.Service(value = "userService")
public class UserServiceImpl implements UserService {
#Autowired
private CounterRepository counterRepository;
#Autowired
private SessionRepository sessionRepository;
}
#org.springframework.stereotype.Service(value = "projectService")
public class UserServiceImpl implements UserService {
#Autowired
private CounterRepository counterRepository;
#Autowired
private SessionRepository sessionRepository;
}
So in above classes, as you see that CounterRepository & SessionRepository are using two times each in UserServiceImpl & ProjectServiceImpl services.
Is this is correct approach or I can make One Factory Class and use it to get required repo.
Approach 2:
class RepoFactory{
#Autowired
private CounterRepository counterRepository;
#Autowired
private SessionRepository sessionRepository;
public <T> T getRepo(Class<T> entityClass) {
if (entityClass == CounterRepository .class) {
return (T) appMessageRepository;
} else if (entityClass == SessionRepository.class) {
return (T) auditTrailRepository;
}
}
And I use like below
#org.springframework.stereotype.Service(value = "userService")
public class UserServiceImpl implements UserService {
#Autowired
private RepoFactory repoFactory;
public void someMethod(){
repoFactory.getRepo(CounterRepository.class);
.....
}
public void someMethod2(){
repoFactory.getRepo(SessionRepository.class);
.....
}
}
#org.springframework.stereotype.Service(value = "projectService")
public class ProjectServiceImpl implements ProjectService {
#Autowired
private RepoFactory repoFactory;
public void someMethod(){
repoFactory.getRepo(CounterRepository.class);
.....
}
public void someMethod2(){
repoFactory.getRepo(SessionRepository.class);
.....
}
}
Could you please help me out which approach is better according to performance and memory consumption.
If you don't configure it explictly, all spring beans are singleton, it will not affect memory at all! http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-scopes
The first approach is easy to go, recommended!!
The second approach is totally unnecessary, if you want to, you can always autowire applicationContext and use applicationContext.getBean(Mybean.class)
If you have to save some memory on application start, you can have a look at #Lazy, but from my point of view, it is also not necessary.

How should I wire in Spring 4.2 ApplicationEventPublisher with out using autowire using xml constructor arg?

I see there are lots of implementations, but how do I use the default implementation without using autowire and using xml config?
There are several option, you can use annotations, implement and interface or explicitly declare the dependency in xml or java config.
To get the ApplicationEventPublisher you can implement the ApplicationEventPublisherAware and implement the method, the ApplicationContext knows about this interface and will call the setter to give you the ApplicationEventPublisher.
public SomeClass implementens ApplicationEventPublisherAware {
private ApplicationEventPublisher publisher;
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher= applicationEventPublisher;
}
}
With annotation you can just put #Autowired on the field
public SomeClass implementens ApplicationEventPublisherAware {
#Autowired
private ApplicationEventPublisher publisher;
}
If it is a required dependency I would suggest using constructor injection, added benefit (IMHO) is that you can make the field final and that you cannot construct an invalid instance.
public SomeClass implementens ApplicationEventPublisherAware {
private final ApplicationEventPublisher publisher;
#Autowired
public SomeClass(ApplicationEventPublisher applicationEventPublisher) {
this.publisher= applicationEventPublisher;
}
When using Java Config you can simply create a #Bean annotated method which takes an ApplicationEventPublisher as argument.
#Configuration
public class SomeConfiguration {
#Bean
public SomeClass someClass(ApplicationEventPublisher applicationEventPublisher) {
return new SomeClass(applicationEventPublisher);
}
}
For XML you would need to autowire the constructor, you can specify this on the specific bean element.
<bean id="someId" class="SomeClass" autowire="constructor" />

Spring Inject Collection From Superclass

I have the following scenario:
class Super{
private List<String> someStringsThatWillBeDifferentForEveryInstancePerDerivedType;
}
#Component
class Derived1 extends Super{
#Autowired
private String name;
}
#Component
class Derived2 extends Super{
#Autowired
private Long configId;
}
I have a different List defined as Spring bean in xml for each derived class…call them listForDerived1 and listForDerived2. How can I wire these lists into my derived classes? I attempted constructor injection but I can't seem to find any luck injecting both the collection and the other deps.
You can use constructor injection with #Qualifier.
class Super {
private List<String> someStrings;
public Super(private List<String> someStrings) {
this.someStrings = someStrings;
}
}
#Component
class Derived1 extends Super {
#Autowired
public Derived1(#Qualifier("listForDerived1") List<String> listForDerived1, OtherBean bean) {
super(listForDerived1);
}
}
#Component
class Derived2 extends Super {
#Autowired
public Derived1(#Qualifier("listForDerived2") List<String> listForDerived1, OtherBean bean) {
super(listForDerived2);
}
}
Also see official Spring doc: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-autowired-annotation-qualifiers

Resources