Почему Spring устарела аннотация @Autowired?

Spring опрос

введение

На практике использоватьIDEAПри разработке многие кодеры любят использовать@AutowiredАннотация используется для внедрения зависимостей. В настоящее время IDEA сообщит о желтом предупреждении и фрагменте кодаwarning, чистота кода Я не допускаю здесь такого расплывчатого предупреждения.@Autowiredтак какSpringмой сын, почему ты здесь?IDEAЕсть ли такое предупреждение? Итак, с моей чистотой и любопытством я начал исследовать это предупреждение.

Кратко переведем, что значит автоматически подсказывать:

Внедрение зависимостей непосредственно в поля не рекомендуется.SpringКоманда разработчиков рекомендует: вJava BeanВсегда используйте конструкторы для внедрения зависимостей.

С вышеуказанными вопросами, давайте посмотрим вниз

способ внедрения зависимостей

SpringСуществует три способа внедрения зависимостей

Внедрение на основе атрибутов (в поле)

Этот метод внедрения заключается в использовании аннотаций к переменным компонента для внедрения зависимостей. По сути, он вводится непосредственно в поле путем отражения. Это то, как я вижу наиболее и наиболее знакомый путь в моем обычном развитии. Например:

@Autowired
UserService userService;

Инъекция по установленному методу

через соответствующую переменнуюsetXXX()методы и использование аннотаций к методам для завершения внедрения зависимостей. Например:

private UserService userService;

@Autowired
public void setUserService(UserService userService) {
    this.userService = userService;
}

Примечание. В Spring 4.5 и более поздних версиях аннотацию @Autowired для setXXX можно опустить.

Инъекция на основе конструктора

将各个必需的依赖全部放在带有注解构造方法的参数中,并在构造方法中完成对应变量的初始化,这种方式,就是基于构造方法的注入。 Например:

private final UserService userService;

@Autowired
public UserController(UserService userService) {
    this.userService = userService;
}

Внедрение свойств

Как видите, способ ввода переменной (filed) очень аккуратный. Но на самом деле у него есть некоторые проблемы, конкретные проблемы заключаются в следующем:

Вопрос первый

@Autowired
private UserService userService;

private String company;

public UserServiceImpl() {
    this.company = userService.getCompany();
}

Процесс компиляции не сообщит об ошибке, но сообщит после запускаNullPointerException

Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [...]: Constructor threw exception; nested exception is java.lang.NullPointerException

Когда Java инициализирует класс, он следует порядку: статическая переменная или блок статических операторов -> переменная экземпляра или блок инициализации -> конструктор -> @Autowired. Таким образом, когда конструктор этого класса выполняется, пользовательский объект не был внедрен, и его значение по-прежнему равно нулю.

Вопрос второй

Зависимости не могут быть указаны эффективно. Я считаю, что многие люди столкнулись с ошибкой.Объект внедрения зависимостей равен нулю.При запуске контейнера зависимостей проблема в том, что в настроенном внедрении зависимостей отсутствует аннотация или что-то в этом роде. Этот метод слишком зависит от контейнера инъекций, когда не запущен весь контейнер зависимостей, класс не может быть запущен, а зависимости, необходимые этому классу, не могут быть предоставлены во время отражения.

Вопрос третий

Одна из основных идей внедрения зависимостей заключается в том, что класс, управляемый контейнером, не должен зависеть от зависимостей, управляемых контейнером, другими словами, если класс использует класс внедрения зависимостей, то класс должен уметь избавляться от зависимостей. эти зависимости нормальная работа. Однако использование переменной инъекции не гарантирует этого.

Как с этим бороться?

Обычно мы используем эти три аннотации, когда нам нужно внедрить свойства в разработку.@Autowired,@Inject,@Resource, эти три аннотации также поддерживаются только в Spring. Давайте сначала посмотрим на разницу между этими тремя аннотациями?

@Autowired

@AutowiredАннотации, предусмотренные для среды Spring, можно считать сыновьями Spring. Вот пример кода

public interface IndexService {

    void sayHello();
}

@Service
public class IndexServiceImpl implements IndexService {

    @Override
    public void sayHello() {
        System.out.println("hello, this is IndexServiceImpl");
    }
}

@Service
public class IndexServiceImpl2 implements IndexService {

    @Override
    public void sayHello() {
        System.out.println("hello, this is IndexServiceImpl2");
    }
}

метод тестирования

@SpringBootTest
public class Stest {

    @Autowired
    // @Qualifier("indexServiceImpl2")
    IndexService indexService;

    @Test
    void gooo() {
        Assertions.assertNotNull(indexService);
        indexService.sayHello();
    }

}

Вот процесс сопоставления бобов:

  1. согласно сtypeНайдите совпадение в контексте, найдитеtypeдляIndexServiceбоб.

  2. Если есть несколько бобов, следуйтеnameсоответствовать

    • Если есть@Qualifierобратите внимание, согласно@QualifierУказанныйnameсопоставить, найтиnameдляindexServiceImpl2боб.

    • Если нет, вы можете сопоставить по имени переменной. найтиnameдляindexServiceбоб .

  3. Если они не совпадают, будет сообщено об ошибке.@Autowired(required=false), если установленоrequiredимеет значение false (по умолчанию true ), в случае сбоя внедрения исключение не будет выдано.

@Inject

В контексте Spring @Inject и @Autowired одинаковы, потому что их внедрение зависимостей используетAutowiredAnnotationBeanPostProcessorЭтот постпроцессор справляется с этим.

Разница между этими двумя, прежде всего @Inject, находится в пакете Java EE и должна быть представлена ​​отдельно в среде SE. Еще одно отличие состоит в том, что @Autowired может установить required=false, а @Inject не имеет этого свойства. Некоторые также говорят, что @Inject — это крестник весны.

@Resource

@Resource — это аннотация, определенная JSR-250. Spring реализует обработку аннотаций JSR-250 в CommonAnnotationBeanPostProcessor, включая @Resource.

это@Resourceимеет 2 свойстваnameа такжеtype. веснойnameСвойство определяется как имя бина,typeЭто сорт фасоли. Если к свойству добавлена ​​аннотация @Resource, то его процесс внедрения:

  1. Если также указаноnameа такжеtype, единственный подходящий bean-компонент находится из контекста Spring для сборки, и если он не найден, генерируется исключение.

  2. если указаноname, компонент с совпадающим именем ищется в контексте для сборки, и если он не найден, выдается исключение.

  3. если указаноtype, из контекста для сборки найден единственный bean-компонент с соответствующим типом, если он не найден или найдено более одного, будет выдано исключение.

  4. Если ни то, ни другое не указаноname, без указанияtype, то по умолчаниюbyNameсборка; если нет совпадения, следуйтеbyTypeСобрать.

Таким образом, мы можем использовать @Resource вместо @Autowired. Конечно, мы также можем использовать внедрение конструктора @RequiredArgsConstructor. Эта форма является внедрением конструктора, рекомендованным Spring. Этот метод является аннотацией в пакете lombok. Если этот метод используется, нужно ввести ломбок в проект,Например:

@RequiredArgsConstructor
public class UserDaoImpl {
	private final User user;
}