Что такое scope «prototype» в Spring и приведи пример его использования?

«Что такое scope «prototype» в Spring и приведи пример его использования?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Spring scope (область видимости) "prototype" означает, что контейнер создает новый экземпляр бина при каждом запросе (через getBean() или инъекцию зависимости). Это противоположность scope "singleton" (по умолчанию), где контейнер возвращает один и тот же экземпляр.

Когда использовать:

  • Когда состояние бина не должно разделяться между разными частями приложения.
  • Для stateful-бинов (содержащих изменяемое состояние, специфичное для клиента).
  • Когда бин не является потокобезопасным и используется в многопоточной среде.

Пример объявления prototype-бина:

  1. С помощью аннотации @Scope:

    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Component;
    
    @Component
    @Scope("prototype") // Ключевая аннотация
    public class PrototypeService {
        private int id = (int) (Math.random() * 1000); // Уникальное состояние для каждого экземпляра
    
        public int getId() {
            return id;
        }
    }
  2. В XML-конфигурации:

    <bean id="prototypeService" class="com.example.PrototypeService" scope="prototype"/>

Пример использования и проверки:

@RestController
public class TestController {
    // При каждой инъекции будет создан НОВЫЙ экземпляр PrototypeService
    @Autowired
    private PrototypeService service1;

    @Autowired
    private PrototypeService service2;

    @GetMapping("/test")
    public String test() {
        // service1 и service2 — разные объекты с разными id
        return "Service1 ID: " + service1.getId() +
               ", Service2 ID: " + service2.getId();
        // Вывод будет примерно: "Service1 ID: 742, Service2 ID: 319"
    }
}

Важные замечания:

  • Spring не управляет полным жизненным циклом prototype-бинов после их создания и передачи клиенту. Метод уничтожения (@PreDestroy) не будет вызван контейнером.
  • Использование prototype для всех бинов может негативно сказаться на производительности из-за постоянного создания объектов.
  • Для внедрения prototype-бина в singleton-бин часто используется режим инъекции Lookup Method или Provider<>, чтобы избежать фиксации одного экземпляра.