Почему не рекомендуется внедрение зависимостей @Autowired?
Мало знаний, большой вызов! Эта статья участвует в "Необходимые знания для программистов«Творческая деятельность
Эта статья также участвуетПроект «Звезда раскопок», чтобы выиграть творческие подарочные наборы и бросить вызов творческим поощрениям
введение
При разработке с IDEA та же группа друзей любит использовать инъекцию @Autowired, код является предупреждением, и выглядит очень неудобно.Как сын Spring, почему @Autowired выдал предупреждение в IDEA: инъекции поля не рекомендуется
Прежде чем пытаться разобраться в этой проблеме, давайте сначала разберемся с несколькими способами внедрения зависимостей.
Три метода инъекции Spring
инъекция собственности
Этот метод внедрения заключается в использовании аннотаций к переменным компонента для внедрения зависимостей. По сути, он напрямую вводится в поле путем отражения. Это то, как я вижу наиболее и наиболее знакомый путь в моем обычном развитии.
@Autowired
UserDao userDao;
Внедрение конструктора
Поместите все необходимые зависимости в параметры аннотированного конструктора и завершите инициализацию соответствующих переменных в конструкторе.Этот метод основан на внедрении конструктора. Например:
final
UserDao userDao;
@Autowired
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
установка метода впрыска
Внедрение зависимостей осуществляется с помощью метода setXXX() соответствующей переменной и использования аннотаций к методу. Например:
private UserDao userDao;
@Autowired
public void setUserDao (UserDao userDao) {
this.userDao = userDao;
}
Возможные проблемы с внедрением свойств
Вопрос первый
Инъекция на месте может привести к некоторым скрытым проблемам. Возьмем пример:
@Autowired
private User user;
private String company;
public UserDaoImpl(){
this.company = user.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. Таким образом, когда конструктор этого класса выполняется, пользовательский объект не был внедрен, и его значение по-прежнему равно нулю.
Вопрос второй
Зависимости не могут быть указаны эффективно. Я считаю, что многие люди столкнулись с ошибкой.Объект внедрения зависимостей равен нулю.При запуске контейнера зависимостей проблема в том, что в настроенном внедрении зависимостей отсутствует аннотация или что-то в этом роде. Этот метод слишком зависит от контейнера инъекций, когда не запущен весь контейнер зависимостей, класс не может быть запущен, а зависимости, необходимые этому классу, не могут быть предоставлены во время отражения.
Вопрос третий
Одна из основных идей внедрения зависимостей заключается в том, что класс, управляемый контейнером, не должен зависеть от зависимостей, управляемых контейнером, другими словами, если класс использует класс внедрения зависимостей, то класс должен уметь избавляться от зависимостей. эти зависимости нормальная работа. Однако использование переменной инъекции не гарантирует этого.
весеннее предложение
Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies.
Перевод:
Принудительные зависимости используют метод конструктора
Необязательные изменяемые зависимости вводятся с помощью сеттеров
Используйте @Resource вместо @Autowired
@Resource имеет 2 имени свойства и тип. В spring атрибут name определяется как имя бина, а type — это тип бина. Если к свойству добавлена аннотация @Resource, то его процесс внедрения
- Если указаны и имя, и тип, единственный соответствующий bean-компонент будет найден из контекста Spring для сборки, и если он не будет найден, будет выдано исключение.
- Если имя указано, ищите bean-компонент с совпадающим именем в контексте сборки и выдайте исключение, если оно не найдено.
- Если тип указан, единственный bean-компонент с соответствующим типом будет найден из контекста для сборки, и будет выдано исключение, если он не будет найден или если будет найдено более одного.
- Если не указано ни имя, ни тип, по умолчанию будет собрано по имени, если совпадения нет, будет собрано по типу.
@Autowired вводит только на основе типа и не соответствует имени. Если тип не может идентифицировать внедренный объект, его необходимо украсить аннотациями @Qualifier или @Primary.
Используйте внедрение конструктора @RequiredArgsConstructor
Эта форма является внедрением конструктора, рекомендованным Spring.Этот метод является аннотацией под пакетом lombok.Если используется этот метод, lombok необходимо ввести в проект, например:
@RequiredArgsConstructor
public class UserDaoImpl{
private final User user;
}