У меня есть класс Service и интерфейс Repository (Spring Data). У меня также есть один абстрактный класс:
public abstract class TestingMethod {
public TestingMethod() {
timeSum = 0;
}
protected long timeSum;
}
И класс, который его расширяет:
@Component
public class LimitTestingMethod extends TestingMethod {
@Autowired
private GeoTestDataRepository geoTestDataRepository;
private final int limitSize;
public LimitTestingMethod(int limitSize) {
super();
this.limitSize = limitSize;
}
}
В моем Service я хочу создать экземпляр LimitTestingMethod и установить его аргумент limitSize.
Что-то вроде:
LimitTestingMethod ltm3 = new LimitTestingMethod(3);
LimitTestingMethod ltm10 = new LimitTestingMethod(10);
Но я получил ошибку:
Описание: Параметр 0 конструктора в Для com.exence.postgiscma.testingMethod.LimitTestingMethod требуется bean-компонент типа 'int', который не может быть найден. Действие: рассмотрите возможность определения bean типа «int» в вашей конфигурации.
Возможно ли добиться того, чего я хочу?
Всего найлучшего!
//РЕДАКТИРОВАТЬ
Как я вижу в комментариях, это плохой подход. Так что, может быть, кто-то даст мне совет, как это лучше спроецировать? Является ли это хорошим решением для передачи репо в качестве аргумента в конструкторе (я думаю, что нет, но я не могу понять, как это сделать лучше)?
LimitTestingMethod ltm3 = new LimitTestingMethod(3, geoTestDataRepository);
Есть ли хорошее и элегантное решение?
Почему вы хотите создать LimitTestingMethod с новым? Может быть, вы можете получить значение limitesSize из файла свойств?




Поскольку вы создаете экземпляры за пределами Spring, ваше текущее решение не будет работать. Ошибка возникает из-за того, что вы аннотировали ее с помощью @Component, она обнаружит ее при запуске и попытается создать bean-компонент, но потерпит неудачу.
Чтобы решить эту проблему, вы можете сделать 1 из 2 вещей.
ApplicationContext в качестве фабрики, предоставляя дополнительные аргументы и делая прототип bean-компонента ограниченным.ApplicationContext.ApplicationContext как фабрикуСначала сделайте свой bean-компонент прототипом, чтобы он мог быть сконструирован при необходимости.
@Component
@Scope(
ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class LimitTestingMethod extends TestingMethod { ... }
Теперь экземпляр не будет создаваться при запуске. В вашем сервисе введите ApplicationContext и используйте метод getBean, чтобы получить желаемый экземпляр.
public class Service {
@Autowired
private ApplicationContext ctx;
public void yourMethod() {
LimitTestingMethod ltm3 = ctx.getBean(LimitTestingMethod.class, 3);
LimitTestingMethod ltm10 = ctx.getBean(LimitTestingMethod.class, 10);
}
}
Это позволит Spring создать экземпляр, используя значение, переданное для конструктора, и выполнить автосвязывание.
Другое решение состоит в том, чтобы вручную создать экземпляры, а затем позволить Spring обрабатывать автоматическую проводку. При этом вы потеряете способности АОП и получите только автосвязь.
Сначала удалите аннотацию @Component из LimitTestingMethod, чтобы она не была обнаружена во время запуска.
public class LimitTestingMethod extends TestingMethod { ... }
Теперь в вашем сервисе автоматически подключите ApplicationContext и после создания вашего bean-компонента используйте его для внедрения зависимостей.
public class Service {
@Autowired
private ApplicationContext ctx;
public void yourMethod() {
LimitTestingMethod ltm3 = new LimitTestingMethod(3);
LimitTestingMethod ltm10 = new LimitTestingMethod(10);
ctx.getAutowireCapableBeanFactory().autowireBean(lmt3);
ctx.getAutowireCapableBeanFactory().autowireBean(lmt10);
}
}
Оба добьются того, чего вы хотите, однако теперь ваш код напрямую зависит от Spring API. Поэтому вместо этого вам, вероятно, лучше выбрать другой вариант, а именно внедрить все для LimitTestingMethod через конструктор и передать репозиторий самостоятельно.
public class LimitTestingMethod extends TestingMethod {
private final GeoTestDataRepository geoTestDataRepository;
private final int limitSize;
public LimitTestingMethod(int limitSize, GeoTestDataRepository geoTestDataRepository) {
this.limitSize=limitSize;
this.geoTestDataRepository=geoTestDataRepository;
}
}
Затем вы можете просто автоматически подключить репозиторий в своем классе обслуживания и создать экземпляры по мере необходимости (или создать фабрику, которая содержит сложность создания этого объекта).
public class Service {
@Autowired
private GeoTestDataRepository repo;
public void yourMethod() {
LimitTestingMethod ltm3 = new LimitTestingMethod(3, repo);
LimitTestingMethod ltm10 = new LimitTestingMethod(10, repo);
}
}
Спасибо за вашу помощь! Я считаю, что вариант 3 не будет элегантным и лучшим решением. Я также думаю, что не должно быть аннотации @Autowired, но это ошибка, которая, вероятно, произошла при копировании кода.
Почему не должно быть autowired? Как еще вы собираетесь заводить репозиторий или ApplicationContext в свой сервис (хотя для последнего можно было бы реализовать ApplicationContextAware, если бы очень хотелось).
Я имею в виду аннотацию @Autowired в методе LimitTestingMethod в последнем примере. Репозиторий передается туда через конструктор.
Основной концепцией Spring является инверсия управления, где контейнер отвечает за создание каждого компонента. Аннотируя класс как
@Component, вы указываете Spring создать экземпляр вашего класса. Однако вы не предоставили каких-либо инструкций по значению, которое должно быть предоставлено для построения bean-компонента. Отсюда и ошибка, какое значение Spring вводить в конструктор.