Ответ
@Autowired в Spring — аннотация для внедрения зависимостей. Начиная с Spring 4.3, во многих случаях она стала опциональной.
Когда @Autowired можно опустить:
-
Для единственного конструктора (наиболее частый случай)
@Service public class UserService { private final UserRepository repository; // @Autowired не нужен (Spring 4.3+) public UserService(UserRepository repository) { this.repository = repository; } } -
Для setter-методов с одним параметром
@Component public class NotificationService { private EmailSender emailSender; // @Autowired не нужен public void setEmailSender(EmailSender emailSender) { this.emailSender = emailSender; } }
Когда @Autowired обязателен или рекомендуется:
-
Несколько конструкторов — нужно указать, какой использовать
@Service public class OrderService { private final OrderRepository repository; private final PaymentService paymentService; // Этот конструктор будет использован для инъекции @Autowired public OrderService(OrderRepository repository, PaymentService paymentService) { this.repository = repository; this.paymentService = paymentService; } // Этот конструктор Spring проигнорирует public OrderService(OrderRepository repository) { this.repository = repository; this.paymentService = null; } } -
Полевая инъекция (field injection)
@RestController public class UserController { @Autowired // обязательно для полей private UserService userService; @Autowired @Qualifier("primaryDataSource") // с Qualifier обязательно private DataSource dataSource; } -
Метод с несколькими параметрами
@Configuration public class AppConfig { @Autowired // рекомендуется для ясности public void configureServices(ServiceA a, ServiceB b, @Value("${timeout}") int timeout) { // настройка } }
Best practices Spring 5+:
// ✅ РЕКОМЕНДУЕТСЯ: инъекция через конструктор (без @Autowired)
@Service
public class ProductService {
private final ProductRepository repository;
private final PriceCalculator calculator;
public ProductService(ProductRepository repository,
PriceCalculator calculator) {
this.repository = repository;
this.calculator = calculator;
}
}
// ⚠️ ДОПУСТИМО: инъекция через setter (для optional зависимостей)
@Component
public class ReportGenerator {
private TemplateEngine templateEngine;
@Autowired
public void setTemplateEngine(TemplateEngine templateEngine) {
this.templateEngine = templateEngine;
}
}
// ❌ НЕ РЕКОМЕНДУЕТСЯ: полевая инъекция (кроме @Configuration классов)
@Service
public class BadExample {
@Autowired
private Dependency dependency; // сложно тестировать, не final
}
Ключевые моменты:
- Конструкторная инъекция — предпочтительный способ для mandatory зависимостей
- Setter-инъекция — для optional зависимостей
- Полевая инъекция — избегать в бизнес-логике
- Lombok — можно использовать
@RequiredArgsConstructorдля final полей
Почему конструкторная инъекция лучше:
- Поля можно сделать
final(immutable) - Легко тестировать (можно передавать моки в конструктор)
- Явные зависимости (видно все, что нужно для работы класса)
- Защита от циклических зависимостей (Spring обнаружит на этапе создания контекста)