[SPRING] Spring 빈을 ExecutorService의 ThreadLocal 인스턴스처럼 동작하게 만들기
SPRINGSpring 빈을 ExecutorService의 ThreadLocal 인스턴스처럼 동작하게 만들기
내 웹 응용 프로그램에는 배경 서비스가 있습니다. 이 서비스는 Engine 클래스를 포함하는 Generator 클래스와 여러 스레드를 사용하도록 구성된 ExecutorService를 사용하며 GeneratorTasks를 허용합니다.
@Component
public class Generator {
@Autowired
private Engine heavyEngine;
private ExecutorService exec = Executors.newFixedThreadPool(3);
//I actually pass the singleton instance Generator class into the task.
public void submitTask(TaskModel model, TaskCallback callback) {
this.exec.submit(new GeneratorTask(model, this, callback));
}
}
@Component
public class Engine {
public Engine() {
//time-consuming initialization code here
}
}
public class GeneratorTask implements Callable<String> {
public GeneratorTask(TaskModel m, Generator g, ReceiptCallback c) {
this.m = m;
this.generator = g;
this.c = c;
}
public String call() throws Exception {
//This actually calls the Engine class of the generator.
//Maybe I should have passed the Engine itself?
this.generator.runEngine(c);
}
}
Engine 클래스는 초기화하는 데 오랜 시간이 걸리므로 스레드 당 한 번만 초기화하는 것이 이상적입니다. 인스턴스를 여러 스레드에서 공유 할 수 없으므로이 인스턴스를 싱글 톤 인스턴스로 만들 수 없습니다 (순차 처리에 의존). 처리 작업이 완료된 후에도 인스턴스를 재사용해도 좋습니다.
개인 Engine heavyEngine 변수를 ThreadLocal 변수로 만들려고합니다. 그러나 Spring을 사용하는 ThreadLocal 변수를 삽입하는 또 다른 방법이 있는지 궁금합니다. 범위를 요청하기 위해 빈 범위를 조사했지만, 내 디자인이 주어진다면 어떻게해야하는지 잘 모르겠습니다.
내 디자인을 개선하는 방법에 대한 지침을 주시면 감사하겠습니다.
해결법
-
==============================
1.우선 ThreadLocal을 포기합니다. - 그 클래스에는 무서운 것이 있습니다. 필요한 것은 객체 풀링뿐입니다. 그것은 잘 알려진 특징은 아니지만 Spring은 이것을 지원합니다 :
우선 ThreadLocal을 포기합니다. - 그 클래스에는 무서운 것이 있습니다. 필요한 것은 객체 풀링뿐입니다. 그것은 잘 알려진 특징은 아니지만 Spring은 이것을 지원합니다 :
<bean id="engineProto" class="Engine" scope="prototype" lazy-init="true"/> <bean id="engine" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="targetSource"> <bean class="org.springframework.aop.target.CommonsPoolTargetSource"> <property name="targetClass" value="Engine"/> <property name="targetBeanName" value="engineProto"/> <property name="maxSize" value="3"/> <property name="maxWait" value="5000"/> </bean> </property> </bean>
이제 엔진을 삽입하면 풀에있는 무료 객체에 대한 모든 호출을 위임하는 프록시 객체 (엔진에는 인터페이스가 필요함)가 실제로 수신됩니다. 풀 크기는 구성 가능합니다. 물론 Commons Pool 대신 ThreadLocal을 사용하는 ThreadLocalTargetSource 사용을 방해하는 것은 없습니다. 두 가지 방법 모두 엔진에 대한 스레드 안전 액세스를 독점합니다.
마지막으로 수동으로 풀링을 사용할 수 있지만 (위의 솔루션의 장점은 완전히 투명하다는 것입니다) 또는 정의에 따라 풀링 된 EJB로 전환하십시오.
-
==============================
2.FYI, Spring 3.0 이상에는 스레드 기반 Scope 구현 인 SimpleThreadScope가 포함되어 있습니다.
FYI, Spring 3.0 이상에는 스레드 기반 Scope 구현 인 SimpleThreadScope가 포함되어 있습니다.
그것을 사용하려면 사용자 정의 범위를 등록해야합니다.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="thread"> <bean class="org.springframework.context.support.SimpleThreadScope" /> </entry> </map> </property> </bean>
그리고 나서 쓰레드 스코프 된 빈을 선언한다 :
<bean id="myBean" class="com.foo.MyBean" scope="thread"> ... </bean>
-
==============================
3.Engine에 대한 팩토리를 생성하고 GeneratorTask 내에서 호출해야합니다. 이렇게하면 GeneratorTask에서 Generator 내의 heavyEngine 필드와 Generator 생성자 인수를 제거 할 수 있습니다. 그런 다음 엔진의 초기화 시간을 저장하려는 경우 여전히 싱글 톤으로 선언 할 수 있지만 thread가 아닌 메소드에서는 synchronized 키워드를 사용하십시오.
Engine에 대한 팩토리를 생성하고 GeneratorTask 내에서 호출해야합니다. 이렇게하면 GeneratorTask에서 Generator 내의 heavyEngine 필드와 Generator 생성자 인수를 제거 할 수 있습니다. 그런 다음 엔진의 초기화 시간을 저장하려는 경우 여전히 싱글 톤으로 선언 할 수 있지만 thread가 아닌 메소드에서는 synchronized 키워드를 사용하십시오.
public class Generator { @Autowired private EngineFactory engineFactory; private ExecutorService exec = Executors.newFixedThreadPool(3); public void submitTask(TaskModel model, TaskCallback callback) { this.exec.submit(new GeneratorTask(engineFactory, model, callback)); } } public class EngineFactory { @Autowired private Engine instance; public Engine getInstance() { return instance; } } public class Engine { public Engine() { //time-consuming initialization code here } public synchronized void runEngine() { // Do non thread safe stuf } } public class GeneratorTask implements Callable<String> { public GeneratorTask(EngineFactory f, TaskModel m, ReceiptCallback c) { this.f = f; this.m = m; this.c = c; } public String call() throws Exception { Engine engine = f.getInstance(); engine.runEngine(); ... } }
아마도 Callable에 엔진을 전달하는 순수한 Spring 방법이 있지만,이 경우에는 공장이 제 의견으로는 충분합니다.
from https://stackoverflow.com/questions/12613451/making-spring-beans-behave-like-threadlocal-instances-for-an-executorservice by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Spring MVC LocaleChangeInterceptor 어노테이션이 작동하지 않음 (0) | 2019.04.05 |
---|---|
[SPRING] Spring RestTemplate 클라이언트 - 연결이 거부 된 예외 (0) | 2019.04.05 |
[SPRING] 하나의 web.xml에 다중 저지 서블릿 (0) | 2019.04.05 |
[SPRING] 스프링 데이터 jpa를 사용하여 jsonb 열을 쿼리하려면 어떻게합니까? (0) | 2019.04.05 |
[SPRING] thymeleaf spring framework (maven 사용)의 로컬 디렉토리에서 이미지 삽입 (0) | 2019.04.05 |