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

Стоит ли по умолчанию Prototype?

2.0 Middle🔥 141 комментариев
#Spring Boot и Spring Data#Spring Framework

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

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

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

Область видимости Prototype в Spring: Разбор

Нет, по умолчанию в Spring используется область видимости Singleton, а не Prototype. Это критически важное различие для собеседования и правильной архитектуры приложения.

Области видимости бинов

Spring предоставляет несколько встроенных scopes:

1. Singleton (по умолчанию)

  • Создаётся один раз при инициализации контекста Spring
  • Переиспользуется для всех инъекций
  • Thread-safe требует внимания разработчика
  • Идеален для stateless сервисов, репозиториев
@Service  // По умолчанию Singleton
public class UserService {
    // Один экземпляр на всё приложение
}

2. Prototype

  • Создаётся новый экземпляр при каждой инъекции
  • Stateful объекты могут быть использованы
  • Не управляется Spring после создания — ответственность за cleanup на разработчике
  • Медленнее Singleton из-за создания объектов
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class RequestContext {
    // Новый экземпляр каждый раз
    private String userId;
    private Map<String, Object> data = new HashMap<>();
}

3. Request (только в web контексте)

  • Новый бин для каждого HTTP запроса
  • Автоматически очищается после запроса
  • Perfect для request-scoped объектов
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestLogger {
    // Один экземпляр на request
}

4. Session (только в web контексте)

  • Один бин на сессию пользователя
  • Для данных пользовательской сессии

5. Application (сервлет контекст)

  • На уровне ServletContext
  • Редко используется

Почему Singleton по умолчанию?

  1. Производительность — создание объектов дорого
  2. Простота — обычно сервисы stateless
  3. Экономия памяти — один объект на много потребителей
  4. Кэширование — Singleton можно кэшировать агрессивнее

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

// ✅ ХОРОШО: Stateful объект
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ReportGenerator {
    private List<String> lines = new ArrayList<>();
    private int pageCount = 0;
    
    public void addLine(String line) {
        lines.add(line);
    }
}

// ❌ ПЛОХО: Singleton со state
@Service  // Singleton!
public class BadService {
    private List<String> cache = new ArrayList<>();  // Shared state!
}

Опасность Singleton со статом

@Service  // Singleton
public class UserProcessor {
    private User currentUser;  // ❌ ОПАСНО: shared state
    
    public void process(User user) {
        this.currentUser = user;  // Race condition!
        Thread.sleep(1000);
        saveUser(currentUser);  // Может быть другой user!
    }
}

Решение:

@Service
public class UserProcessor {
    public void process(User user) {
        // user передаётся как параметр — thread-safe
        saveUser(user);
    }
}

Проблема: Singleton инъектирует Prototype

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class RequestData {
}

@Service  // Singleton
public class MyService {
    @Autowired
    private RequestData data;  // ❌ Инъектируется ОДИН раз!
}

Решение 1: Lookup method injection

@Service
public class MyService {
    @Lookup
    public RequestData createRequestData() {
        return null;  // Spring переопределит
    }
}

Решение 2: ObjectFactory

@Service
public class MyService {
    @Autowired
    private ObjectFactory<RequestData> dataFactory;
    
    public void process() {
        RequestData data = dataFactory.getObject();  // Новый каждый раз
    }
}

Решение 3: Scoped proxy

@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, 
       proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestData {
}

@Service
public class MyService {
    @Autowired
    private RequestData data;  // ✅ Прокси создаёт новые
}

Best Practices

  1. По умолчанию используй Singleton для сервисов и репозиториев
  2. Избегай state в Singleton бинах — используй parameters методов
  3. Используй Prototype для stateful объектов
  4. Используй @Scope(SCOPE_REQUEST) в веб контексте вместо Prototype
  5. Помни про проблему "Singleton инъектирует Prototype" — используй ObjectFactory или @Lookup

На собеседовании ожидают

  • Уверенный ответ: "По умолчанию Singleton"
  • Объяснение различий scopes
  • Понимание thread-safety проблем
  • Знание решений для Singleton инъектирующего Prototype