• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

@Component bądź @ComponentScan nie działa

0 głosów
604 wizyt
pytanie zadane 12 lipca 2017 w Java przez Kodoj Nowicjusz (120 p.)

Cześć, zacznę od tego że jestem osobą zupełnie początkującą jeżeli chodzi o Springa, zaczynam uczyć się tworzenia kontekstów, wstrzykiwania zależności, tworzenia ziaren itd. Mam w tym momencie malutki projekt na którym po prostu trenuję kolejne zagadnienia i pokonały mnie adnotacje @Component oraz @ComponentScan - nie potrafię jeszcze debugować dlatego nie jestem w stanie powiedzieć, która z nich nie działa, w każdym razie moja aplikacja wygląda następująco:

Klasa startowa mojej aplikacji, tutaj dodam że w chwili kiedy @ComponentScan był w osobnym pliku konfiguracyjnym, aplikacja tak samo nie działała:

package pl.javastart.app;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
        import org.springframework.context.annotation.ComponentScan;
        import org.springframework.context.annotation.Configuration;

        import pl.javastart.beans.MessagePrinter;

@Configuration
@ComponentScan
public class SpringDiApplication {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx =
                new AnnotationConfigApplicationContext(SpringDiApplication.class);
        MessagePrinter printer = ctx.getBean(MessagePrinter.class);
        printer.print();
        ctx.close();
    }
}

Klasa będąca producentem mojej wiadomości:

package pl.javastart.beans;

import org.springframework.stereotype.Component;

@Component
public class SimpleMessageProducer implements MessageProducer{

    @Override
    public String getMessage() {
        return "Example message " + System.currentTimeMillis();
    }
}

Klasa drukująca wiadomość:

import org.springframework.stereotype.Component;

@Component
public class MessagePrinter {

    private MessageProducer producer;

    MessagePrinter() {}

    public MessagePrinter(MessageProducer producer) {
        this.producer = producer;
    }

    public MessageProducer getProducer() {
        return producer;
    }

    public void setProducer(MessageProducer producer) {
        this.producer = producer;
    }

    public void print() {
        System.out.println(producer.getMessage());
    }
}

No i Interface

public interface MessageProducer {

    public String getMessage();
}

Błąd który mi wyskakuje to:
lip 12, 2017 8:11:48 PM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@37bba400: startup date [Wed Jul 12 20:11:48 CEST 2017]; root of context hierarchy
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [pl.javastart.beans.MessagePrinter] is defined
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:372)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:332)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1066)
    at pl.javastart.app.SpringDiApplication.main(SpringDiApplication.java:19)


Jak rozumiem kontener Springa nie potrafi stworzyć ziarna, nie widzi podanych przeze mnie komponentów. Kiedy w projekcie był dodatkowy plik beans-config.xml w którym ręcznie stworzyłem ziarna, wskazując po prostu klasy a do tworzenia kontekstu używałem klasy ClassPathXmlApplicationContext, cały projekt działał prawidłowo. Z tego jednak co wiem @Component to coś, co jest używane aktualnie a konfiguracja przez plik xml przechodzi do lamusa, więc chciałbym się dowiedzieć co robię źle.

1 odpowiedź

+1 głos
odpowiedź 12 lipca 2017 przez xenonso Mądrala (5,160 p.)

Na początku zaznaczę, że sam w Springa dopiero zaczynam i jestem zielony jak listek w logo :P. Dlatego moje rady traktuj jako coś mało pewnego i będę wdzięczny jeśli wypowie się ktoś bardziej ogarnięty.

1. Wyodrębnij osobną klasę do konfiguracji beanów. Wydaje mi się, że nie jest dobre łączenie jej z mainem.


package info.stanislawczyk.spring.api;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages="info.stanislawczyk")
public class AppConfiguration {
	
}

Pozostałe klasy, w których coś zmieniłem

package info.stanislawczyk.spring.api;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("messagePrinter")
public class MessagePrinter {
 
	@Autowired
    private MessageProducer producer;
 
    MessagePrinter() {}
 
    public MessagePrinter(MessageProducer producer) {
        this.producer = producer;
    }
 
    public MessageProducer getProducer() {
        return producer;
    }
 
    public void setProducer(MessageProducer producer) {
        this.producer = producer;
    }
 
    public void print() {
        System.out.println(producer.getMessage());
    }
}
package info.stanislawczyk.spring.api;

import org.springframework.stereotype.Component;

@Component("simpleMessageProducer")
public class SimpleMessageProducer implements MessageProducer{
 
    public String getMessage() {
        return "Example message " + System.currentTimeMillis();
    }
}
package info.stanislawczyk.spring.api;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class SpringDiApplication {

   public static void main(String[] args) {
       AnnotationConfigApplicationContext ctx =
               new AnnotationConfigApplicationContext(AppConfiguration.class);
       MessageProducer messageProducer = ctx.getBean("simpleMessageProducer", MessageProducer.class);
       System.out.println(messageProducer.getMessage());
   }
}

2. W mainie context wywołujesz podobnie jak było to przy xml czyli 

 AnnotationConfigApplicationContext ctx =
               new AnnotationConfigApplicationContext(AppConfiguration.class);
       MessageProducer messageProducer = ctx.getBean("simpleMessageProducer", MessageProducer.class);

Nazwa simpleMessageProducer została ustawiona przy adnotacji Component w odpowiedniej klasie

3. W AppConfigu basePackages jest opcjonalne, ale u mnie raz działa bez tego, a raz nie także na wszelki wypadek to dałem

4. Componenty nazywasz w taki sposób @Component("nazwaBeana")

Tak jak mówiłem w Springu jestem jeszcze słaby i najlepiej będzie jak przejrzysz sobie jakieś kursy (np. Artura Owczarka na YT).

1
komentarz 12 lipca 2017 przez Aisekai Nałogowiec (42,190 p.)
Nie jestem pewien, ale z tego co pamiętam, to czy w @ComponentScan nie jest wymagane podanie paczek (pakiety, pack jak zwał tak zwał) które się skanuje w poszukiwaniu Beanow? Z tego co też pamiętam, to jak się nie poda nazwy w @Component to domyślną nazwą będzie nazwa klasy tylko z małej litery.
komentarz 13 lipca 2017 przez Kodoj Nowicjusz (120 p.)
Połączenie tych dwóch komentarzy dało mi rozwiązanie :)
Zapomniałem o @Autowired, bez tego Spring nie miał prawa wiedzieć o co mi chodzi. Co do @ComponentScan, czytałem że najbardziej polecanym rozwiązaniem jest nie wpisywanie niczego, jednak moja aplikacja zadziałała dopiero kiedy do @ComponentScan dopisałem chociażby taki ogólnik jak(basePackages = "pl.javastart").

Wszystko działa i dziękuję wam obu za zainteresowanie moją sprawą.

Podobne pytania

0 głosów
2 odpowiedzi 780 wizyt
+1 głos
1 odpowiedź 560 wizyt
pytanie zadane 25 września 2018 w Java przez BuxBleed Użytkownik (810 p.)
0 głosów
1 odpowiedź 402 wizyt
pytanie zadane 14 lipca 2019 w Sprawy forum przez qwiateq Początkujący (430 p.)

93,771 zapytań

142,731 odpowiedzi

323,383 komentarzy

63,372 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Twierdza Linux. Bezpieczeństwo dla dociekliwych

Aby uzyskać rabat -10%, użyjcie kodu pasja-linux, wpisując go w specjalne pole w koszyku.

...