Spring zrozumienie @Autowired @ComponentScan

0

Cześć,
nie dawno zacząłem uczyć się springa, ale coś nie mogę zrozumieć koncepcji automatycznego skanowania i auto łączenia. Mam taki przykład. Jest sobie rycerz, który może wykonać misję np. zabić smoka. W wiązaniu jawnym wgląda to tak:

public interface Knight {
    void embarkOnQuest();
}

public interface Quest {
    void embark();
}

public class BraverKnight implements Knight {

    private Quest quest;

    public BraverKnight(Quest quest) {
        this.quest = quest;
    }

    public void embarkOnQuest(){
        quest.embark();
    }
}

public class SlayDragonQuest implements Quest {

    private PrintStream stream;

    public SlayDragonQuest(PrintStream stream) {
        this.stream = stream;
    }

    public void embark() {
        stream.println("Embarking on quest to slay the dragon");
    }
}

@Configuration
public class KnightConfig {

    @Bean
    public Knight knight(){
        return new BraverKnight(quest());
    }

    @Bean
    public Quest quest(){
        return new SlayDragonQuest(System.out);
    }
}

public class KnightMain {

    public static void main(String[] args) throws Exception{

        ApplicationContext context = new AnnotationConfigApplicationContext(KnightConfig.class);
        BraverKnight knight = context.getBean(BraverKnight.class);
        knight.embarkOnQuest();
    }
}

Chciałbym teraz przerobić to na auto wiązanie, więc dodaję do klasy konfiguracyjnej adnotację @ComponentScan. Rozumiem też, że moimi komponentami są klasy BraverKnight oraz SlayDragonQuest, więc im dodaję adnotację @Component, ale teraz nie do końca już rozumiem o co chodzi z tym auto wiązaniem, jak to powinienem zrobić? Dodać do ww. konstruktorów adnotację @Autowired? A co później z tymi Beanami w klasie konfiguracyjnej?
Zapytam się też od razu czy można w Spring core za symulować sobie zwykła aplikację javy? Np. mamy aplikację, która pobiera od użytkownika bok kwadratu i liczy jego pole.

0

Auto-wiązania używasz jak chcesz wykorzystać dane beany w innych klasach. Dajesz w nich np.:

@Autowired
private BraverKnight braverKnight;

W całej aplikacji będzie to ta sama instancja (chyba, że to zmienisz ustawiając Scope).

@ComponentScan używasz, żeby Spring znalazł komponenty oznaczone adnotacją @Component i jego pochodnymi jak @Service, @Repository itd. Mógłbyś np. oznaczyć BraverKnight taką adnotacją i wtedy już nie musisz tworzyć tego obiektu jako @Bean tylko będzie on utworzony dzięki @ComponentScan.

Aplikacja w Springu to normalna aplikacja Javy. Możesz sobie w mainie pobrać Scannerem dane od użytkownika z konsoli.

0

No ja te adnotację rozumiem, ale nie umiem coś tego zastosować. Dodałem @ComponentScan do klasy konfiguracyjnej ustawiłem klasę BraveKnight jako @Component, ale nie wiem gdzie użyć tego auto wiązania teraz. Jak zrobię coś takiego

@Autowired
private BraverKnight braverKnight;

W klasie konfiguracyjnej to nie działa.

0

Ale tego nie stosuje się tego w klasie konfiguracyjnej tylko w innym komponencie

na przykład masz

@Repository
public class UserDAOImpl implements UserDAO{
...

}
 

A później

@Service
public class UserServiceImpl implements UserService{
@Autowired
private UserDAO userDAO;
...
}
 

a klasie konfiguracyjneej oznaczasz żeby @ComponentScan skanowało odpowiednie pakiety (zazwyczaj cały pakiet projektu)
@Repository i @Service to rozszerzenia @Component więc kontener springa utworzy UserDAO jako bean dzięki adnotacji @Repository a później wstrzyknie do UserServiceImpl dzięki @Autowired

0

aha to chyba rozumiem. Czyli @Beana i tak muszę sobie stworzyć tak? Tylko np. jakieś jego elementy mogą być auto wiązane i nimi się nie interesuję?

0

Nie no @Bean to jest w klasie konfiguracyjnej
Albo wczytujesz komponent przez autoskanowanie albo fabryke i metode z anotacją @Bean

@Component
public class FajnaKlasa(){
}
 

i

@Configuration
public class RootConfig(){
   @Bean
   public FajnaKlasa fajnaKlasa(){
       return new FajnaKlasa();
   }
}
 

daje ten sam efekt

0

no okej ale ja myślę o swoim przykładzie. Jeśli mam swoją klasę

@Component
public class BraveKnight implements Knight {

    private Quest quest;
    
    public BraveKnight(Quest quest) {
        this.quest = quest;
    }

    public void embarkOnQuest(){
        quest.embark();
    }
}

To teraz Questowi mogę przypisać @Autowired i wtedy stworzyć tylko @Beana BraveKnight? Nie wiem czy dobrze to rozumiem, ale jakbyście mogli mi to pokazać na tym moim przykładnie to było by cudownie :P

0

Dobra mam inny przykład przepisany z książki i kurde to mi nie chce działać :/

public interface CompactDisc {
    void play();
}
@Component
public class SgtPeppers implements CompactDisc {

    private String title = "Sgt. Pepper's Lonely Hearts Club Band";
    private String artist = "The Beatles";

    public void play() {
        System.out.println("Odtwarzam utwór " + title + " artysty " + artist);
    }

}
@Configuration
@ComponentScan
public class CDPlayerConfig {
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=CDPlayerConfig.class)
public class CDPlayerTest {

    @Autowired
    private CompactDisc cd;

    @Test
    public void cdShouldNotBeNull() {
        assertNotNull(cd);
    }

}
WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.context.annotation.internalAsyncAnnotationProcessor' defined in class path resource [org/springframework/scheduling/annotation/ProxyAsyncConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor]: Factory method 'asyncAdvisor' threw exception; nested exception is java.lang.IllegalArgumentException: @EnableAsync annotation metadata was not injected
sie 05, 2016 12:59:44 PM org.springframework.test.context.TestContextManager prepareTestInstance
SEVERE: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@7c75222b] to prepare test instance [CDPlayerTest@522d86e4]
java.lang.IllegalStateException: Failed to load ApplicationContext

1 użytkowników online, w tym zalogowanych: 0, gości: 1