введение
На практике использовать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();
}
}
Вот процесс сопоставления бобов:
-
согласно с
type
Найдите совпадение в контексте, найдитеtype
дляIndexService
боб. -
Если есть несколько бобов, следуйте
name
соответствовать-
Если есть
@Qualifier
обратите внимание, согласно@Qualifier
Указанныйname
сопоставить, найтиname
дляindexServiceImpl2
боб. -
Если нет, вы можете сопоставить по имени переменной. найти
name
дляindexService
боб .
-
-
Если они не совпадают, будет сообщено об ошибке.
@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, то его процесс внедрения:
-
Если также указано
name
а такжеtype
, единственный подходящий bean-компонент находится из контекста Spring для сборки, и если он не найден, генерируется исключение. -
если указано
name
, компонент с совпадающим именем ищется в контексте для сборки, и если он не найден, выдается исключение. -
если указано
type
, из контекста для сборки найден единственный bean-компонент с соответствующим типом, если он не найден или найдено более одного, будет выдано исключение. -
Если ни то, ни другое не указано
name
, без указанияtype
, то по умолчаниюbyName
сборка; если нет совпадения, следуйтеbyType
Собрать.
Таким образом, мы можем использовать @Resource вместо @Autowired. Конечно, мы также можем использовать внедрение конструктора @RequiredArgsConstructor. Эта форма является внедрением конструктора, рекомендованным Spring. Этот метод является аннотацией в пакете lombok. Если этот метод используется, нужно ввести ломбок в проект,Например:
@RequiredArgsConstructor
public class UserDaoImpl {
private final User user;
}