Spring @Autowired не работает

У меня есть некоторые проблемы с аннотацией autowire. Мое приложение выглядит так:

Вот контроллер:

@Controller
public class MyController {
    @Autowired
    @Qualifier("someService")
    private SomeService someService;

    ....
}

Это сервисный уровень:

public interface SomeService {
    ...
}

@Service
public class SomeServiceImpl implements SomeService{    
    @Autowired
    @Qualifier("myDAO")
    private MyDAO myDAO;

    ....
}

И слой DAO:

public interface MyDAO{
    ....        
}

@Repository
public class JDBCDAOImpl implements MyDAO {    
    @Autowired
    @Qualifier("dataSource")
    private DataSource dataSource;    
    ....
}

Это файл app-service.xml:

....
<bean id="propertyConfigurer"
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
      p:location="/WEB-INF/jdbc.properties" />

<bean id="dataSource"
      class="org.springframework.jdbc.datasource.DriverManagerDataSource"
      p:driverClassName="${jdbc.driverClassName}"
      p:url="${jdbc.url}"
      p:username="${jdbc.username}"
      p:password="${jdbc.password}"/>

<bean id="SomeService" class="com.service.SomeServiceImpl" />    
<bean id="myDAO" class="com.db.JDBCDAOImpl" />    

Итак... Когда я запускаю веб-приложение, MyController Autowires правильно (поле someService правильно введено объектом класса SomeServiceImpl), но поле myDAO для someService имеет нулевое значение (не введено должным образом).

Не могли бы вы помочь мне найти проблему?

P.S. Это интересно, но когда я меняю "идентификатор компонента" с myDAO на какой-либо другой (например, myDAO2), система выдает мне ошибку, что инъекция не может быть выполнена, потому что bean myDAO не существует. Итак, Spring делает инъекцию, но где она? И почему это не работает правильно?


person Ilnur    schedule 26.11.2010    source источник
comment
Почему бы вам не использовать аннотацию @Service в службе и @Repository в DAO, как вы используете @Controller в контроллере?   -  person Javi    schedule 26.11.2010
comment
да... пользуюсь. Отредактировано... Я забыл их написать, потому что мое приложение сложнее, чем код выше. Но ошибки в том месте.   -  person Ilnur    schedule 26.11.2010
comment
если вы добавите аннотацию @Repository и @Service, вам не нужно определять их в xml как bean-компонент. Их можно найти с помощью ‹context:component-scan base-package=org.example/›.   -  person Javi    schedule 26.11.2010
comment
@Javi: когда я удаляю эти 2 строки: ‹bean id=SomeService class=com.service.SomeServiceImpl /› ‹bean id=myDAO class=com.db.JDBCDAOImpl /›, мое приложение выдает ошибку: Injection of autowired зависимости не удались; вложенное исключение ......   -  person Ilnur    schedule 26.11.2010
comment
Можете ли вы отредактировать вопрос и добавить журнал неудачной инъекции автосвязанных зависимостей?   -  person Javi    schedule 26.11.2010
comment
Я разместил ответ ... Мои проблемы решены, но я до сих пор не знаю, как использовать аннотацию @Autowire на более низких уровнях приложения (когда аннотации @Repository и @Service не нужны).   -  person Ilnur    schedule 26.11.2010


Ответы (7)


Я нашел решение. Как сказал Хави (большое спасибо, Хави), я должен аннотировать классы уровня DAO и службы с помощью аннотаций @Repository и @Service. Сейчас попробовал написать так:

@Service("someService")
public class SomeServiceImpl implements SomeService{    
    @Autowired
    @Qualifier("myDAO")
    private MyDAO myDAO;

    ....
}

а также

@Repository("myDAO")
    public class JDBCDAOImpl implements MyDAO {    
    @Autowired
    @Qualifier("dataSource")
    private DataSource dataSource;    
    ....
}

и все работает отлично!!!

Но я до сих пор не нашел ответа на этот вопрос: если приложение будет более сложным, и будет иметь более сложную структуру, где аннотации @Repositore и @Service не являются предпочтительными для некоторых классов, как правильно внедрить бины, которые находятся на более низких уровнях (в поля классов, или в поле полей классов) (с аннотацией @Autowire, разумеется)?

person Ilnur    schedule 26.11.2010
comment
@Component используется для другого компонента, который не является контроллером, службой или репозиторием. - person Javi; 26.11.2010
comment
@Ilnur Отметьте свой ответ как принятый, потому что именно вы его нашли, хотя вы можете проголосовать за комментарий, если он также показался вам интересным :) - person Javi; 26.11.2010
comment
@llnur: обратите внимание, что в этом случае вам также не нужно явно объявлять их как <bean>s. - person axtavt; 26.11.2010
comment
@axtavt: но как я могу вводить конкретные классы в поля без объявления bean-компонентов в xml-файле (кроме аннотаций @Repository и @Service)? - person Ilnur; 26.11.2010
comment
@llnur: я имею в виду, что bean-компоненты, объявленные с помощью аннотаций, не нужно объявлять в XML. - person axtavt; 26.11.2010
comment
аааа... Хорошо, я тебя понимаю! Спасибо! - person Ilnur; 26.11.2010
comment
@axtavt: Я весь день думал о таком методе аннотирования (с использованием @Repository и @Service). Я думаю, что их использование и избегание объявления их как ‹beans› делает приложение потерявшим свою силу (внедрение зависимостей и IOC), потому что теперь мы не могли настроить наше приложение без перекомпиляции. - person Ilnur; 27.11.2010

