2016-04-27 25 views
0

上下文:如何在具有自定義作用域的彈簧應用程序中以編程方式「發佈」bean

我需要使用Spring對來自JMS的消息進行處理。我對整個流程的最大部分沒有任何控制權,但是我確實知道它發生在單個線程中(通常一些信息可以使用ThreadLocals)。

對於治療,我稱之爲服務鏈。我無法控制這些服務的方法簽名,或者只是在執行時如何初始化這些服務。

我需要將信息從鏈條的入口點傳遞到它的最新步驟。我可以使用這個ThreadLocal,但我想知道是否有辦法使用Spring的線程範圍來做到這一點。

我可以做什麼:

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)您將不得不創建「​​線程」範圍,該範圍仍將使用下面的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(); 
     } 
    } 
} 

說了這麼多,下面是使用Spring的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); 
     } 

    } 
} 

我使用Spring 1.3.3引導。這是我的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> 

爲了檢驗這一擊10秒內http://localhost:8080/test網址多次,看到控制檯的結果。每個線程都有自己的價值。

相關問題