Ответ
В Spring scope (область видимости) "prototype" означает, что контейнер создает новый экземпляр бина при каждом запросе (через getBean() или инъекцию зависимости). Это противоположность scope "singleton" (по умолчанию), где контейнер возвращает один и тот же экземпляр.
Когда использовать:
- Когда состояние бина не должно разделяться между разными частями приложения.
- Для stateful-бинов (содержащих изменяемое состояние, специфичное для клиента).
- Когда бин не является потокобезопасным и используется в многопоточной среде.
Пример объявления prototype-бина:
-
С помощью аннотации
@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; } } -
В 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<>, чтобы избежать фиксации одного экземпляра.
Ответ 18+ 🔞
А, ну вот, прототипы в Спринге! Слушай, это ж классика, как "Муму" у Тургенева, только без утоплений, блядь.
Короче, представь: есть у тебя scope "singleton" — это как Герасим, один на весь двор, всех обслуживает, и хоть ты его в десять мест инжектни, он один и тот же мужик. А "prototype" — это уже другой коленкор, ёпта. Это когда каждый раз, как ты просишь бин, тебе выдают нового Герасима, свежесозданного, блядь. И у каждого свой уникальный номер, как у зэка, а не общая судьба на всех.
Когда это пиздец как нужно:
- Когда твой бин — это хитрая жопа с состоянием, которое нельзя шарить между всеми подряд.
- Для этих самых stateful-штук, где у каждого клиента своя отдельная песочница.
- Если бин не потокобезопасный, а вокруг него мартышлюшки-потоки носятся, как угорелые. Чтобы они друг другу в тарелку не срали.
Как его объявить, этого франта:
-
Через аннотацию
@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); // Каждому новому — свой рандомный ID, как паспорт! public int getId() { return id; } } -
В XML — для староверов и ценителей старой школы:
<bean id="prototypeService" class="com.example.PrototypeService" scope="prototype"/>
А вот как это выглядит в деле, на примере контроллера:
@RestController
public class TestController {
// Тут при каждой инъекции Spring, сука, рожает нового!
@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-бин. Если просто заинжектить, singleton схватит одного прототипа при своём рождении и будет с ним до гроба. Чтобы этого не было, используют
Provider<>илиLookup Method— это такие костыли, чтобы каждый раз выпрашивать свеженький экземпляр. Ёперный театр, но работает!
Вот и вся философия. Либо один на всех, либо каждому — свой, блядь. Выбирай, но думай головой, а не жопой.