2017-04-12 112 views
13

我正在開發一個基於Spring的應用程序,它註冊了一個自定義作用域「任務」。這個想法是,當一個新任務開始時,Spring應該提供任務範圍的對象。Spring - 運行時註冊scoped bean

該任務在運行時實例化。它以一個Properties對象的形式提供了一些配置。我想用ApplicationContext註冊該對象,但在任務範圍內,以便該範圍內的所有bean都可以引用該特定任務的配置。

下面是在代碼中粗略的想法:

public class MyTask extends SourceTask { 
    @Override 
    public void start(Map<String, String> props) { 
     context = ContextProvider.getApplicationContext(); 
     // Initialize the scope 
     ConnectorTaskScope scope = context.getBean(ConnectorTaskScope.class); 
     scope.startNewTask(); 

     // TODO register the props object in the context 

     // get an object which requires the properties and work with it 
     context.getBean(SomeScopedBean.class);   
    } 
} 

我想不通我怎麼能註冊在ApplicationContext一個bean是適當的作用域。

謝謝

更新:

下面是一些更多的代碼來解釋這個問題好一點。 SomeScopedBean應該做與配置的東西它提供豆,看起來是這樣的:

public class SomeScopedBean { 
    @Autowire 
    public SomeScopedBean (Properties configuration) { 
     // do some work with the configuration 
    } 
} 

應用程序的想法是,它應該有不同的配置下運行的MyTask多個實例,每個任務本身就是範圍。在每個任務的範圍內,應該有1個SomeScopedBean實例用任務的配置進行初始化。

public class MyApplication { 
    public static void main (String[] args) { 
     // ... 
     Properties config1 = loadConfiguration1(); 
     Properties config2 = loadConfiguration2(); 
     MyTask task1 = new MyTask(); 
     MyTask task2 = new MyTask(); 
     task1.start(config1); 
     task2.start(config2); 
     // ... 
    } 
} 
+2

http://memorynotfound.com/spring-custom-scope-creating-and-implementing-threadscope/ – StanislavL

+1

@StanislavL,我已經得到了實現的定製範圍,它工作正常。問題是如何在運行時註冊一個scoped bean。 – artemb

+0

您是否嘗試過使用'scope = prototype'來創建類的新實例,無論它被注入到哪裏? –

回答

2

如果我把你最後的評論:

我想要的是讓每個範圍 (每個MyTask內)SomeScopedBean的1個實例,但每個不同的配置配置種性質(其由部署框架設置時,它 實例化的每個任務,

尤其within each MyTask並且如果它被限制爲MyTask

您可以:

  • 定義SomeScopedBean爲原型豆
  • 創建一個工廠@Configuration將實例SomeScopedBean與所提供的屬性配置

首先配置:

@Configuration 
public class SomeScopedBeanFactoryConfiguration { 

    @Bean 
    @Scope(BeanDefinition.SCOPE_PROTOTYPE) 
    public SomeScopedBean create(Properties configuration) { 
     return new SomeScopedBean(configuration); 
    } 

} 

然後自動裝配的SomeScopedBeanFactoryConfigurationMyTask,並創建SomeScopedBean

public class MyTask extends SourceTask { 

    @Autowired 
    private SomeScopedBeanFactoryConfiguration someScopedBeanFactoryConfiguration; 

    @Override 
    public void start(Map<String, String> props) { 
     SomeScopedBean scopedBean = someScopedBeanFactoryConfiguration.create(props);  
    } 
} 

注:如果SomeScopedBean必須在一個以上的豆被注入與task/thread範圍,你可以在其範圍更改爲線程範圍一個如:

@Bean 
    @Scope("thread") 
    public SomeScopedBean create(Properties configuration) { 
     return new SomeScopedBean(configuration); 
    } 
+0

這看起來很有希望。我想知道在同一個(「任務」)範圍內的其他bean是否可以要求SomeScopedBean並且提供正確配置的實例。我會試試 – artemb

+0

如果你將'SomeScopedBean'的範圍設置爲你的'任務'範圍而不是'原型'範圍,那麼應該這樣做 –

+0

是的!這正是我想要的!一個但不直觀的設置,但工作正如我想要的!謝謝 – artemb

2
AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory(); 

MyTask instance = new MyTask(); 
beanFactory.autowireBean(instance); 
beanFactory.initializeBean(instance, MyTask.class.getCanonicalName()); 

//for singleton I used 
((ConfigurableListableBeanFactory)beanFactory).registerSingleton(MyTask.class.getCanonicalName(), instance); 

在你的情況我會註冊MyTask代理的單。代理可以保留所有與範圍有關的實例(例如在Map或ThreadLocal存儲中)以及調用委託邏輯,以從Map中更正一個實例。

更新: 實際上,您自動裝載的不是MyTask bean,而是代理服務器。代理包裝所有MyTask方法。代理與MyTask具有相同的界面。假設你調用ProxyMyTask.do()方法。代理攔截呼叫,獲得某種程度上的範圍,例如,當前線程是Tread Scope示例,並從Map(或ThreadLocal存儲的線程範圍)中獲取適當的MyTask實例。最後調用找到MyTask實例的DO(0方法

更新2: 見的例子http://tutorials.jenkov.com/java-reflection/dynamic-proxies.html您可以輕鬆地包裹的接口你的邏輯來確定範圍,並返回正確的情況下,應在方法

@Override 
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
    return method.invoke(target, args); 
} 
+0

好吧,如果MyTask將所有依賴於範圍的實例存儲在映射中,那麼當調用MyTask方法時,它將如何知道它在哪個範圍內被調用? – artemb

+0

答案已更新。 – StanislavL

+0

謝謝!在這種情況下MyTaskProxy - 這是我開發的東西還是由Spring提供的? – artemb