Ответ
Да, по умолчанию создаётся один экземпляр (singleton). Все поля, аннотированные @Autowired и ссылающиеся на бин с @Component, получат ссылку на один и тот же объект в контексте Spring.
Пример:
@Component // Spring создаст ОДИН экземпляр этого класса
public class CommonService {
// ...
}
@Service
public class OrderService {
@Autowired // Ссылка на единственный экземпляр CommonService
private CommonService commonService;
}
@Controller
public class UserController {
@Autowired // Ссылка на тот же самый экземпляр CommonService
private CommonService commonService;
}
Области видимости (Scope) бинов:
Поведение по умолчанию можно изменить с помощью аннотации @Scope:
@Scope("singleton")(по умолчанию): Один бин на IoC-контейнер.@Scope("prototype"): Новый экземпляр при каждом запросе (черезgetBean()или инъекцию).@Scope("request"),@Scope("session"): Бин привязан к жизненному циклу HTTP-запроса или сессии (в веб-приложениях).
Почему singleton по умолчанию? Это обеспечивает эффективное использование памяти, отсутствие накладных расходов на создание объектов и безопасность в многопоточном окружении, если бин является stateless.
Ответ 18+ 🔞
А, слушай, вот это вообще классика, про которую все постоянно пиздят, но не все до конца въезжают. Ну, типа, представь: ты написал класс, пометил его @Component и думаешь — о, класс, теперь у меня их будет столько, сколько надо. А Spring такой: «Не, мудила, погоди, я тебе щас объясню, как оно работает на самом деле».
По умолчанию, блядь, Spring создаёт один-единственный экземпляр твоего бина на весь свой контейнер. Это называется singleton, ёпта. И все, кто на него ссылаются через @Autowired, получают в морду одну и ту же ссылку на этот самый объект. Не копию, не новый, а именно ту самую, оригинальную, блядь, сущность.
Вот смотри, как это выглядит в коде, чтоб не быть голословным:
@Component // Вот тут Spring видит эту аннотацию и говорит: "О, так, щас я из этого сделаю ОДНУ штуку на весь свой огород".
public class CommonService {
// ... тут какая-то логика, неважно
}
@Service
public class OrderService {
@Autowired // И вот сюда он подсовывает ссылку на ту самую, единственную CommonService
private CommonService commonService;
}
@Controller
public class UserController {
@Autowired // И сюда ТОЖЕ подсовывает ссылку на ту же самую, блядь, CommonService. Один объект на всех!
private CommonService commonService;
}
Получается, что OrderService и UserController работают с одним и тем же объектом CommonService. Если в одном месте его состояние поменяли — во всех остальных местах оно тоже поменялось, потому что это один и тот же экземпляр в памяти. Вот такая, блядь, магия, а не dependency injection.
Но! — всегда есть это ёбаное «но» — если тебе такая всеобщая коммуналка не нравится, можно изменить поведение. Для этого есть аннотация @Scope, которая как раз и определяет, сколько этих экземпляров будет плодиться:
@Scope("singleton")— это как раз то самое, что стоит по умолчанию. Одна штука на весь контейнер. Экономия памяти, все дела.@Scope("prototype")— а вот это уже интереснее. Тут Spring каждый раз, когда ты просишь этот бин (черезgetBean()или инъекцию), создаёт новый, свеженький экземпляр. Как одноразовые стаканчики — попользовался и выкинул.@Scope("request"),@Scope("session")— это уже для веб-приложений. Здесь бин живёт ровно столько, сколько живёт HTTP-запрос или пользовательская сессия. Умрёт запрос — умрёт и бин. Закроется сессия — и ему пиздец.
А почему, собственно, singleton — дефолт? Да потому что это, блядь, эффективно! Не надо каждый раз тратить ресурсы на создание нового объекта, особенно если он stateless (то есть не хранит никакого состояния, связанного с конкретным запросом или пользователем). Один раз создал — и все им пользуются. И в многопоточке с ним проблем нет, если он, опять же, не тащит в себе какого-то изменяемого состояния на всех. Просто, быстро, надёжно. Ну, почти всегда.