• 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

Object Storage Arubacloud
0 głosów
403 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 229 wizyt
+1 głos
1 odpowiedź 243 wizyt
pytanie zadane 25 września 2018 w Java przez BuxBleed Użytkownik (810 p.)
0 głosów
1 odpowiedź 263 wizyt
pytanie zadane 14 lipca 2019 w Sprawy forum przez qwiateq Początkujący (430 p.)

92,575 zapytań

141,424 odpowiedzi

319,649 komentarzy

61,960 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.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...