Переменная экземпляра класса Spring Bean Service и проблема с многопоточностью в веб-приложении - PullRequest
1 голос
/ 03 мая 2020

У меня есть веб-приложение на основе Spring 5, где controller вызывает этот класс service и получает текущую зарегистрированную информацию User.

Поскольку объект loggedInUser определен как экземпляр Переменная здесь, создаст ли это состояние гонки, когда несколько пользователей попытаются войти в приложение и получить доступ к страницам со своими учетными данными? Должна ли это быть локальная переменная вместо переменной экземпляра в методе getLoggedInUser()? 1009 *

У меня сложилось впечатление, что Tomcat будет создавать новый поток для каждого запроса HTTP и экземпляра бренда new UserService bean будет создаваться каждый раз, когда поступает запрос, независимо от того, кто обращается к нему.

И как я могу определить, является ли bean, используемый Spring, экземпляром new или singleton ? Есть ли способ проверить это во время выполнения, используя System.out.println() или любую другую методологию / инструмент?

Итак,

User 1 -> new UserController()    -> new UserService() -> welcome.jsp 
User 1 -> new ProductController() -> new ProductService() -> new UserService() -> product.jsp  

User 2 -> new UserController()    -> new UserService() -> welcome.jsp 
User 2 -> new ProductController() -> new ProductService() -> new UserService() -> product.jsp  

UserService. java

@Service
public class UserService {

    private User loggedInUser;

    public User getLoggedInUser(HttpServletRequest request) {
        if (this.loggedInUser != null) {
            return this.loggedInUser;
        }
        this.loggedInUser = (User) session.getAttribute("loggedInUser");
        return loggedInUser;
    }

}       

Ответы [ 2 ]

1 голос
/ 03 мая 2020

Область по умолчанию для Spring bean-компонентов singleton Spring Documentation . Это означает, что будет создан только один экземпляр компонента. Это можно продемонстрировать с помощью следующего фрагмента кода:

@RestController
public class TestController {
    @GetMapping("/test")
    public void test() {
        System.out.println(this);
    }
}

Каждый раз, когда вызывается конечная точка /test, выходные данные будут одинаковыми, что-то вроде этого:

com.example.TestController@17870d99
com.example.TestController@17870d99
com.example.TestController@17870d99

Использование с другой областью действия (например, request scope), запустив следующий код:

@RestController
@Scope(value = WebApplicationContext.SCOPE_SESSION)
public class TestController {
    @GetMapping("/test")
    public void test() {
        System.out.println(this);
    }
}

мы получим следующий вывод:

com.example.TestController@3213427f
com.example.TestController@2318434f
com.example.TestController@5e0df012

Мы видим, что контроллер создается с каждым сеансом (в нашем случае с каждым вызовом /test конечной точки).

Теперь не рекомендуется использовать переменную экземпляра в одноэлементном бине, поскольку это будет иметь непредвиденные последствия ( как условия гонки или утечка несанкционированных данных). Если мы хотим использовать переменную экземпляра, мы должны использовать соответствующую область видимости для компонента.

Или вообще избегать переменных экземпляра.

1 голос
/ 03 мая 2020

Spring Io C контейнер создаст UserService один раз и внедрит зависимость, где он используется, если это Singleton, что по умолчанию.

Вы можете использовать VisualVM взять отвал и проанализировать.

И изменение loggedInUser на ThreadLocal может помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...