Я хотел поиграть с различными типами областей действия bean-компонентов. Поэтому я написал тестовую среду, которая должна генерировать случайное число, чтобы я мог видеть, изменился ли компонент. Моя тестовая установка не работает, и я не могу объяснить, что я обнаружил.
Я использую Spring Boot 2.13 с Spring Framework 5.15.
Следующая настройка:
Основной класс:
package domain.webcreator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WebcreatorApplication {
public static void main(String[] args) {
SpringApplication.run(WebcreatorApplication.class, args);
}
}
Класс фасоли:
package domain.webcreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Random;
@Configuration
public class Beans {
@Bean
public Random randomGenerator() {
return new Random();
}
}
Класс области видимости:
package domain.webcreator;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import java.util.Random;
@Service
@Scope("singleton")
public class Scoper {
private Random rand;
public Scoper(Random rand) {
this.rand = rand;
}
public int getNumber(int max) {
return rand.nextInt(max);
}
}
Контроллер индекса
package domain.webcreator.controller;
import domain.webcreator.Scoper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class IndexController {
@GetMapping("/")
@ResponseBody
@Autowired
public String indexAction(Scoper scoper) {
return String.valueOf(scoper.getNumber(50));
}
}
Моя проблема в том, что я получаю NPE при вызове scoper.getNumber (50).
Это странно, потому что при отладке генерируется bean-компонент Random и передается в конструктор области видимости.
Позже в контроллере свойство rand равно null.


Что я делаю неправильно?




Вы пытаетесь применить @Autowired к случайному методу, а Spring работает иначе. Параметры метода контроллера предназначены для информации, специфичной для этого HTTP-запроса, а не для общих зависимостей, поэтому Spring пытается создать новый Scoper, связанный с запросом, но у него нет входящих значений в запросе для заполнения. (Я действительно удивлен, что вы не получаете сообщение об отсутствии конструктора по умолчанию.)
Вместо этого передайте свой Scoper в конструкторе.
@RestController
public class IndexController {
private final Scoper scoper;
public IndexController(Scoper scoper) {
this.scoper = scoper;
}
@GetMapping("/")
public String indexAction(Scoper scoper) {
return String.valueOf(scoper.getNumber(50));
}
}
Пара замечаний:
@RestController предпочтительнее повторения @ResponseBody, если у вас нет смешанного класса контроллера.
Спасибо, очень полезно. Я читал об этом некоторое время назад, но я не мог вспомнить это, чувствуя себя немного глупо сейчас. Если другие наткнутся на это, здесь вы можете найти поддерживаемые аргументы метода @Controller: docs.spring.io/spring/docs/5.1.5.RELEASE/…