← Назад к вопросам

Один ли экземпляр бина @Component класса создается, если он используется в трех разных местах через @Autowired

2.3 Middle🔥 191 комментариев
#Docker, Kubernetes и DevOps#JVM и управление памятью#ORM и Hibernate

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ответ: 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
    }
}

Зачем это нужно

  1. Производительность — экономия памяти, нет создания новых объектов
  2. Состояние — если в бине есть поле, оно будет одинаковым для всех потребителей
  3. 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 паттерн, обеспечивающий экономию ресурсов и единый контекст, но требующий внимания к потокобезопасности при работе с состоянием бина.