![](/img/trans.png)
[英]Spring Boot autowire field in singleton service/controller by request scoped bean
[英]Autowire a Spring bean in a Singleton class
我正在嘗試在 Singleton 類中自動裝配一個 bean,我知道避免手動自動裝配總是一個最好的主意,但是這個類在很多地方被使用,所以我不想改變這個類的調用者。
跑步者.java
@Component
public class RunnerClass {
@Autowired
public ConfigService configService;
}
配置服務.java
@Service
public class ConfigService {
private ConfigServiceDAO = ConfigServiceDAO.getInstance();
}
ConfigServiceDAO.java
public class ConfigServiceDAO {
//Bean I want to autowire here....
@Autowired
ConfigServiceDAOBuilder DAOBuilder
public static ConfigServiceDAO getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
public static final ConfigServiceDAO INSTANCE = new ConfigServiceDAO();
private SingletonHolder() {}
}
}
ConfigServiceDAO 中的 DAOBuilder 始終為 null,這是有道理的,因為我的理解是手動實例化類時,不會發生 spring 注入。 如果我想將 ConfigServiceDAO 保留為非彈簧組件,這里的解決方案是什么?
====編輯==== 我知道可以將 ConfigServiceDAO 作為彈簧組件並自動裝配所有依賴項。 但是來自不同包的許多類已經調用 ConfigServiceDAO.getInstance().someMethod() 所以我想正確的問題是,將 spring 組件自動裝配到手動實例化的類的最佳方法是什么。
我不知道您的用例,但您不能在 Spring bean 之外使用@Autowired
注釋。 但是,如果您確實需要從非 Spring 代碼段訪問 Spring bean,則可以像下面那樣進行。 然而,這是設計依賴項的一種非常非 Spring 的方式。
import org.springframework.context.ApplicationContext;
public enum ApplicationContextHolder {
INSTANCE;
private ApplicationContext applicationContext;
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
然后你有一個配置類:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
@Configuration
public class SomeConfig {
@Autowired
private ApplicationContext applicationContext;
@PostConstruct
public void init() {
ApplicationContextHolder.INSTANCE.setApplicationContext(applicationContext);
}
}
然后在您的 DAO 類中,您將獲得對您感興趣的構建器 bean 的引用。 像這樣的東西:
public class ConfigServiceDAO {
public static ConfigServiceDAO getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
public static final ConfigServiceDAO INSTANCE =
ApplicationContextHolder.INSTANCE.getApplicationContext().getBean(ConfigServiceDAOBuilder.class).buildConfigServiceDAO()
private SingletonHolder() {}
}
}
同樣,這是一種非常非 Spring 的做事方式。
Spring 僅在它自己管理的 bean 中處理@Autowired
。 所以你有兩個選擇:
擺脫單例 - 如果您使用的是 spring,它在應用程序上下文中已經是單例了。 這是迄今為止最好的方法(假設調用您的單例的其他應用程序部分也是彈簧驅動的)。 我認為您不應該害怕更改ConfigServiceDAO.getInstance.method()
- IDE 中的重構工具將完成這項工作。
如果你不能做 1,不要在單例中使用自動裝配的注釋 - 無論如何它都沒用,相反,當你配置了應用程序上下文時(例如,在應用程序啟動時 spring 發出的偵聽器中),獲得對ConfigServiceDAOBuilder
bean 通過調用appCtx.getBean(ConfigServiceDAOBuilder.class)
並通過反射手動“注入”,這就是 Spring 對 Spring 管理的 bean 所做的:
@EventListener
public void onApplicationReadyEvent(ApplicationReadyEvent event) {
ConfigServiceDAOBuilder builder =
event.getApplicationContext().getBean(ConfigServiceDAOBuilder.class);
ConfigServiceDao dao = ConfigServiceDAO.getInstance();
dao.setDaoBuilder(builder); // or alternatively by reflection
}
作為旁注,考慮使用setDaoBuilder
方法setDaoBuilder
私有包,以保護單例免受某些意外調用 setter 的影響
據我了解您想要什么:由 Spring ConfigServiceDAOBuilder
創建。 之后將其注入到ConfigServiceDAO
類的非托管對象中。 您可以在實例化 Spring 應用程序上下文后執行此操作。 例如使用CommanLineRunner
:
@Component
public class CommandLineAppStartupRunner implements CommandLineRunner {
@Autowired
ConfigServiceDAOBuilder DAOBuilder
@Override
public void run(String...args) throws Exception {
ConfigServiceDAO.getInstance().init(DAOBuilder);
}
}
在ConfigServiceDAO
中必須是方法init
來幫助注冊所有需要的 bean。
看完你的評論我很困惑,所以讓我這樣說。 您所指的手動自動裝配是 Spring 依賴注入方式。 每當您使用任何具有默認作用域實例的 Spring Stereotype 注釋時,它始終是 Singleton。
您的 ConfigService 類有問題。 您正在混淆事物,您應該使用@configuration 創建一個單獨的配置類並為類 ConfigServiceDAO 創建 Bean,如下所示
@Configuration
Class Config{
@Bean
public ConfigServiceDAO configServiceDAO( ){
return ConfigServiceDAO.getInstance();
}
}
然后在 ConfigService 類中自動裝配 ConfigServiceDAO。 有了這個 Spring 將按正確的順序解決所有依賴項,並且 DAOBuilder 不應該為空。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.