I have a multi module project (gradle) with following structure:
Root project 'mp-search'
+--- Project ':analyzer'
+--- Project ':common'
| \--- Project ':common:es-model'
...
Description:
:analyzer
: contains a spring boot application
:common:es-model
: contains models + repositories for Spring Data Elasticsearch
Say I have the following classes in :common:es-model
with package com.example.esmodel.document.model
:
package com.example.esmodel.document.model;
//imports
@org.springframework.data.elasticsearch.annotations.Document(indexName = "document")
public class Document {
@Id
private String documentId;
@Field
private String content;
// Getter + Setter + Constructor
}
package com.example.esmodel.document.repository;
// imports
@Repository
public interface DocumentRepository extends ElasticsearchRepository<Document, String> {
}
Furthermore I created a configuration class with @ComponentScan
to find them
package com.example.esmodel.document.configuration;
// Imports
@Configuration
@ComponentScan(basePackages = "com.example.esmodel.document")
public class DocumentConfiguration {
}
And an custom annotation for simple inclusion in the application which imports the configuration:
package com.example.esmodel.document;
//Imports
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(DocumentConfiguration.class)
public @interface EnableDocumentModel {
}
I want to use the DocumentRepository
in a controller in my application project ( :analyzer
). So I want to include it via the EnableDocumentModel
annotation like this:
package com.example.analyzer;
import com.example.esmodel.document.EnableDocumentModel;
// Other imports
@SpringBootApplication
@EnableFeignClients
@EnableDocumentModel // [1]
//@Import(DocumentConfiguration.class) // [2]
//@ComponentScan(basePackages = "com.example.esmodel.document") // [3]
public class AnalyzerApplication {
public static void main(String[] args) {
SpringApplication.run(AnalyzerApplication.class, args);
}
}
Of these three tests [1] and [2] are not working. The classes ( EnableDocumentModel
, DocumentConfiguration
) are found and application tries to start, but fails with a UnsatisfiedDependencyException
:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.example.analyzer.controller.DocumentController required a bean of type 'com.example.esmodel.document.repository.DocumentRepository' that could not be found.
But test [3], using the same @ComponentScan(basePackages = "com.example.esmodel.document")
from DocumentConfiguration
in the AnalyzerApplication
, works fine. But this is not what I desire.
Do I miss something? Any ideas?
Thanks in advance!
Edit :
Just to make sure the DocumentConfiguration
is considered by spring at all, I added @Import(DocumentRepository.class)
in DocumentConfiguration
, but it throws an BeanInstantiationException
because it's an interface (which is of course reasonable).
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.esmodel.document.repository.DocumentRepository]: Specified class is an interface
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:70) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1326) ~[spring-beans-5.3.19.jar:5.3.19]
... 31 common frames omitted
So Spring definitely considers DocumentConfiguration
otherwise the exception wouldn't be thrown. So somehow the configuration is considered, but @ComponentScan(basePackages = "de.sva.medpower.esmodel.document")
doesn't do its job...
I also found a tutorial on medium ( https://medium.com/trendyol-tech/how-to-write-a-spring-boot-library-project-7064e831b63b ) doing it that way, but somehow it doesn't work for me..
@ComponentScan
does not trigger Spring Data repository initialization. You'd need an @EnableElasticsearchRepositories
somewhere in your configuration (ideally on a class in the package that you'd want to scan for ES repositories).
This is even activated automatically if Boot finds Spring Data Elasticsearch on the execution classpath, but in your case doesn't show any effect as the application's root package is com.example.analyzer
(the package that your @SprignBootApplication
class resides in).
Annotating DocumentConfiguration
with @EnableElasticsearchRepositories
and point that to the packages that the ES repositories reside in should fix the issue.
Spring is just a framework, meaning it has some rules based on which it will just parse the code you have written, and convert it into some other code to have more functionalities avoiding boileplate code.
The point however is that spring has some rules based on which it reads your code and makes the conversion.
One of those rules for Spring Boot
is that it begins it's search from the package that has the class with the annotation @SpringBootApplication
and then automatically scans all other nested packages under the package where this class has been found.
So by moving the @ComponentScan
outside this default path that the framework will start searching for usuful metadata, you are actually hiding this meta information from spring.
Also by creating your own annotation @EnableDocumentModel
, you are not changing how spring is parsing the code of your project. So even if with your custom annotation you point to some other class, java annotations will be considered by java compiler and not by spring framework when doing the parsing.
You have to place @ComponentScan
somewhere, where by default the framework will initially search and when it catches this metadata, it will be able to continue the search in some other packages as well. But this information contained in @ComponentScan
must be in the default path that spring framework searches, meaning the package where the @SpringBootApplication
is to be found or some other nested to this package.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.