2016-04-27 7 views
0

コンテキスト:カスタムスコープを持つSpringアプリケーションでBeanをプログラムで「公開」する方法

Springを使用してJMSから送信されるメッセージにtreamentを適用する必要があります。私はプロセス全体の中で最も大きな部分を支配していませんが、それは単一のスレッド(通常はいくつかの情報はThreadLocalsを使用して利用可能です)で行われることを知っています。

私はサービスのチェーンを呼んでいます。私は、これらのサービスのメソッドの署名、または初期化された方法について実装上のみで制御することはできません。

チェーンのエントリポイントから最新のステップに情報を渡す必要があります。私はこのためにThreadLocalを使うことができましたが、SpringのThread Scopeを使ってそれを行う方法があるのだろうかと思っていました。私は何ができるか

:私は(一種の)やりたい何

public class ThreadHolder { 
    private static final ThreadLocal<Object> objectThreadLocal = new ThreadLocal<>(); 
    public static Object getObject() { 
     return objectThreadLocal.get(); 
    } 

    public static void setObject(Object object) { 
     objectThreadLocal.set(object); 
    } 

    public static void cleanObject() { 
     objectThreadLocal.remove(); 
    } 
} 

public class MyController { 
    public MandatoryInsurance process(JMSMessage message) { 
     Object valueToPassDown = retrieveReferenceValueCode(); //Object here, but could be a String if easier 
     ThreadHolder.setObject(valueToPassDown); 
     TreamentResult treamentResult = chainEntryPoint.startTreament(message); //The chainEntryPoint will call chainStep.executeTreamentStep) 

     return treatmentResult; 
    } 
} 

public class ChainStep { 
    public TreamentResult executeTreatmentStep(JMSMessage message) { 
     Object valuePassedDown = ThreadHolder.getObject() 
     // Do treament 
    } 
} 

public class MyController { 

    @Autowired 
    ApplicationContext context; 
    public MandatoryInsurance process(JMSMessage message) { 
     Object valueToPassDown = retrieveReferenceValueCode(); //Object here, but could be a String if easier 
     context.put("valueToPassDown", valueToPassDown, "thread"); 
     TreamentResult treamentResult = chainEntryPoint.startTreament(message); //The chainEntryPoint will call chainStep.executeTreamentStep) 
     ThreadHolder.cleanOject(); 
     return treatmentResult; 
    } 
} 

public class ChainStep { 
    public TreamentResult executeTreatmentStep(JMSMessage message) { 
     Object valuePassedDown = context.getBean("valueToPassDown"); 
     // Do treament 
    } 
} 

答えて

0

私は、このためのSpring Beanを使用してのいずれかの利点があるとは思いません。

1)「Thread」スコープを作成する必要があります。これは、まだThreadLocal実装を使用しています。 2)applicationContextにはput()メソッドはありません。 3)すべてのプロセッサ(連鎖ステップ)はスプリングコンテキストをオートワイヤリングする必要があります。

結論:ThreadLocalを使用するだけですが、処理が完了したらそれをクリーンアップすることを忘れないでください。

public class MyController { 
    public MandatoryInsurance process(JMSMessage message) { 
     Object valueToPassDown = retrieveReferenceValueCode(); //Object here, but could be a String if easier 
     try { 
      ThreadHolder.setObject(valueToPassDown); 
      TreamentResult treamentResult = chainEntryPoint.startTreament(message); //The chainEntryPoint will call chainStep.executeTreamentStep) 
      return treatmentResult; 
     } finally { 
      ThreadHolder.cleanOject(); 
     } 
    } 
} 

ことを言って、ここでは春のSimpleThreadScopeを使用しての作業例です:

package com.test.boot; 

import java.util.HashMap; 
import java.util.Map; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.config.CustomScopeConfigurer; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.boot.builder.SpringApplicationBuilder; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Scope; 
import org.springframework.context.support.SimpleThreadScope; 
import org.springframework.stereotype.Component; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RestController; 

@SpringBootApplication 
public class App { 

    public static void main(String[] args) { 
     new SpringApplicationBuilder(App.class).build().run(args); 
    } 

    @Bean 
    public CustomScopeConfigurer customScope() { 
     CustomScopeConfigurer configurer = new CustomScopeConfigurer(); 
     Map<String, Object> threadScope = new HashMap<String, Object>(); 
     threadScope.put("thread", new SimpleThreadScope()); 
     configurer.setScopes(threadScope); 
     return configurer; 
    } 

    @Component 
    @Scope("thread") 
    public static class MyThreadLocal { 
     String value; 
    } 

    @RestController 
    public static class Controller { 

     @Autowired 
     ApplicationContext appContext; 

     @Autowired 
     ChainStep chainStep; 

     @RequestMapping(value = "/test") 
     public String process() throws InterruptedException { 
      MyThreadLocal bean = appContext.getBean(MyThreadLocal.class); 
      bean.value = "" + Math.random(); 
      System.out.println(Thread.currentThread().getName() + " begin processing, value=" + bean.value); 
      chainStep.executeStep(); 
      Thread.sleep(10000); 
      System.out.println(Thread.currentThread().getName() + " end processing, value=" + bean.value); 
      return "ok"; 
     } 

    } 

    @Component 
    public static class ChainStep { 

     @Autowired 
     ApplicationContext appContext; 

     public void executeStep() throws InterruptedException { 
      MyThreadLocal bean = appContext.getBean(MyThreadLocal.class); 
      System.out.println(Thread.currentThread().getName() + " middle processing, value=" + bean.value); 
     } 

    } 
} 

私は春のブート1.3.3を使用しています。これは、これは10秒以内にhttp://localhost:8080/test URLを複数回ヒットテストし、結果のコンソールを表示するには、私のpom.xmlに

<parent> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-parent</artifactId> 
    <version>1.3.3.RELEASE</version> 
    <relativePath /> <!-- lookup parent from repository --> 
</parent> 

です。各スレッドは独自の値を持ちます。

関連する問題