У меня есть приложение Spring Boot, которое использует Spring Data и JPA. Итак, я написал классы репозитория (фактически интерфейсы) для объектов данных, и у меня есть @Service
s, чтобы предоставить средства для работы с данными.
У меня возникла проблема, когда я не могу понять, как внедрить репозиторий в класс обслуживания. При других обстоятельствах я бы написал класс @Configuration
с определением @Bean
, чтобы предоставить элемент, который необходимо внедрить.
Здесь это не работает, потому что я не внедряю экземпляр класса, а вместо этого нуждаюсь в какой-то реализации интерфейса Repository
.
Я использовал эту технику в приложении Vaadin Spring Boot, которое имеет встроенную поддержку для идентификации, создания/генерации и внедрения того, что необходимо. Для базовых операций нет необходимости создавать какой-либо класс реализации.
Он работает очень хорошо, но у меня его нет. Я не хочу делать приложение приложением Vaadin только для того, чтобы получить качество внедрения в репозиторий. Как я могу это сделать?
Обновлять:
Я пробовал то, что было предложено, но до сих пор нет кости. Должно быть что-то фундаментальное, чего мне не хватает.
Вот несколько фрагментов:
AppConfig.java:
@Configuration
public class AppConfig {
@Bean
public TaskMasterService tmService(final TaskMasterRepository repo) {
return new TaskMasterService(repo);
}
// Other @Bean definitions
}
DataIngester.java: («основной»)
@SpringBootApplication
public class DataIngester {
public static void main(String[] args) {
SpringApplication.run(DataIngester.class, args);
}
}
IngesterRunner.java:
@Component
public class IngesterRunner implements CommandLineRunner {
private TaskMasterService tmService;
private TaskRelationshipService trService;
private VariantDetailService vdService;
@Autowired
public IngesterRunner(TaskMasterService tmService, TaskRelationshipService trService,
VariantDetailService vdService) {
this.tmService = tmService;
this.trService = trService;
this.vdService = vdService;
}
@Override
public void run(String... args) throws Exception {
...
}
}
ТаскМастерСервис.java:
@Service
@Transactional
public class TaskMasterService {
private final TaskMasterRepository repo;
@Autowired
public TaskMasterService(TaskMasterRepository repo) {
this.repo = repo;
}
...
}
TaskMasterRepository.java:
@Repository
public interface TaskMasterRepository extends JpaRepository<TaskMaster, Long> {
}
Вывод консоли:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ / _` | \ \ \ \
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.3.RELEASE)
2020-12-23 07:31:12.972 INFO workstation --- [ restartedMain] c.f.e.i.DataIngester : Starting DataIngester on workstation with PID 23800 (C:\Users\jgagnon\workspace\java\e1-task-info2\target\classes started by jgagnon in C:\Users\jgagnon\workspace\java\e1-task-info2)
2020-12-23 07:31:12.975 INFO workstation --- [ restartedMain] c.f.e.i.DataIngester : No active profile set, falling back to default profiles: default
2020-12-23 07:31:13.007 INFO workstation --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2020-12-23 07:31:13.364 INFO workstation --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFERRED mode.
2020-12-23 07:31:13.382 INFO workstation --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 11ms. Found 0 JPA repository interfaces.
2020-12-23 07:31:13.636 INFO workstation --- [ restartedMain] o.s.s.c.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-12-23 07:31:13.661 WARN workstation --- [ restartedMain] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ingesterRunner' defined in file [C:\Users\jgagnon\workspace\java\e1-task-info2\target\classes\com\mycompany\app\ingest\IngesterRunner.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.mycompany.app.backend.service.TaskMasterService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
2020-12-23 07:31:13.661 INFO workstation --- [ restartedMain] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2020-12-23 07:31:13.668 INFO workstation --- [ task-1] o.h.j.i.u.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
2020-12-23 07:31:13.713 INFO workstation --- [ task-1] o.h.Version : HHH000412: Hibernate ORM core version 5.4.20.Final
2020-12-23 07:31:13.838 INFO workstation --- [ task-1] o.h.a.c.Version : HCANN000001: Hibernate Commons Annotations {5.1.0.Final}
2020-12-23 07:31:13.937 INFO workstation --- [ task-1] c.z.h.HikariDataSource : HikariPool-1 - Starting...
2020-12-23 07:31:14.112 INFO workstation --- [ task-1] c.z.h.HikariDataSource : HikariPool-1 - Start completed.
2020-12-23 07:31:14.128 INFO workstation --- [ task-1] o.h.d.Dialect : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
2020-12-23 07:31:14.342 INFO workstation --- [ task-1] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2020-12-23 07:31:14.348 INFO workstation --- [ task-1] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
Exception in thread "task-2" 2020-12-23 07:31:14.352 INFO workstation --- [ restartedMain] o.s.s.c.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
2020-12-23 07:31:14.353 INFO workstation --- [ restartedMain] c.z.h.HikariDataSource : HikariPool-1 - Shutdown initiated...
org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean with name 'springApplicationAdminRegistrar': Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:212)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
at org.springframework.context.event.AbstractApplicationEventMulticaster.retrieveApplicationListeners(AbstractApplicationEventMulticaster.java:245)
at org.springframework.context.event.AbstractApplicationEventMulticaster.getApplicationListeners(AbstractApplicationEventMulticaster.java:197)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:134)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:404)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:361)
at org.springframework.boot.autoconfigure.orm.jpa.DataSourceInitializedPublisher.publishEventIfRequired(DataSourceInitializedPublisher.java:99)
at org.springframework.boot.autoconfigure.orm.jpa.DataSourceInitializedPublisher.access$100(DataSourceInitializedPublisher.java:50)
at org.springframework.boot.autoconfigure.orm.jpa.DataSourceInitializedPublisher$DataSourceSchemaCreatedPublisher.lambda$postProcessEntityManagerFactory$0(DataSourceInitializedPublisher.java:200)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
at java.base/java.lang.Thread.run(Thread.java:832)
2020-12-23 07:31:14.379 INFO workstation --- [ restartedMain] c.z.h.HikariDataSource : HikariPool-1 - Shutdown completed.
2020-12-23 07:31:14.384 INFO workstation --- [ restartedMain] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-12-23 07:31:14.503 ERROR workstation --- [ restartedMain] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.mycompany.app.ingest.IngesterRunner required a bean of type 'com.mycompany.app.backend.service.TaskMasterService' that could not be found.
Action:
Consider defining a bean of type 'com.mycompany.app.backend.service.TaskMasterService' in your configuration.
Он должен работать из коробки.
@Component
public class MyService {
private final MyRepository myRepository;
public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
}
Или версия с дополнительным классом конфигурации:
public class MyService {
private final MyRepository myRepository;
public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
}
@Configuration
public class MyConfiguration {
@Bean MyService myService(MyRepository myRepository) {
return new MyService(myRepository);
}
}
Автоматически подключайте свои репозитории, как и любую другую зависимость (также известную как spring bean):
@Repository
public interface YourRepository extends CrudRepository<YourEntity, String> {
// …
}
@Service
public class YourService {
private final YourRepository repo;
@Autowired
public YourService(final YourRepository repo) {
this.repo = repo;
}
public Object method() {
// use your dependency:
this.repo.findById(…);
}
}
Простое решение: переместите «основной» класс в «корень» исходного пути. У меня он был в пакете. [фейспалм]
Конечно, все ваши сервисы и репозитории должны быть обнаружены сканированием компонентов или конфигурацией ;)
Аннотируйте класс репозитория с помощью
@Repository
и внедрите его с помощью@Autowire
в аннотированный класс@Service
.