SPRING – @Autowired vs. @Inject vs. @Resource

Cześć.

Aktualnie na blogu powstaje ciąg artykułów związanych z wzorcami projektowymi i pewnie już macie ich dość, dlatego postanowiłem zrobić krótką przerwę. Ze względu na to, że Spring jest teraz na topie, a poza tym bardzo lubię tę technologię, pomyślałem, że napiszę parę postów, które będą się z nim wiązać.

Ostatnio ktoś zapytał mnie o różnicę między adnotacjami @Autowired oraz @Resource i wydaję mi się, że jest to dobry pomysł, aby wyjaśnić różnicę między nimi. Do porównania dorzucę jeszcze adnotację @Inject, ponieważ ma takie samo zastosowanie jak dwie powyższe.

Na początek troszkę teorii:

Trzy adnotacje, o których wspomniałem, służą oczywiście do wstrzykiwania zależności.
Znajdują się w różnych pakietach:
@Resource -> javax. annotation
@Inject -> javax.inject
@Autowired -> org.springframework.beans.factory.annotation

Jedną z głównych różnic jest to, że @Autowired oraz @Inject używają do wstrzykiwania zależności „post procesora” – AutowiredAnnotationBeanPostProcessor, a @Resource  CommonAnnotationBeanPostProcessor. Możemy się więc domyślić, że @Autowired oraz @Inject działają identycznie, a @Resource inaczej.

Najistotniejszą różnicą w działaniu @Autowired(@Inject) i @Resource jest inna kolejność wyboru typu wstrzykiwania.

@Autowired oraz @Inject

– po typie konkretnej klasy
– po wartości adnotacji @Qualifier
– po nazwie obiektu

@Resource

– po nazwie obiektu
– po typie konkretnej klasy
– po wartości adnotacji @Qualifier

Myślę, że najlepiej będzie zaprezentować tę różnicę na przykładzie:

Załóżmy, że mamy jeden interfejs Person, przez który będziemy wstrzykiwać jego dwie implementacje – Student i Teacher.

interface Person {
    void show();
}

@Component
public class Student implements Person {
    public void show() {
        System.out.println("Person");
    }
}

@Component
public class Teacher implements Person {
    public void show() {
        System.out.println("Teacher");
    }
}

Jeżeli teraz wstrzykniemy Person poprzez którakolwiek z adnotacji

@Autowired
private Person person;
    
@Inject
private Person person;

@Resource
private Person person;

zawsze dostaniemy błąd:

Field person in injection.beans.Main required a single bean, but 2 were found:
- student: defined in file [F:\work\Projects\spring-example\target\classes\injection\beans\Student.class]
- teacher: defined in file [F:\work\Projects\spring-example\target\classes\injection\beans\Teacher.class]

Spring nie wie, której implementacji użyć, dlatego wyrzuca odpowiedni wyjątek.

Aby rozwiązać ten problem, musimy w jakiś sposób zdefiniować, której klasy Spring ma użyć (załóżmy, że chcemy użyć Person).
Możemy to zrobić na trzy sposoby:
– przez typ konkretnej klasy
– przez nazwę obiektu
– przez adnotacje @Qualifier

Sposób 1 (przez typ konkretnej klasy)

@Autowired
private Student person;

@Inject
private Student person;

@Resource
private Student person;
Student    // for Autowired

Student    // for Inject

Student    // for Resource

Sposób 2 (przez nazwę obiektu)

@Autowired
private Person student;

@Inject
private Person student;

@Resource
private Person student;
Student    // for Autowired

Student    // for Inject

Student    // for Resource

 

Sposób 3 (przez adnotacje @Qualifier)

@Autowired
@Qualifier("student")
private Person person;

@Inject
@Qualifier("student")
private Person person;

@Resource
@Qualifier("student")
private Person person;
Student    // for Autowired

Student    // for Inject

Student    // for Resource

Na razie wszystkie adnotacje zachowują się tak samo, ale co w momencie, jeśli pomieszamy trochę te sposoby i np. w adnotacji @Qualifier wpiszemy nazwę „student”, ale nazwą obiektu będzie „teacher”.

@Autowired
@Qualifier("student")
private Person teacher;

@Inject
@Qualifier("student")
private Person teacher;

@Resource
@Qualifier("student")
private Person teacher;
Student    // for Autowired

Student    // for Inject

Teacher    // for Resource

Na tym przykładzie właśnie różnicę między adnotacjami.
Adnotacje @Autowired i @Inject w pierwszej kolejności sprawdzają wartość @Qualifier i pobierają obiekt tam wskazany, a @Resource najpierw zwraca uwagę na nazwę.

Jak widzicie, różnice, a właściwie różnica w zachowaniu nie jest zbyt duża, ale bardzo często to pytanie pojawia się na rozmowach i wszelakich testach kwalifikacyjnych, więc polecam zapamiętać ten szczegół.

Dziękuje za uwagę.
Pozdrawiam.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *