Один ли экземпляр бина @Component класса создается, если он используется в трех разных местах через @Autowired
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Ответ: Singleton паттерн в Spring @Component
Одно ключевое правило
Да, один ли экземпляр — это правильный ответ. По умолчанию, когда вы используете аннотацию @Component (или @Service, @Repository, @Controller), Spring создает ровно один экземпляр этого бина на все приложение, и этот же экземпляр будет внедрён во все места, где вы используете @Autowired.
Как это работает
Spring по умолчанию работает с singleton scope. Это означает:
@Component
public class UserService {
public void processUser() {
System.out.println("Processing user");
}
}
@Component
public class Controller1 {
@Autowired
private UserService userService; // Получит одну ссылку
}
@Component
public class Controller2 {
@Autowired
private UserService userService; // Та же ссылка!
}
@Component
public class Controller3 {
@Autowired
private UserService userService; // Все равно та же ссылка
}
Доказательство через hashCode()
Вы можете доказать это в коде:
@Component
public class UserService {
public int getInstanceId() {
return System.identityHashCode(this);
}
}
@Component
public class TestClass {
@Autowired
private UserService service1;
@Autowired
private UserService service2;
public void test() {
System.out.println(service1.getInstanceId()); // Например: 123456
System.out.println(service2.getInstanceId()); // Тот же: 123456
System.out.println(service1 == service2); // true
}
}
Зачем это нужно
- Производительность — экономия памяти, нет создания новых объектов
- Состояние — если в бине есть поле, оно будет одинаковым для всех потребителей
- Thread safety — нужно проектировать бины как thread-safe, так как их используют несколько потоков одновременно
Важное: статус потокобезопасности
Поскольку один экземпляр используется несколькими потоками, никогда не используйте поля-члены класса для хранения состояния:
// ❌ НЕПРАВИЛЬНО
@Component
public class BadService {
private String currentUser; // Опасно! Данные одного пользователя помешают другому
public void process() {
Thread.sleep(100);
System.out.println(currentUser); // Может быть другой пользователь!
}
}
// ✅ ПРАВИЛЬНО
@Component
public class GoodService {
public void process(String user) {
Thread.sleep(100);
System.out.println(user); // Безопасно
}
}
Как изменить scope
Если вам всё-таки нужны новые экземпляры, используйте @Scope:
@Component
@Scope("prototype") // Новый экземпляр каждый раз
public class UserService {
}
Доступные скоупы:
- singleton (по умолчанию) — один на приложение
- prototype — новый на каждый запрос
- request — новый на каждый HTTP запрос (только веб)
- session — один на HTTP сессию (только веб)
- application — один на ServletContext (только веб)
Резюме
@Component с @Autowired создает один экземпляр на всё приложение, который используется везде. Это singleton паттерн, обеспечивающий экономию ресурсов и единый контекст, но требующий внимания к потокобезопасности при работе с состоянием бина.