Я думаю, вам нужно <context:annotation-config />.

person axtavt    schedule 26.11.2010
comment
Он существует в файле app-servlet.xml. Что-то вроде этого: ‹context:annotation-config /› ‹context:component-scan base-package=com /› - person Ilnur; 26.11.2010

Вы можете использовать

<context:component-scan base-package="PATH OF THE BASE PACKAGE"/>  

запись в файле конфигурации .xml. Эта запись будет сканировать/считывать все указанные типы и аннотации из классов Java.

person Krishna Kumar Chourasiya    schedule 23.09.2013

Важные моменты:

  1. Иногда @Component может привести к проблеме, когда может быть указано, что конструктор по умолчанию не найден. Класс, определенный как аннотация @Component, должен иметь конструктор по умолчанию.
  2. Предположим, мы применили аннотацию @Autowired к полю, которое является определяемой пользователем ссылкой на класс. Теперь, если мы также применим @Component к этому классу, он всегда будет инициализирован нулем. Таким образом, поле с @Autowired не должно иметь @Component в своем определении класса.
  3. По умолчанию @Autowired по типу.

Адресный компонент автоматически подключается в классе Student. Давайте посмотрим, что произойдет, если мы применим @Component к Address.java.

CollegeApp.java:

package com.myTest
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.bean.Address;
import com.bean.Student;
//Component scanning will for only those classes
//which is defined as @Component. But, all the class should not use
//@Component always even if the class is enabled with auto
//component scanning, specially the class which is Autowired
//Or which is a property of another class 
@Configuration
@ComponentScan(basePackages={"com.bean"})
public class CollegeApp {
    @Bean
    public Address getAddress(){
        return new Address("Elgin street");
}
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(CollegeApp.class);
        Student student=context.getBean(Student.class);
        System.out.println(student.toString());
        context.close();
    }
}

Мы хотим, чтобы улица Элгин была автоматически привязана к адресу студента.

Адрес.java:

package com.bean;
import org.springframework.stereotype.Component;
@Component
public class Address {
    private String street;
    public Address()
    {
    }
    public Address(String theStreet)
    {
        street=theStreet;
    }
    public String toString()
    {
        return (" Address:"+street);
    }
}

Студент.java:

package com.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Student {
    private String name;
    private int age;
    private Address address;
    public Student()
    {
    }
    public Student(String theName,int theAge)
    {
        name=theName;age=theAge;
    }
    @Autowired
    public void setAddress(Address address) {
        this.address = address;
    }
    public String toString()
    {
        return ("Name:"+name+" Age:"+age+ " "+address);
    }
}

Вывод: - Name:null Age:0 Address:null //Адрес здесь не автоподключен.

Чтобы решить эту проблему, измените только Address.java, как показано ниже:

Адрес.java:

package com.bean;
public class Address {
    private String street;
    public Address(String theStreet)
    {
        street=theStreet;
    }
    public String toString()
    {
        return (" Address:"+street);
    }
}

Результат:- Имя: null Возраст: 0 Адрес: улица Элгин

person Sumit Basu    schedule 08.08.2018
comment
Непонятно, какое это имеет отношение к вопросу. - person Nathan Hughes; 08.08.2018

Вы должны включить этот раздел кода XML в spring-config.xml :

<context:component-scan base-package="Fully.Qualified.Package.Name" />

но вы должны знать разницу между <context:annotation-config> и <context:component-scan>, так как большинство людей предлагают эти два:

1) Первое большое различие между обоими тегами заключается в том, что <context:annotation-config> используется для активации примененных аннотаций в уже зарегистрированных bean-компонентах в контексте приложения. Обратите внимание, что просто не имеет значения, был ли зарегистрирован bean-компонент с помощью какого механизма, например. с помощью <context:component-scan> или он был определен в самом файле application-context.xml.

2) Второе отличие определяется самим первым отличием. Он регистрирует bean-компоненты в контексте + также сканирует аннотации внутри bean-компонентов и активирует их. Итак, <context:component-scan>; делает то, что делает <context:annotation-config>, но дополнительно сканирует пакеты и регистрирует bean-компоненты в контексте приложения.

person Shubh    schedule 29.03.2020

Этому может быть две причины.

  1. Если вы не аннотировали внедренный объект или службу с помощью правильных аннотаций @Service/@Component/@Repository.

  2. Убедившись в пункте 1, затем проверьте, включен ли пакет класса вашего аннотированного класса обслуживания в путь к классу для вашего приложения весенней загрузки в основном классе. Вы можете настроить это, используя следующую аннотацию.

@SpringBootApplication (scanBasePackages = {com.ie.efgh.somepackage, com.ie.abcd.someotherpackage})

Делая это, вы говорите Spring просматривать пакеты для классов во время загрузки класса.

person Poorvi    schedule 17.12.2020
comment
Пожалуйста, отредактируйте свой ответ: улучшите форматирование кода См. Как ответить - person Gander; 17.12.2020

person    schedule
comment
Хотя код хорош, объяснение того, как он решает вопрос, также полезно как для человека, который задал вопрос, так и для будущих читателей. - person Philipp Reichart; 13.04.2018