[英]Spring ComponentScan excludeFilters annotation not working in Spring Boot Test context
[英]Spring Boot @ComponentScan not working via custom annotation in multi module project
我有一個具有以下結構的多模塊項目(gradle):
Root project 'mp-search'
+--- Project ':analyzer'
+--- Project ':common'
| \--- Project ':common:es-model'
...
描述:
:analyzer
: 包含一個 Spring Boot 應用程序
:common:es-model
: 包含 Spring Data Elasticsearch 的模型 + 存儲庫
假設我在:common:es-model
中有以下類,包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> {
}
此外,我使用@ComponentScan
創建了一個配置類來找到它們
package com.example.esmodel.document.configuration;
// Imports
@Configuration
@ComponentScan(basePackages = "com.example.esmodel.document")
public class DocumentConfiguration {
}
還有一個自定義注釋,用於簡單地包含在導入配置的應用程序中:
package com.example.esmodel.document;
//Imports
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(DocumentConfiguration.class)
public @interface EnableDocumentModel {
}
我想在我的應用程序項目( :analyzer
)的控制器中使用DocumentRepository
。 所以我想通過這樣的EnableDocumentModel
注釋包含它:
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);
}
}
這三個測試 [1] 和 [2] 都不起作用。 找到類( EnableDocumentModel
、 DocumentConfiguration
)並且應用程序嘗試啟動,但失敗並出現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.
但是測試 [3],使用來自AnalyzerApplication
中DocumentConfiguration
的相同@ComponentScan(basePackages = "com.example.esmodel.document")
工作正常。 但這不是我想要的。
我錯過了什么嗎? 有任何想法嗎?
提前致謝!
編輯:
只是為了確保 Spring 完全考慮DocumentConfiguration
,我在DocumentConfiguration
中添加了@Import(DocumentRepository.class)
,但它拋出了BeanInstantiationException
因為它是一個接口(這當然是合理的)。
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
所以 Spring 肯定會考慮DocumentConfiguration
否則不會拋出異常。 所以以某種方式考慮了配置,但@ComponentScan(basePackages = "de.sva.medpower.esmodel.document")
沒有完成它的工作......
我還找到了一個關於媒體的教程( https://medium.com/trendyol-tech/how-to-write-a-spring-boot-library-project-7064e831b63b )這樣做,但不知何故它不起作用為了我..
@ComponentScan
不會觸發 Spring Data 存儲庫初始化。 您需要在配置中的某處有一個@EnableElasticsearchRepositories
(理想情況下,在您想要掃描 ES 存儲庫的包中的一個類上)。
如果 Boot 在執行類路徑上找到 Spring Data Elasticsearch,這甚至會自動激活,但在您的情況下,它不會顯示任何效果,因為應用程序的根包是com.example.analyzer
(您的@SprignBootApplication
類所在的包)。
使用@EnableElasticsearchRepositories
注釋DocumentConfiguration
並將其指向 ES 存儲庫所在的包應該可以解決問題。
Spring 只是一個框架,這意味着它有一些規則,它會根據這些規則解析您編寫的代碼,並將其轉換為其他代碼以具有更多功能,從而避免樣板代碼。
然而,重點是 spring 有一些規則,它會根據這些規則讀取您的代碼並進行轉換。
Spring Boot
的其中一個規則是,它從具有注釋@SpringBootApplication
的類的包開始搜索,然后自動掃描找到該類的包下的所有其他嵌套包。
因此,通過將@ComponentScan
移到框架將開始搜索常用元數據的默認路徑之外,您實際上是在向 spring 隱藏此元信息。
此外,通過創建自己的注釋@EnableDocumentModel
,您不會改變 spring 解析項目代碼的方式。 因此,即使使用自定義注釋指向其他類,java 編譯器也會在解析時考慮 java 注釋,而不是 Spring 框架。
您必須將@ComponentScan
放置在某個地方,默認情況下框架將在該位置進行初始搜索,當它捕獲此元數據時,它也能夠繼續在其他一些包中進行搜索。 但是@ComponentScan
中包含的這些信息必須在 spring 框架搜索的默認路徑中,這意味着要找到@SpringBootApplication
的包或其他嵌套到該包的包。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.