← Назад к вопросам
В чем разница между Session и Global Session?
2.3 Middle🔥 81 комментариев
#ORM и Hibernate#Spring Framework
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Session vs Global Session в Spring Beans
Контекст
Это вопрос про scope-ы бинов в Spring Framework. В веб-приложениях доступны несколько scope-ов для определения жизненного цикла бина.
Session Scope
Назначение: бин создаётся и существует в рамках одной HTTP Session.
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserSession {
private String username;
private LocalDateTime loginTime;
public UserSession() {
System.out.println("UserSession bean created");
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
Характеристики:
- Один бин на одну HTTP Session
- Создаётся при первом обращении в сессии
- Уничтожается при invalidate сессии
- Может быть разным для разных пользователей
- Данные не передаются между браузерами
Пример использования:
@Controller
public class LoginController {
@Autowired
private UserSession userSession; // Бин из текущей сессии
@PostMapping("/login")
public String login(@RequestParam String username, HttpSession session) {
userSession.setUsername(username);
userSession.setLoginTime(LocalDateTime.now());
return "redirect:/dashboard";
}
@GetMapping("/profile")
public String profile(Model model) {
// Получим ТОТ ЖЕ объект UserSession, что и при login
model.addAttribute("username", userSession.getUsername());
return "profile";
}
}
Как работает:
- Пользователь A открывает сайт → создаётся Session A → создаётся UserSession bean (экземпляр A)
- Пользователь B открывает сайт → создаётся Session B → создаётся UserSession bean (экземпляр B)
- Пользователь A и B имеют разные экземпляры UserSession
- Данные A не видны для B
Global Session Scope
Назначение: бин существует в рамках Global Session (используется в Portlet приложениях, очень редко).
@Component
@Scope(value = "globalSession", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class PortalGlobalData {
private String sharedData;
public PortalGlobalData() {
System.out.println("PortalGlobalData bean created");
}
}
Характеристики:
- Один бин на одного пользователя портала
- Используется ТОЛЬКО в Portlet приложениях (очень редко в production)
- В обычных Servlet приложениях ведёт себя как
sessionscope - PortletSession имеет два уровня видимости: APPLICATION_SCOPE и PORTLET_SCOPE
- Global Session — это APPLICATION_SCOPE в portlet терминологии
Пример использования (Portlet):
// В Portlet приложении (portal.liferay.com или подобное)
@Component
@Scope(value = "globalSession", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class PortalUserPreferences {
private String theme; // Выбранная тема на уровне портала
private String language; // Язык портала
// Доступно всем портлетам в приложении
public String getTheme() {
return theme;
}
}
Детальное сравнение
| Аспект | Session | Global Session |
|---|---|---|
| Область видимости | Одна HTTP Session | Одна Global Session (Portlet) |
| Создание | При первом доступе | При первом доступе |
| Уничтожение | При invalidate сессии | При выхода из портала |
| Использование | Обычные веб-приложения | Portlet приложения (редко) |
| Количество экземпляров | Один на пользователя | Один на пользователя портала |
| Совместное использование | Между контроллерами одной сессии | Между всеми портлетами |
| Реальное применение | ~80% session-based приложений | < 5% (legacy portals) |
| В servlet приложении | Работает как задумано | Ведёт себя как session |
Практические сценарии
Session Scope — реальный пример
Шоппинг-карзина
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ShoppingCart {
private List<CartItem> items = new ArrayList<>();
public void addItem(CartItem item) {
items.add(item);
}
public List<CartItem> getItems() {
return items;
}
public void clear() {
items.clear();
}
}
@RestController
@RequestMapping("/api/cart")
public class CartController {
@Autowired
private ShoppingCart cart; // Разный для каждого пользователя
@PostMapping("/add")
public void addItem(@RequestBody CartItem item) {
cart.addItem(item); // Добавит в корзину текущего пользователя
}
@GetMapping("/items")
public List<CartItem> getItems() {
return cart.getItems(); // Вернёт только товары текущего пользователя
}
@PostMapping("/checkout")
public Order checkout() {
Order order = new Order(cart.getItems());
cart.clear(); // Очистить корзину текущего пользователя
return order;
}
}
Сценарий:
1. Пользователь A открывает сайт (Session A создана)
2. Пользователь A добавляет товары в корзину
3. Пользователь B одновременно открывает сайт (Session B создана)
4. Пользователь B добавляет товары в корзину
5. Корзина A != Корзина B (разные экземпляры ShoppingCart)
6. Пользователь A не видит товары B
Global Session — портал (редко)
// Portlet контекст (IBM Portal, Liferay)
@Component
@Scope(value = "globalSession", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class CompanySettings {
private String companyName; // Доступна всем портлетам компании
private String logo; // Общее лого
private String theme; // Общая тема
}
// Портлет 1
@Controller
public class SalesPortlet {
@Autowired
private CompanySettings settings;
@GetMapping("/sales")
public String view() {
String logo = settings.getLogo(); // Общее для всех портлетов
return "sales";
}
}
// Портлет 2
@Controller
public class HRPortlet {
@Autowired
private CompanySettings settings;
@GetMapping("/hr")
public String view() {
String logo = settings.getLogo(); // ТОТ ЖЕ объект
return "hr";
}
}
Важное примечание про Proxy Mode
Зачем proxyMode = ScopedProxyMode.TARGET_CLASS?
Session-scoped бины нельзя внедрить прямо в singleton бин.
// ❌ Ошибка! Singleton пытается внедрить session-scoped бин
@Service
public class OrderService {
@Autowired
private ShoppingCart cart; // BeanCreationException
}
// ✅ Правильно! Используем proxy
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ShoppingCart {
// Proxy будет выбирать правильный экземпляр в зависимости от текущей сессии
}
Как работает proxy:
- Spring создаёт CGLIB proxy объект
- Каждый раз, когда вызывается метод, proxy определяет текущую сессию
- Находит (или создаёт) правильный экземпляр бина для этой сессии
- Делегирует вызов реальному объекту
Другие scope-ы для сравнения
// Singleton (по умолчанию)
@Component
public class ApplicationConfig {
// Один экземпляр на всё приложение
}
// Prototype
@Component
@Scope("prototype")
public class NewObject {
// Новый экземпляр при каждом внедрении
}
// Request
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestData {
// Один экземпляр на один HTTP запрос
}
// Session
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserSession {
// Один экземпляр на одну HTTP сессию
}
// Application (глобальный для приложения)
@Component
@Scope(value = "application", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ApplicationData {
// Один экземпляр на всё веб-приложение
}
Когда использовать Session
✅ Используй Session scope:
- Для данных пользователя (корзина покупок)
- Для user-specific настроек
- Для кэширования пользовательских данных
- Для временных данных в рамках сессии
❌ Не используй Session scope:
- Для shared данных (используй application scope или кэш)
- Для тяжёлых объектов (используй lazy loading)
- Если data нужна в async потоках (может быть undefined)
Когда использовать Global Session
⚠️ Global Session используется редко:
- Только в Portlet приложениях (IBM Portal, Liferay)
- Для data общей между портлетами
- В обычных Servlet приложениях лучше использовать
applicationscope
Заключение
- Session — один бин на одного пользователя в рамках одной HTTP сессии, основной scope для веб-приложений
- Global Session — один бин на одного пользователя портала, используется редко в Portlet приложениях
- В обычных веб-приложениях Global Session ведёт себя как Session
- Используй
proxyMode = ScopedProxyMode.TARGET_CLASSпри внедрении session-scoped бинов в singleton