簡體   English   中英

Spring Boot @ComponentScan 無法通過多模塊項目中的自定義注釋工作

[英]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 應用程序
    • 包含 @SpringBootApplication 和所有其他需要的依賴項(Web、Feign 等)
  • :common:es-model : 包含 Spring Data Elasticsearch 的模型 + 存儲庫
    • 僅包含“spring-boot-starter-data-elasticsearch”依賴項(無 @SpringBootApplication)

假設我在: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] 都不起作用。 找到類( EnableDocumentModelDocumentConfiguration )並且應用程序嘗試啟動,但失敗並出現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],使用來自AnalyzerApplicationDocumentConfiguration的相同@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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM