簡體   English   中英

在 Singleton 類中自動裝配 Spring 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 所以你有兩個選擇:

  1. 擺脫單例 - 如果您使用的是 spring,它在應用程序上下文中已經是單例了。 這是迄今為止最好的方法(假設調用您的單例的其他應用程序部分也是彈簧驅動的)。 我認為您不應該害怕更改ConfigServiceDAO.getInstance.method() - IDE 中的重構工具將完成這項工作。

  2. 如果你不能做 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.

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